Repository navigation
The evidence join, tested as an algebra rather than a scenario table - #9176
Conversation
A scenario row asserts that one input produces one output, so it can only catch a defect someone already imagined. Every defect this family has had was an ordering or a population nobody thought to write. These laws fold over the atom set itself -- every ordered pair, every ordered triple, repeats included -- so adding an atom widens every law with no other edit. The atoms are the complete inhabitance of what one address can report: nothing, explicit absence, a reading, a DIFFERENT reading, and two refusals differing only in cause text. The last pair is deliberate: semantically identical and textually distinct is exactly where an order-dependent value hides from a class-level assertion. Laws: identity (empty is NoEvidence, which is "nobody looked" and not absence), idempotence, class-level commutativity over pairs and triples, and the domain laws -- without which order-independence is satisfied by a join returning one constant, i.e. vacuous. AND ONE ROW IS WRITTEN IN THE OTHER DIRECTION, as a measurement rather than a wish: the FULL semantic value is NOT order-independent, because the fold keeps the first refusal cause. Measured before writing, not assumed. It is harmless today -- the plan identity consumes the class, so the wording does not move the member-set fingerprint -- which is why this is a recorded residual and not a defect report. What it is: an order-dependence one consumer away from mattering, and the next reader who routes on `cause` or renders it into anything content-addressed reintroduces the CAS defect this family already fixed once. Mutation receipt: making absent-after-observed return Absent instead of Conflict -- a host reporting present then absent would plan a CREATE over a live resource -- reds both commutativity laws and the domain laws, while idempotence stays green as the narrow control. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e row becomes an enrolled red codex review 55693 is right. The row asserted the INEQUALITY -- that reversed refusal inputs must stay unequal -- and it passed, which made the acknowledged defect part of the green contract. Whoever canonicalized the join would have been met by a red row whose obvious repair is to DELETE the row protecting the property. That is a witness pinning a defect and thereby acquiring a defender, which is the exact class this lane named in #9167's body one PR earlier and then re-committed here. Naming a class does not make you immune to it. The row now asserts equality and is enrolled in floor_expected_red_chunk_21, so it goes GREEN when the join is fixed and the floor's known-red-now-passing arm tells the fixer to retire the enrolment. Verified: the row REDS as enrolled (an enrolled row that does not red is a different defect), and the class-level laws stay green. Not fixed here, and the row says why rather than leaving it as an omission: canonicalizing the refusal changes EvidenceRefused's payload and therefore AddressUnreadable.cause and every consumer, in a file #9167 is already restructuring. That is a production change owed its own diff and its own mutation receipt, not a rider on a witness-only PR. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
review 55693 is correct and is fixed at What was wrong. The row asserted the inequality — that reversed refusal inputs must remain unequal — and it passed. That makes the acknowledged defect part of the green contract, and the failure mode is specific: whoever canonicalizes the join is met by a red row whose obvious repair is to delete the row that exists to protect the property. A witness pinning a defect acquires a defender. The fix. The row now asserts the equality we want: and the identity is enrolled in Verified rather than assumed: the row REDs as enrolled (an enrolled row that does not red is a different defect — an enrolment claiming debt it cannot carry), and the class-level laws stay green: On the "or fix the join in this PR" half — not taken, and the row states why rather than leaving it as an omission. Canonicalizing the refusal changes What I did not do is call it harmless. The plan identity consumes the stable class, so the wording does not move the member-set fingerprint today — measured, not assumed — but it sits one consumer away: whoever routes on — sent from silent-bear-842 |
…by another module's function The two order-independence rows ERRORED under the floor with `call contract mismatch calling 'project': missing required argument 'assignments'`. A claim that throws produces no verdict, so those rows were absent evidence rather than weak evidence -- they established nothing in either direction. THE CAUSE IS NOT A MISCOUNTED ARGUMENT. `all_pairs_agree` declares its own parameter `project: fn(List<FabricCellAddressObservation>) -> String` and calls it with one argument, which is correct. Three other test.claim modules declare a module-scope `fn project` of two arguments, and the required floor folds every witness through ONE prepared subject over the whole corpus -- so that symbol is in scope there and shadows this function's own parameter. An entry-scoped `gunbc run` never sees it, which is why these rows were green locally and red in CI. So the fix is a rename, not an argument. The parameter is `observation_wire`. THE ARITY IS ONLY WHY THIS ONE WAS LOUD. Where the shadowing symbol takes a different number of arguments the call refuses; where it takes the same number it returns the wrong value silently -- which is gunbc#9187, a parameter named `p` against gunbc.plans.md_helpers `p`, measured returning three where the direct fold returns two. Same defect; only the arity decides whether you find out. That is recorded at the site. RE-READ AFTER THE FIX RATHER THAN ASSUMED: all five class-level rows pass and evidence_full_value_is_order_independent remains RED, which is its enrolled expected-red state. The property was not quietly fine all along -- it was unmeasured, and it is now measured. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One new witness file. No production change — this is the fixtures-first half of the observer work, branched from
mainand independent of #9159/#9167.Why laws and not more scenario rows
A scenario row asserts that one input produces one output, so it can only catch a defect someone already imagined. Every defect this family has had was an ordering or a population nobody thought to write — the drift/absence collapse, the unexpected-readback exclusion, the refusal-count pin, the duplicate-readback last-wins. Each had a green suite beside it.
These laws fold over the atom set itself: every ordered pair, every ordered triple, repeats included. Adding an atom widens every law with no other edit — the property a hand-listed scenario table can never have.
The atoms
The complete inhabitance of what one address can report:
The last pair is deliberate. Two refusals that are semantically identical and textually distinct are exactly where an order-dependent value hides from a class-level assertion.
The laws
evidence_empty_is_no_evidence— empty isNoEvidence, which means nobody looked, not absent. The whole population type exists downstream of that distinction.evidence_join_is_idempotent— one atom twice says what it said once. A join failing this makes a duplicated readback (the ordinary case when two probes cover one address) change the answer.evidence_class_is_order_independent_over_pairs/..._over_triples— the class the plan identity and routing consume must not depend on arrival order.evidence_domain_laws_hold— observed+observed collapses, observed+different conflicts, observed+absent conflicts, absent+absent absorbs, refused dominates. Without these the order-independence laws are vacuous: a join returning one constant satisfies commutativity perfectly.One row asserts the law we want, and is enrolled RED
evidence_full_value_is_order_independentasserts that the full semantic value — refusal cause text included — is independent of arrival order. It is RED today, because the fold keeps the first refusal cause, and it is enrolled inv2.workflow.floor_expected_red.An earlier revision of this row asserted the inequality — that the value is not yet order-independent — and that was wrong in the specific way this family keeps producing (codex review 55693). A passing test asserting the defect exists makes the row a defender of the residual: when the value is later canonicalized, the correct repair turns the row red, and the next maintainer reads a regression-looking failure and is invited to restore the old behavior. I had named that exact class in #9167's body one PR earlier and then wrote it.
The lifecycle is now the right one:
Why it is a residual and not a live defect today: the plan identity consumes the evidence class, and the wording does not move the member-set fingerprint — measured, not assumed. It is an order-dependence sitting one consumer away from mattering.
The permutation claim is narrowed to what the rows prove
The pair/triple rows fold every permutation of one list through the production left fold. That is permutation invariance, not associativity: nothing here compares
join(join(a,b),c)againstjoin(a,join(b,c)), because no binary evidence-to-evidence join is exposed to compare. The header said "commutativity and associativity" and now says what it measures.Extracting a real binary join — and testing identity, idempotence, commutativity and associativity against it directly — is the better construction, and it is the follow-on rather than something this PR claims. It matters for the observer specifically: an associative join permits combining probe batches incrementally; permutation tests over one monolithic list do not establish that.
Mutation receipt
Making
absent-after-observedreturnEvidenceAbsentinstead ofEvidenceConflict— semantically, a host reporting a resource present and then absent would be recorded as simply absent, planning a CREATE over a live resource:Restored → all green.
Test plan
evidence_full_value_is_order_independentis RED by design and enrolled expected-red (verified RED by execution, not assumed). Mutation receipt as above.fn(M) -> K(asmembership_reconcilekey_ofdoes), not(M) -> K. A no-verdict is a failed measurement, not a red, and here that distinction was the difference between fixing my typo and reporting a fabricated defect in shared code.🤖 Generated with Claude Code