Verified at 5df8f8e. Same class as #2 (absence from the consumer contract), on a different axis, and the guard shipped in 96bfd39 does not reach it.
Result
StableErrorCode in crates/synapse-core/src/error_contract.rs declares 23 variants. Enumerating each against docs/wire-contract-v1.md:
20 documented. 3 absent:
| code |
reachable? |
evidence |
owned_cuda_unsupported |
yes |
crates/synapse-core/src/cuda.rs:41, :198, :207 — real capability-gating logic (11 refs) |
op_not_supported_for_remote |
yes |
constructor at error_contract.rs:251; crates/synapse-module/tests/skeleton_e2e.rs:672 asserts the wire string, so it is emitted over the wire today |
sentinel_calibration_refused |
yes |
constructor at error_contract.rs:260; emitted at crates/synapse-module/src/remote/gateway.rs:266 in remote provider calibration |
I checked reachability specifically because a doc gap for a dead variant is not a gap. All three are live.
The doc's Errors section lists a fixed set — queue_full, deadline_exceeded, model_loading, not_certified, substitution_rejected, artifact_invalid, engine_crashed, probe_required, migration_required, module_restarted, grammar_disabled — and tells consumers to branch on class and handle codes by name. A consumer implementing that list exhaustively will meet three codes it has never seen.
(Side note: grammar_disabled appears in the doc but is not a StableErrorCode — zero references in synapse-core. It looks like a separate refusal vocabulary. Worth a line saying which vocabulary a reader is looking at, since the doc presents them together.)
Why this survived #2's fix
wire_contract_documents_every_management_operation (96bfd39) derives names from management_operations() and asserts each appears in the doc. That closes the operation-name axis mechanically, and I mutation-proved it works.
It does not touch error codes. StableErrorCode is not referenced anywhere in that test or its file. So the same document has a second enumerable axis with no guard on it, currently three gaps wide.
Suggested fix
Extend the existing guard rather than adding a parallel one — same shape, same file:
// alongside the operation-name loop
for code in StableErrorCode::ALL { // or strum/iter equivalent
assert!(CONTRACT.contains(&format!("`{}`", code.as_wire_str())), …);
}
That requires a way to enumerate the variants, which the enum does not currently expose. If adding that is unwelcome, a hand-maintained sentinel array like the one already in that test would still be an improvement over nothing — it would at least fail when a documented code is deleted.
Why I went looking
This came out of the claustrum seam work on #3. The generalisable point, which I think is the useful part of this issue:
Testing what a doc says cannot reveal what it fails to say. That needs enumerating the surface against the doc — a different act, and one no consumer has a reason to perform.
A false statement in a contract is self-correcting under use: a consumer runs it, it disagrees with reality, it gets fixed. An omission generates no contradiction at all — AFT and MC integrate against what the doc shows and have no reason to enumerate what it does not. #2's sixteen missing operations survived a public release with two live consumers for exactly that reason.
Which is why the mechanical guard matters more here than usual: enumeration is the only thing that finds this class, and nobody performs it on a schedule. A test does it every run.
Verified at
5df8f8e. Same class as #2 (absence from the consumer contract), on a different axis, and the guard shipped in96bfd39does not reach it.Result
StableErrorCodeincrates/synapse-core/src/error_contract.rsdeclares 23 variants. Enumerating each againstdocs/wire-contract-v1.md:20 documented. 3 absent:
owned_cuda_unsupportedcrates/synapse-core/src/cuda.rs:41,:198,:207— real capability-gating logic (11 refs)op_not_supported_for_remoteerror_contract.rs:251;crates/synapse-module/tests/skeleton_e2e.rs:672asserts the wire string, so it is emitted over the wire todaysentinel_calibration_refusederror_contract.rs:260; emitted atcrates/synapse-module/src/remote/gateway.rs:266in remote provider calibrationI checked reachability specifically because a doc gap for a dead variant is not a gap. All three are live.
The doc's Errors section lists a fixed set —
queue_full, deadline_exceeded, model_loading, not_certified, substitution_rejected, artifact_invalid, engine_crashed, probe_required, migration_required, module_restarted, grammar_disabled— and tells consumers to branch onclassand handle codes by name. A consumer implementing that list exhaustively will meet three codes it has never seen.(Side note:
grammar_disabledappears in the doc but is not aStableErrorCode— zero references insynapse-core. It looks like a separate refusal vocabulary. Worth a line saying which vocabulary a reader is looking at, since the doc presents them together.)Why this survived #2's fix
wire_contract_documents_every_management_operation(96bfd39) derives names frommanagement_operations()and asserts each appears in the doc. That closes the operation-name axis mechanically, and I mutation-proved it works.It does not touch error codes.
StableErrorCodeis not referenced anywhere in that test or its file. So the same document has a second enumerable axis with no guard on it, currently three gaps wide.Suggested fix
Extend the existing guard rather than adding a parallel one — same shape, same file:
That requires a way to enumerate the variants, which the enum does not currently expose. If adding that is unwelcome, a hand-maintained sentinel array like the one already in that test would still be an improvement over nothing — it would at least fail when a documented code is deleted.
Why I went looking
This came out of the claustrum seam work on #3. The generalisable point, which I think is the useful part of this issue:
A false statement in a contract is self-correcting under use: a consumer runs it, it disagrees with reality, it gets fixed. An omission generates no contradiction at all — AFT and MC integrate against what the doc shows and have no reason to enumerate what it does not. #2's sixteen missing operations survived a public release with two live consumers for exactly that reason.
Which is why the mechanical guard matters more here than usual: enumeration is the only thing that finds this class, and nobody performs it on a schedule. A test does it every run.