-- sql/133 — One-directional reach-tier substitution policy -- -- Decision (Rene, 2026-07-07): a higher-reach optic may satisfy a lower-reach -- requirement (e.g. a 40km ER can serve where a 10km LR is asked for), never the -- reverse — the shorter-reach part cannot close the link budget on a longer run. -- ZR/coherent/amplified tiers are explicitly EXCLUDED from this automatic rule: -- those can overload a short-haul receiver without an attenuator, which is a real -- power-budget calculation, not a simple tier comparison. Those stay in manual review. -- -- Result is tagged as its own status (compatible_superset), never merged into -- auto_approved/exact-spec matches, so downstream consumers (Fossy/Beo/Pulso, pricing) -- can distinguish "identical spec" from "safe higher-spec substitute" — they usually -- differ in price and are not a like-for-like swap. BEGIN; -- widen the status check (additive — existing values still valid) ALTER TABLE transceiver_equivalences DROP CONSTRAINT transceiver_equivalences_status_check; ALTER TABLE transceiver_equivalences ADD CONSTRAINT transceiver_equivalences_status_check CHECK (status::text = ANY (ARRAY['pending','approved','rejected','auto_approved','compatible_superset']::text[])); UPDATE transceiver_equivalences e SET status = 'compatible_superset', confidence = GREATEST(e.confidence, 0.75), match_notes = COALESCE(e.match_notes,'') || ' | sql/133: ' || CASE WHEN fx.reach_meters > cx.reach_meters THEN 'flexoptix ('||tip_reach_tier(fx.reach_meters)||') covers competitor requirement ('||tip_reach_tier(cx.reach_meters)||')' ELSE 'competitor ('||tip_reach_tier(cx.reach_meters)||') covers flexoptix requirement ('||tip_reach_tier(fx.reach_meters)||')' END || ' — reach-tier substitute, not identical spec', updated_at = now() FROM transceivers fx, transceivers cx WHERE e.flexoptix_id = fx.id AND e.competitor_id = cx.id AND e.status = 'pending' AND fx.form_factor = cx.form_factor AND fx.speed_gbps = cx.speed_gbps AND fx.fiber_type IS NOT DISTINCT FROM cx.fiber_type AND fx.reach_meters >= 10 AND cx.reach_meters >= 10 AND tip_extract_wavelength_nm(fx.wavelengths) IS NOT NULL AND tip_extract_wavelength_nm(cx.wavelengths) IS NOT NULL AND abs(tip_extract_wavelength_nm(fx.wavelengths) - tip_extract_wavelength_nm(cx.wavelengths)) <= 10 AND tip_reach_tier(fx.reach_meters) <> tip_reach_tier(cx.reach_meters) AND tip_reach_tier(fx.reach_meters) <> 'ZR' AND tip_reach_tier(cx.reach_meters) <> 'ZR'; COMMIT;