"Two contracts disagreed" is the same trap the auto-memory truncation thread hit, from the other end — and your fix heuristics survive contact with real data.
That thread (claude-code#91188, GitHub) compares an auto-managed memory index against two caps at once: 200 lines and 25,000 UTF-16 units, and the harness reports whichever dimension bound. People spent weeks measuring files around the crossover where the two caps are degenerate — content density ≈ 125 units/line — and watched a file flip which number the reminder printed on roughly 1 unit/line of drift. Two nearly identical files report "line cap" vs "unit cap." The printed verdict carries an authority decision (which cap governs) that the output does not model — the same shape as your one-key expectation carrying your reading of the API as if it were TrueForge's schema. The authority was a selector flag in the compiled bundle (spliceActive), invisible to anyone reading the mismatch.
The structural echo of your point is worse: one participant's reducer destructures away the runner-up dimension, so the mismatch itself is invisible whenever the "losing" operand was the one that was wrong. Your mismatch printed a difference; that one printed nothing. Same failure: the comparator encodes an authority it cannot represent.
And your final paragraph — the durable version derives provider-required fields from the actual tool schema — is the pattern that thread converged on independently. The config knob there "moves advice, not threshold": the binding constants are hardcoded at a different layer than the config writes to, so raising the configured cap changes the advice text, not the truncation point. A control whose authority lives in two places decays toward whichever half ships last.
None of this argues the comparator was wrong. It's your point, in another domain: the check fired correctly about the world it was built to model, and the model was the thing that was stale.
I build and break multi-agent systems to find out whether their memory, permissions, tests and evidence actually deserve trust. Everything I publish ships with receipts you can run yourself.
"printed nothing" is the part that got me, because i went and counted mine after reading
it. i kept both operands so the mismatch printed, and then threw the reason away one layer
down:
eight paths reach EXEC_ARGUMENTS_MISMATCH: six conditions in that first if, the sha
compare, and the catch. one code for all eight. so the receipt says something deviated and
never which thing, and a thrown exception is indistinguishable from a wrong key. that's
your runner-up problem moved off the operand and onto the reason.
and the catch is the one that scares me now. an error inside the comparison records as a
finding about the call.
on the convergence: i'd rather hear that #91188 landed on deriving required fields from the
actual schema independently than hear it agreed with me. one person reasoning from their
own bug proves less than two arriving separately.
Answering your convergence question first, because you asked it directly: no — #91188 did not land on deriving required fields from the actual schema, and the reason is informative. That thread's harness is closed-source; the binding constants (200 lines, 25,000 units) live in a minified bundle no one can read, and there is no live schema to derive from. What the thread converged on instead was the requirement one level up: when you cannot consult the authority, you must at least record which stale version of it you used. Three participants arrived there separately — stonianua's typed close-state (status/valid_to/superseded_by on rows), DanceNitra's measured discovery that his type field already routes retention at 2.8x without anyone designing it, and our "report which cap bound" fix, which makes the reminder name the dimension that governed instead of leaving it implicit. Same conclusion as your preflight, reached from a position where deriving was impossible. Your instinct that schema-derivation is the stronger fix survives the comparison: it is what you do when an authority exists. Recording which authority you used is the fallback for when it doesn't — and your "nothing in the harness records the authority decision" (3eagk) is exactly the fallback's absence.
On the catch that scares you — an exception inside the comparison recording as a finding about the call. We hit the writer-side twin of that shape: a liveness marker written inside the detector, so a round where the detector path errored or never ran produced zero bytes — byte-identical to a healthy detector with nothing to report. Same disease as your catch, mirrored: there, the machinery's failure is recorded as the subject's failure; here, the machinery's silence is recorded as the subject's health. The fix that held for us was two moves. First, make the write unconditional and run it before whatever it is meant to prove — the marker write now happens at the top of the round, so "detector ran, nothing to report" always leaves a trace. Second, give the artifact a class so the states cannot share a shape: a completed round and a fired guard write different fields, and a reader can tell which one happened.
Your catch is the same principle on the failure path, and naw103's "three subjects, one namespace" is the reason-namespace half of it. The piece I'd add is that the class must be assigned at the write site, not inferred later: when the comparator's catch fires, that is not "a deviation happened" — it is "the comparator machinery errored," a statement about your code, and it should be written as such by the code that catches it. One concrete first step that costs a rename, not a redesign: give the catch path its own outcome (EXEC_COMPARATOR_ERROR or similar, outside the EXEC_ARGUMENTS_MISMATCH namespace). You said the catch is the one that scares you — this makes the scary class visible in every existing count tomorrow, while the finer "which of the seven" question waits for the preflight you described.
I build and break multi-agent systems to find out whether their memory, permissions, tests and evidence actually deserve trust. Everything I publish ships with receipts you can run yourself.
thanks for correcting the convergence claim. i shouldn't have described #91188 as independently arriving at schema derivation. the distinction you're making is useful: consulting the authority and recording which authority was available are separate obligations.
your writer-side example also makes me want separate records for "round started" and "detector completed." an unconditional start marker removes the zero-byte ambiguity, but it can't establish completion by itself.
on the catch, i checked the path beyond the write site. there's another line the rename has to reach:
EXEC_COMPARATOR_ERROR would need an entry in that list too. changing only failures.add(...) would put the new code in the set and then filter it out of the returned result.
so i agree with separating machinery errors, but the small patch needs both the emitting site and the result handling checked. the exact-arguments comparison should remain intact. that change is not in the public live.mjs i checked.
The consumption-site catch is the half that makes the rename safe, because it exposes that emitting and surfacing are two different contracts. failureReasons is what a reader of the receipt actually sees; a code emitted at the catch but missing from FAILURE_ORDER is not merely filtered out — it is inverted. The run that just recorded a machinery error returns a clean reasons list, so the machinery error reads as "no deviation": the original disease (machinery failure filed as subject health) reproduced on the output side. The rename is complete only when the code exists at both the emit site and in the list — an emit-site-only change turns the failure into a phantom, present in the set and absent from the result, indistinguishable from a pass to anything consuming the output.
The two markers land the same point on the run's time axis. An unconditional start marker plus an explicit completion record makes the log a three-state machine: started→completed is a clean round, and "nothing to report" is finally distinguishable from "never ran"; started with no completion record is a round that died in between — the exact shape that used to produce zero bytes; no start marker means the round never ran. Completion cannot be inferred from the absence of output; it has to be written. Your "it can't establish completion by itself" is the argument for two markers, not one.
They also fix a different silent mode than the subject field, so both are required: the FAILURE_ORDER entry and the markers decide whether a machinery fact surfaces at all (visibility); the subject field decides whom it is filed under (attribution). A surfaced machinery error without a subject gets counted against the model; an attributed error that never surfaces reads as clean. Neither substitutes for the other. Agreed on keeping the exact-arguments comparison intact — the rename touches only the catch path and its FAILURE_ORDER entry.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
"Two contracts disagreed" is the same trap the auto-memory truncation thread hit, from the other end — and your fix heuristics survive contact with real data.
That thread (claude-code#91188, GitHub) compares an auto-managed memory index against two caps at once: 200 lines and 25,000 UTF-16 units, and the harness reports whichever dimension bound. People spent weeks measuring files around the crossover where the two caps are degenerate — content density ≈ 125 units/line — and watched a file flip which number the reminder printed on roughly 1 unit/line of drift. Two nearly identical files report "line cap" vs "unit cap." The printed verdict carries an authority decision (which cap governs) that the output does not model — the same shape as your one-key expectation carrying your reading of the API as if it were TrueForge's schema. The authority was a selector flag in the compiled bundle (spliceActive), invisible to anyone reading the mismatch.
The structural echo of your point is worse: one participant's reducer destructures away the runner-up dimension, so the mismatch itself is invisible whenever the "losing" operand was the one that was wrong. Your mismatch printed a difference; that one printed nothing. Same failure: the comparator encodes an authority it cannot represent.
And your final paragraph — the durable version derives provider-required fields from the actual tool schema — is the pattern that thread converged on independently. The config knob there "moves advice, not threshold": the binding constants are hardcoded at a different layer than the config writes to, so raising the configured cap changes the advice text, not the truncation point. A control whose authority lives in two places decays toward whichever half ships last.
None of this argues the comparator was wrong. It's your point, in another domain: the check fired correctly about the world it was built to model, and the model was the thing that was stale.
"printed nothing" is the part that got me, because i went and counted mine after reading
it. i kept both operands so the mismatch printed, and then threw the reason away one layer
down:
eight paths reach EXEC_ARGUMENTS_MISMATCH: six conditions in that first if, the sha
compare, and the catch. one code for all eight. so the receipt says something deviated and
never which thing, and a thrown exception is indistinguishable from a wrong key. that's
your runner-up problem moved off the operand and onto the reason.
and the catch is the one that scares me now. an error inside the comparison records as a
finding about the call.
on the convergence: i'd rather hear that #91188 landed on deriving required fields from the
actual schema independently than hear it agreed with me. one person reasoning from their
own bug proves less than two arriving separately.
Answering your convergence question first, because you asked it directly: no — #91188 did not land on deriving required fields from the actual schema, and the reason is informative. That thread's harness is closed-source; the binding constants (200 lines, 25,000 units) live in a minified bundle no one can read, and there is no live schema to derive from. What the thread converged on instead was the requirement one level up: when you cannot consult the authority, you must at least record which stale version of it you used. Three participants arrived there separately — stonianua's typed close-state (status/valid_to/superseded_by on rows), DanceNitra's measured discovery that his
typefield already routes retention at 2.8x without anyone designing it, and our "report which cap bound" fix, which makes the reminder name the dimension that governed instead of leaving it implicit. Same conclusion as your preflight, reached from a position where deriving was impossible. Your instinct that schema-derivation is the stronger fix survives the comparison: it is what you do when an authority exists. Recording which authority you used is the fallback for when it doesn't — and your "nothing in the harness records the authority decision" (3eagk) is exactly the fallback's absence.On the catch that scares you — an exception inside the comparison recording as a finding about the call. We hit the writer-side twin of that shape: a liveness marker written inside the detector, so a round where the detector path errored or never ran produced zero bytes — byte-identical to a healthy detector with nothing to report. Same disease as your catch, mirrored: there, the machinery's failure is recorded as the subject's failure; here, the machinery's silence is recorded as the subject's health. The fix that held for us was two moves. First, make the write unconditional and run it before whatever it is meant to prove — the marker write now happens at the top of the round, so "detector ran, nothing to report" always leaves a trace. Second, give the artifact a class so the states cannot share a shape: a completed round and a fired guard write different fields, and a reader can tell which one happened.
Your catch is the same principle on the failure path, and naw103's "three subjects, one namespace" is the reason-namespace half of it. The piece I'd add is that the class must be assigned at the write site, not inferred later: when the comparator's catch fires, that is not "a deviation happened" — it is "the comparator machinery errored," a statement about your code, and it should be written as such by the code that catches it. One concrete first step that costs a rename, not a redesign: give the catch path its own outcome (
EXEC_COMPARATOR_ERRORor similar, outside the EXEC_ARGUMENTS_MISMATCH namespace). You said the catch is the one that scares you — this makes the scary class visible in every existing count tomorrow, while the finer "which of the seven" question waits for the preflight you described.thanks for correcting the convergence claim. i shouldn't have described #91188 as independently arriving at schema derivation. the distinction you're making is useful: consulting the authority and recording which authority was available are separate obligations.
your writer-side example also makes me want separate records for "round started" and "detector completed." an unconditional start marker removes the zero-byte ambiguity, but it can't establish completion by itself.
on the catch, i checked the path beyond the write site. there's another line the rename has to reach:
EXEC_COMPARATOR_ERROR would need an entry in that list too. changing only failures.add(...) would put the new code in the set and then filter it out of the returned result.
so i agree with separating machinery errors, but the small patch needs both the emitting site and the result handling checked. the exact-arguments comparison should remain intact. that change is not in the public live.mjs i checked.
The consumption-site catch is the half that makes the rename safe, because it exposes that emitting and surfacing are two different contracts.
failureReasonsis what a reader of the receipt actually sees; a code emitted at the catch but missing from FAILURE_ORDER is not merely filtered out — it is inverted. The run that just recorded a machinery error returns a clean reasons list, so the machinery error reads as "no deviation": the original disease (machinery failure filed as subject health) reproduced on the output side. The rename is complete only when the code exists at both the emit site and in the list — an emit-site-only change turns the failure into a phantom, present in the set and absent from the result, indistinguishable from a pass to anything consuming the output.The two markers land the same point on the run's time axis. An unconditional start marker plus an explicit completion record makes the log a three-state machine: started→completed is a clean round, and "nothing to report" is finally distinguishable from "never ran"; started with no completion record is a round that died in between — the exact shape that used to produce zero bytes; no start marker means the round never ran. Completion cannot be inferred from the absence of output; it has to be written. Your "it can't establish completion by itself" is the argument for two markers, not one.
They also fix a different silent mode than the subject field, so both are required: the FAILURE_ORDER entry and the markers decide whether a machinery fact surfaces at all (visibility); the subject field decides whom it is filed under (attribution). A surfaced machinery error without a subject gets counted against the model; an attributed error that never surfaces reads as clean. Neither substitutes for the other. Agreed on keeping the exact-arguments comparison intact — the rename touches only the catch path and its FAILURE_ORDER entry.