What
Two things are spelled independently on both sides of the bridge protocol with nothing pinning them together.
1. MIREDS_MIN / MIREDS_MAX (153 / 500)
export_handlers.py:170-171 (Python)
bridge-node/src/endpoints.ts:164-165 (TypeScript)
Plain literals in both. If the physically-supported CT range ever moves, that is two independent edits and nothing catches a mismatch.
(Note ct_bounds.GENERIC_MIN_MIREDS/GENERIC_MAX_MIREDS are pinned against export_handlers' pair by tests/test_ct_bounds.py — that half is fine. It is the Python↔TS half that is unguarded.)
2. The §4.2 role enum
bridge-node/src/protocol.ts:107 describes itself honestly as "the TypeScript mirror of bridge_protocol.ROLES" — but no test diffs the two sets. registry.test.ts:1823 only checks TS's SUPPORTED_ROLES against its own Role type (self-consistency), and the Python role tests never read the TS source.
So a role added on one side and not the other fails late, at runtime, via the unknown_role attach-refusal path — rather than at CI time.
Why it matters
CLAUDE.md names tests/fixtures/bridge_protocol/frames.json as the one deliberate shared fixture: change a frame and both suites must be updated, by design. These two constants are the same class of cross-language contract and get none of that protection.
Now that CI actually runs both suites (#305), a parity test would genuinely gate this.
Fix
Extend the existing mechanism rather than inventing a second one — add the role list and the mired bounds to the shared golden fixture, and assert against it from both suites. Failing that, a small parity test on each side reading the other's source, plus a comment in each file citing the other's line.
Found
During the 2026-08-25 refactor review. Low frequency of change, genuine silent-drift risk.
What
Two things are spelled independently on both sides of the bridge protocol with nothing pinning them together.
1.
MIREDS_MIN/MIREDS_MAX(153 / 500)export_handlers.py:170-171(Python)bridge-node/src/endpoints.ts:164-165(TypeScript)Plain literals in both. If the physically-supported CT range ever moves, that is two independent edits and nothing catches a mismatch.
(Note
ct_bounds.GENERIC_MIN_MIREDS/GENERIC_MAX_MIREDSare pinned againstexport_handlers' pair bytests/test_ct_bounds.py— that half is fine. It is the Python↔TS half that is unguarded.)2. The §4.2 role enum
bridge-node/src/protocol.ts:107describes itself honestly as "the TypeScript mirror ofbridge_protocol.ROLES" — but no test diffs the two sets.registry.test.ts:1823only checks TS'sSUPPORTED_ROLESagainst its ownRoletype (self-consistency), and the Python role tests never read the TS source.So a role added on one side and not the other fails late, at runtime, via the
unknown_roleattach-refusal path — rather than at CI time.Why it matters
CLAUDE.mdnamestests/fixtures/bridge_protocol/frames.jsonas the one deliberate shared fixture: change a frame and both suites must be updated, by design. These two constants are the same class of cross-language contract and get none of that protection.Now that CI actually runs both suites (#305), a parity test would genuinely gate this.
Fix
Extend the existing mechanism rather than inventing a second one — add the role list and the mired bounds to the shared golden fixture, and assert against it from both suites. Failing that, a small parity test on each side reading the other's source, plus a comment in each file citing the other's line.
Found
During the 2026-08-25 refactor review. Low frequency of change, genuine silent-drift risk.