Contract silence: name the two ways an I/O contract reads as satisfied when it is not - #413
Merged
Merged
Conversation
A technique can declare an input no phase spends, and a Protocol Apply can omit an input the applied operation declares. Both leave a contract that reads as satisfied and is not, and neither had a Detect anywhere in the canon: output-without-destination covers the output side, bind-protocol-locals covers dead locals, and binding-fidelity proves argument conformance for activity step binds rather than for Protocol Apply sites. declared-input-never-read and apply-omits-declared-input name the two, each carrying the carve-outs that keep them from firing on container-merged inputs, pass-through substitution maps, and same-name ambient binds. no-rationale-in-description gains technique Rules and rules.* on its Detect surface, so rationale inside a rule has a home — including a constraint justified by naming another actor's remit, which couples the rule to a contract it does not own. The carve-out preserves what no-rule-protocol-restatement already protects: a prohibition citing the home it forbids bypassing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Summary
A technique can declare an input and never spend it. A Protocol step can apply another operation and pass only some of what that operation declares. In both cases the contract reads as satisfied — every slot is declared, every call is made — and a reader has no way to tell that a value is going nowhere or arriving from nowhere. Neither shape had a Detect anywhere in the canon. This adds one entry for each, and extends an existing entry so that rationale sitting inside a rule has a home.
How the gap was found
A small change to the meta engine — five files, one new operation — was audited three times against the canon. The first pass found ten defects, the second five, the third three. The third pass's three had all been present since the first commit, and the first pass had walked those files whole and missed them.
The reason was not reading depth. Two of the three were the same shape: a new operation declared
session_indexandactivity_idand referenced neither, and the operation it applied declaredsession_indexas an input the Apply site never passed — so the resumed worker's prompt would have carried no session index to authenticate with. Nothing could have caught either. The walk follows the catalogue entry by entry, and the catalogue has no entry for it.What already exists, and what it does not reach
output-without-destinationcovers the output side of exactly this concern: a declared output with no reader. There is no input twin.bind-protocol-localscovers a dead{$local}, not a dead declared input. And the mechanical net stops short too —binding-fidelityproves that step bindings resolve and their arguments conform, but its subject is activitysteps[]binds; a ProtocolApplyis not a bind site, so every such call is unchecked.Separately,
no-rationale-in-descriptionlists the surfaces its Detect reaches —description,message, option and action descriptions, procedure bullets — and technique## Rulesis not among them. So a rule that justifies its own prohibition has no home either, which is how a rule reading "orchestrators never call this tool; the definition is the worker's domain" survives an audit: the second clause is rationale, and it couples the rule to a contract it does not own.The additions
declared-input-never-read— an input declared on a technique that its own Protocol and Rules never reference. Detect searches for the braced designator, the dotted field form, and the bare name inside a tool-call signature a phase passes, because that last form is how several engine operations legitimately reference an argument. Carve-outs keep it off container inputs the descendants reference after the merge, and off an input handed wholesale to an applied operation as a substitution map.apply-omits-declared-input— a Protocol Apply that omits a required input of the operation it applies. Detect resolves the target's Inputs through the loader, including container merges, and flags a required slot the Apply site neither passes nor covers by a declared default, and that no same-name slot on the applying technique makes ambient. Carve-outs keep it off optional inputs, defaulted inputs, same-name ambient binds, and activity step binds, whose conformance is a bind-site concern.no-rationale-in-descriptiongains two surfaces — technique## Rulesandrules.*strings, with a test for the rule case: delete the clause, and if the constraint still says what is constrained, the clause was rationale. The Do-not-flag preserves whatno-rule-protocol-restatementalready protects, so a prohibition that cites the home it forbids bypassing keeps its pointer.Scope of change
One file:
workflow-design/resources/anti-patterns.md. Two appended entries and one amended Detect triad. No other workflow, technique, or activity is touched.Acceptance criteria
resource-anchorsandsource-encoding.Non-goals
binding-fidelity, but run corpus-wide they will report well beyond any one change, so they want per-finding triage rather than a zero gate from day one. That is a separate change against the server.Investigation detail
The audit that surfaced the gap, and the change it was auditing: #410 and #411.
🤖 Generated with Claude Code