docs: stop the remote-error table claiming to be the enumeration - #385
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
error_handling.md's "Remote wire errors" table listed 8 refusals and read as the complete set, and its `unknown envelope kind` row told a client implementer the refusal fires for anything that is not register/deregister/execute. Both are wrong, and the second is wrong in the way that matters: dispatchMessage compares env.kind against eight values, and attach, assign, instances, schemas and hello all reach real branches that never produce that message. The real numbers, re-derived rather than taken from the issue's "~16" estimate. scenario_coverage.py's own extractor -- remote.hpp's server half above `class SimulatedRemoteBackend`, plus the body of wire::decode -- reports 8 envelope kinds and 17 refusals, 14 fixed messages and 3 with a runtime suffix: assign attach deregister execute hello instances register schemas assign requires a typeId / attach requires a typeId / connection closed / handleInline does not support execute (reply is asynchronous) / instances requires a typeId / model not found / protocol version unsupported / register requires a typeId / schemas requires a typeId / server busy / server shutting down / timeout / too many models / unauthorized, and the prefixes envelope decode failed: / payload missing required field(s): / unknown envelope kind: Each site was then read in remote.hpp to fill the Raised in and Cause columns, which is where the eight `unauthorized` sites and the three each for `too many models` and `connection closed` come from -- the old row named three of the eight. The judgement the issue handed over: yes, several of these are operational rather than protocol-level, and mixing them cost a reader the one thing the message text never tells them, which is whether retrying can help. The section is now three tables -- the request is malformed, the request is refused on the merits, the server's own condition produced it -- with a fourth heading for the one message no transport can reach (handleInline's, which is an in-process C++ API). The third table gains a "reachable when" column, because three of its five rows need a LimitPolicy field no default and only one ladder rung ever sets. The head states the count and where it comes from, so the claim of completeness is checkable rather than asserted: 17 extracted, 16 in the tables, the 17th called out separately, plus two rows sourced from outside those headers (registry.hpp's `unknown model type:` and the exc.what() passthrough). Verified: scripts/check_spec_citations.sh exits 0 (711 references, 59 cited sections, wire.md tables complete), and the extraction above is scenario_coverage.py's own, which exits 0 with kinds 8/8 and refusals 11/17 covered plus 6 written exemptions. Not verified: I did not add a check that ties this table to the extractor. Nothing mechanically stops it drifting again -- what does exist is test_real_headers_carry_exactly_these_refusals failing when a refusal is added, which forces a human to that decision without pointing them here. Closes #358. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GnSnsebJ92Kti1D7m3RwYJ
Yaraslaut
force-pushed
the
fix/358-remote-error-table
branch
from
September 1, 2026 15:43
b9652c8 to
4727101
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #358.
docs/spec/error_handling.md's "Remote error envelopes" section listed 8 refusals and describedunknown envelope kindas covering anything that is notregister/deregister/execute. Both were wrong in the way that matters: the table presented itself as the enumeration while being a subset, and the one row whose job is to say when it fires named three kinds where the code has eight.Re-derived, not copied
The issue's own figures were treated as a starting point, not as input.
scripts/scenario/scenario_coverage.pyalready extracts both universes mechanically fromremote.hpp's server half andwire::decode, and its self-test pins them. Running that extractor reports:assign attach deregister execute hello instances register schemasenvelope decode failed:,payload missing required field(s):,unknown envelope kind:)The issue estimated "~16", which was low. Every site was then read in
remote.hppto confirm, which is where the multiplicity comes from: 8unauthorizedsites where the old table implied 3, and 3 sites each fortoo many modelsandconnection closed.The judgement the issue handed over
It asked whether some refusals were "operational rather than protocol-level", and whether an intentional omission deserved a sentence. The answer is that several are operational, and the fix is not one longer table — a client author reading a flat list of 17 cannot tell which ones they should code against.
The section is now organised by what a client should do about it:
LimitPolicyfield that no default sets and only one ladder rung configures;handleInline's message, under its own heading, because no transport can reach it.The head states the arithmetic, so a reader can check completeness rather than trust it, and the
unknown envelope kinddescription now matches the code.Verification
scripts/check_spec_citations.shexits 0 after the edit.CHANGELOG.mdentry under### Fixed.Not verified: no mechanical check ties this table to the extractor, so drift is still only caught indirectly — by
scenario_coverage.py's pin test failing when a refusal is added toremote.hpp, which forces a human to decide where it belongs but does not point at this file. Wiring the table itself to the extractor would be its own change.Note for review order: #377 (
fix/351-execute-ticket-guard) is open againstremote.hppand changes no refusal literal, so this table is stable against it either way it merges.🤖 Generated with Claude Code
https://claude.ai/code/session_01GnSnsebJ92Kti1D7m3RwYJ