126 only guards writes to compatibility; a later transceivers.speed_gbps update (e.g. daily enrich-modulation-fec.sh self-heal) never re-validated existing compatible spec_match rows. Found live 2026-07-12: 189 rows had drifted physically-impossible again. One-time remediation (189 rows -> incompatible, backed up to compat_speed_drift_backup_20260712) + AFTER UPDATE OF speed_gbps trigger on transceivers closes the gap for good. check_switch_quality() passes.
84 lines
4.3 KiB
PL/PgSQL
84 lines
4.3 KiB
PL/PgSQL
-- sql/138-transceiver-speed-drift-guard.sql
|
|
-- Closes a gap in the sql/125+126 "no physically-impossible compatibility rows"
|
|
-- invariant: compat_speed_guard() (126) only fires on INSERT/UPDATE of the
|
|
-- `compatibility` table itself. It never re-validates existing 'compatible'
|
|
-- spec_match rows when a TRANSCEIVER's speed_gbps changes later (e.g. the daily
|
|
-- enrich-modulation-fec.sh self-heal, sql/135, recovering speed from part-number
|
|
-- tokens for previously NULL/junk rows). Found live 2026-07-12: 189 compat rows
|
|
-- had gone physically-impossible because their transceiver's speed_gbps was
|
|
-- updated (all sampled rows dated today, i.e. by the 03:30 cron) after the
|
|
-- compat row was already written as 'compatible'.
|
|
--
|
|
-- Fix mirrors 126 exactly, just triggered from the other table: AFTER UPDATE OF
|
|
-- speed_gbps on transceivers, re-validate every 'compatible' spec_match
|
|
-- compatibility row referencing that transceiver against the same evidence-based
|
|
-- ceiling (v_switch_effective_max) used by v_compat_speed_errors. Curated rows
|
|
-- (vendor_matrix/vendor_compat/tested/datasheet) are never touched. Idempotent,
|
|
-- safe to re-run.
|
|
|
|
-- Backup of affected rows before remediation (audit trail, matches
|
|
-- tip_speed_gbps_rollback precedent from sql/136).
|
|
create table if not exists compat_speed_drift_backup_20260712 as
|
|
with em as materialized (
|
|
select switch_id, effective_max_gbps from v_switch_effective_max)
|
|
select c.*, e.effective_max_gbps, t.speed_gbps as tx_speed_gbps, now() as backed_up_at
|
|
from compatibility c
|
|
join em e on e.switch_id = c.switch_id
|
|
join transceivers t on t.id = c.transceiver_id
|
|
where c.status = 'compatible'
|
|
and c.verification_method = 'spec_match'
|
|
and e.effective_max_gbps > 0
|
|
and t.speed_gbps is not null
|
|
and t.speed_gbps > e.effective_max_gbps;
|
|
|
|
-- One-time remediation: flip the rows found live today (same logic as 125's
|
|
-- Remediation B, using the full evidence-based ceiling incl. curated bump).
|
|
with em as materialized (
|
|
select switch_id, effective_max_gbps from v_switch_effective_max)
|
|
update compatibility c
|
|
set status = 'incompatible',
|
|
notes = case when c.notes is null or c.notes = ''
|
|
then 'auto(138): transceiver speed exceeds switch max port speed (post-hoc drift)'
|
|
else c.notes || ' | auto(138): transceiver speed exceeds switch max port speed (post-hoc drift)' end
|
|
from em e, transceivers t
|
|
where e.switch_id = c.switch_id
|
|
and t.id = c.transceiver_id
|
|
and c.status = 'compatible'
|
|
and c.verification_method = 'spec_match'
|
|
and e.effective_max_gbps > 0
|
|
and t.speed_gbps is not null
|
|
and t.speed_gbps > e.effective_max_gbps;
|
|
|
|
-- Durable fix: re-validate on transceiver speed change.
|
|
create or replace function compat_speed_guard_on_transceiver_change() returns trigger
|
|
language plpgsql as $$
|
|
begin
|
|
if NEW.speed_gbps is distinct from OLD.speed_gbps and NEW.speed_gbps is not null then
|
|
update compatibility c
|
|
set status = 'incompatible',
|
|
notes = case when c.notes is null or c.notes = ''
|
|
then 'auto(138): transceiver speed exceeds switch max port speed (post-hoc drift)'
|
|
else c.notes || ' | auto(138): transceiver speed exceeds switch max port speed (post-hoc drift)' end
|
|
from v_switch_effective_max e
|
|
where e.switch_id = c.switch_id
|
|
and c.transceiver_id = NEW.id
|
|
and c.status = 'compatible'
|
|
and c.verification_method = 'spec_match'
|
|
and e.effective_max_gbps > 0
|
|
and NEW.speed_gbps > e.effective_max_gbps;
|
|
end if;
|
|
return NEW;
|
|
end $$;
|
|
|
|
comment on function compat_speed_guard_on_transceiver_change() is
|
|
'AFTER UPDATE OF speed_gbps on transceivers: re-validates existing compatible spec_match rows for this transceiver against the evidence-based switch ceiling, closing the drift gap left by compat_speed_guard() (126), which only fires on compatibility writes. Never touches curated rows.';
|
|
|
|
drop trigger if exists trg_compat_speed_guard_on_transceiver_change on transceivers;
|
|
create trigger trg_compat_speed_guard_on_transceiver_change
|
|
after update of speed_gbps on transceivers
|
|
for each row execute function compat_speed_guard_on_transceiver_change();
|
|
|
|
insert into _migrations (filename, applied_at)
|
|
select '138-transceiver-speed-drift-guard.sql', now()
|
|
where not exists (select 1 from _migrations where filename = '138-transceiver-speed-drift-guard.sql');
|