Skip to content

The behavioral receipt reported DIVERGENT over a byte-identical file: measure instability instead of rendering it as a difference - #8743

Merged
gunbai-bot[bot] merged 3 commits into
mainfrom
session/snappy-ferret-99-receipt
Aug 21, 2026
Merged

gunbai-bot[bot] merged 3 commits into
mainfrom
session/snappy-ferret-99-receipt

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The behavioral receipt reported DIVERGENT over a byte-identical file: measure instability instead of rendering it as a difference

generate_receipt_driver renders every derived call as println!("... = {:?}", call), and a
mirror function returning Rc<HashMap<..>> renders in per-process randomized order. The seed and
candidate transcripts come from two separate driver processes, so a map-returning call is a coin
flip that the differential scores as a behavioural difference.

THE DISCRIMINATING OBSERVATION: on gunbc#8726's CI run, required-regen reported
first_generation_equal=true -- the emitted std_algebra.rs byte-identical to the committed
mirror -- and the receipt then installed that candidate over the mirror and reported DIVERGENT.
It compared a file against itself and could not answer EQUIVALENT. The printed first_difference
was kernel_algebra_profile_value() with the same seven entries in a different order.

MEASURED, not inferred: a one-line driver built against the committed libv1_compiler.rlib
printing that call through {:?}, run 20 times on an unchanged tree, produced 20 DISTINCT
transcripts. Two agreeing runs is the rare event, not the divergence.

This does not fail open. It fails WRONG, and nondeterministically -- the fabricated-difference
mirror of the fabricated-pass that behavioral_differential's own dirty-tree refusal (review
54094) was hardened against.

WHY THE CHECK IS A SECOND RUN AND NOT A TYPE CHECK. The obvious fix is to refuse map-returning
functions at admission, at the function grain main moved to. It is the wrong instrument: order-
dependent rendering is a property of the value's TRANSITIVE shape, so a record CONTAINING a map
renders unstably while its own return type says Record, and HashSet has the property too. Any
check keying on the outermost constructor under-refuses BY CONSTRUCTION, and it under-refuses
silently -- the missed call lands in Divergent, indistinguishable from a real divergence. An
admission check also runs before anything has been rendered, so a proxy is all it could ever key on.

run_receipt_driver already builds the crate and compiles a driver binary. Running THAT SAME
BINARY a second time costs milliseconds -- no rebuild -- and two executions of one unchanged binary
that disagree PROVE the disagreeing call renders nondeterministically. The property itself, with
no type walk to keep in sync, catching HashSet and containing-record cases for free.

PLACEMENT: a verdict, not a ReceiptExclusion. The property is only knowable by RUNNING, and
selection happens before any run. That respects the boundary main's function-grain admission
draws rather than ignoring it.

WHAT LANDS

  • DriverTranscript { lines, unstable }; run_receipt_driver runs the built binary twice.
  • The differential unions BOTH sides' unstable sets (each side is its own binary, measured
    independently) and compares only the lines proved stable.
  • Equivalent carries nondeterministic_calls + the FUNCTION NAMES, because a green with an
    excluded population is a different claim from a green over everything, and a name can be
    acted on where a count cannot.
  • NondeterministicRendering when every derived call is unstable: nothing was compared, so it
    is neither equivalence nor divergence, and the fix lives in emission rather than in this gate
    or in the diff under test.
  • A counter printed EVERY run including zero, carrying its own FLOOR warning and its own
    dissolution trigger.

THE COUNT IS A FLOOR AND THE LINE SAYS SO. Instability is proved by two runs disagreeing, so a
call whose randomized rendering happened to agree twice is not counted and is compared as if it
were deterministic. The warning is in the printed line rather than in a comment because the line
outlives the comment: someone will trend this number and read a small one as a nearly-closed
class. The residue SHRINKS with more executions, unlike a structural blind spot -- but one extra
run is what the evidence to date justifies, and speculatively adding more would be a threshold
nobody measured.

DISSOLUTION: the counter goes to zero when emission is deterministic (a BTreeMap container
template rather than HashMap), NOT when the probe gets better at spotting the residue. That
higher rung makes the nondeterminism unwritable rather than detected-and-excluded; this change is
the declared, counted, bounded reduction until then. Its blast radius --
rust_container_templates plus every v1_rt map signature -- is why it is not in this diff.

EVIDENCE BY EXECUTION

  • --behavioral-receipt-selftest green: arm preserving EQUIVALENT over 12 derived calls,
    arm changing DIVERGENT over 12 at the authored difference (band_of(100i64) = High vs
    Mid). Both pre-existing controls still discriminate with the probe in place.
  • The preserving arm is now ALSO a false-positive control: its fixture is deterministic, so
    the probe must mark nothing unstable, and the arm fails loudly if it does. A probe that
    marked everything would otherwise still print a green there while the gate had quietly
    stopped comparing.
  • Four unit tests over DriverTranscript::of, including one that PINS the residue: a
    nondeterministic call that agreed twice is not caught. If someone makes the probe complete,
    that test fails and forces the FLOOR wording to be revisited rather than left stale.
  • MUTATION CONTROLS, both directions: flipping the length-difference branch to false reds
    exactly a_length_difference_marks_every_line; flipping the line comparison from a != b to
    a == b reds the other three. The tests are not vacuous.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

gunbc-ci-auto-heal and others added 2 commits August 21, 2026 06:32
… measure instability instead of rendering it as a difference

`generate_receipt_driver` renders every derived call as `println!("... = {:?}", call)`, and a
mirror function returning `Rc<HashMap<..>>` renders in per-process randomized order. The seed and
candidate transcripts come from two separate driver processes, so a map-returning call is a coin
flip that the differential scores as a behavioural difference.

THE DISCRIMINATING OBSERVATION: on gunbc#8726's CI run, `required-regen` reported
`first_generation_equal=true` -- the emitted `std_algebra.rs` byte-identical to the committed
mirror -- and the receipt then installed that candidate over the mirror and reported DIVERGENT.
It compared a file against itself and could not answer EQUIVALENT. The printed `first_difference`
was `kernel_algebra_profile_value()` with the same seven entries in a different order.

MEASURED, not inferred: a one-line driver built against the committed `libv1_compiler.rlib`
printing that call through `{:?}`, run 20 times on an unchanged tree, produced 20 DISTINCT
transcripts. Two agreeing runs is the rare event, not the divergence.

This does not fail open. It fails WRONG, and nondeterministically -- the fabricated-difference
mirror of the fabricated-pass that `behavioral_differential`'s own dirty-tree refusal (review
54094) was hardened against.

WHY THE CHECK IS A SECOND RUN AND NOT A TYPE CHECK. The obvious fix is to refuse map-returning
functions at admission, at the function grain main moved to. It is the wrong instrument: order-
dependent rendering is a property of the value's TRANSITIVE shape, so a record CONTAINING a map
renders unstably while its own return type says `Record`, and `HashSet` has the property too. Any
check keying on the outermost constructor under-refuses BY CONSTRUCTION, and it under-refuses
silently -- the missed call lands in `Divergent`, indistinguishable from a real divergence. An
admission check also runs before anything has been rendered, so a proxy is all it could ever key on.

`run_receipt_driver` already builds the crate and compiles a driver binary. Running THAT SAME
BINARY a second time costs milliseconds -- no rebuild -- and two executions of one unchanged binary
that disagree PROVE the disagreeing call renders nondeterministically. The property itself, with
no type walk to keep in sync, catching `HashSet` and containing-record cases for free.

PLACEMENT: a verdict, not a `ReceiptExclusion`. The property is only knowable by RUNNING, and
selection happens before any run. That respects the boundary main's function-grain admission
draws rather than ignoring it.

WHAT LANDS
  - `DriverTranscript { lines, unstable }`; `run_receipt_driver` runs the built binary twice.
  - The differential unions BOTH sides' unstable sets (each side is its own binary, measured
    independently) and compares only the lines proved stable.
  - `Equivalent` carries `nondeterministic_calls` + the FUNCTION NAMES, because a green with an
    excluded population is a different claim from a green over everything, and a name can be
    acted on where a count cannot.
  - `NondeterministicRendering` when every derived call is unstable: nothing was compared, so it
    is neither equivalence nor divergence, and the fix lives in emission rather than in this gate
    or in the diff under test.
  - A counter printed EVERY run including zero, carrying its own FLOOR warning and its own
    dissolution trigger.

THE COUNT IS A FLOOR AND THE LINE SAYS SO. Instability is proved by two runs disagreeing, so a
call whose randomized rendering happened to agree twice is not counted and is compared as if it
were deterministic. The warning is in the printed line rather than in a comment because the line
outlives the comment: someone will trend this number and read a small one as a nearly-closed
class. The residue SHRINKS with more executions, unlike a structural blind spot -- but one extra
run is what the evidence to date justifies, and speculatively adding more would be a threshold
nobody measured.

DISSOLUTION: the counter goes to zero when emission is deterministic (a `BTreeMap` container
template rather than `HashMap`), NOT when the probe gets better at spotting the residue. That
higher rung makes the nondeterminism unwritable rather than detected-and-excluded; this change is
the declared, counted, bounded reduction until then. Its blast radius --
`rust_container_templates` plus every `v1_rt` map signature -- is why it is not in this diff.

EVIDENCE BY EXECUTION
  - `--behavioral-receipt-selftest` green: arm `preserving` EQUIVALENT over 12 derived calls,
    arm `changing` DIVERGENT over 12 at the authored difference (`band_of(100i64) = High` vs
    `Mid`). Both pre-existing controls still discriminate with the probe in place.
  - The `preserving` arm is now ALSO a false-positive control: its fixture is deterministic, so
    the probe must mark nothing unstable, and the arm fails loudly if it does. A probe that
    marked everything would otherwise still print a green there while the gate had quietly
    stopped comparing.
  - Four unit tests over `DriverTranscript::of`, including one that PINS the residue: a
    nondeterministic call that agreed twice is not caught. If someone makes the probe complete,
    that test fails and forces the FLOOR wording to be revisited rather than left stale.
  - MUTATION CONTROLS, both directions: flipping the length-difference branch to `false` reds
    exactly `a_length_difference_marks_every_line`; flipping the line comparison from `a != b` to
    `a == b` reds the other three. The tests are not vacuous.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sage

Review 54277's nit, and the way it was found matters more than the fix. The literal was authored
with `\` line-continuations, which Rust strips along with the following indentation -- correct as
written. `cargo fmt` then joined the continuation lines and kept the indentation as literal
content, so the printed line carried two 25-space gaps.

A regex over the source could not see it: the literal is one physical line with every continuation
properly escaped, which is what I checked first and what came back clean. Compiling the exact
literal and PRINTING it is what showed the gaps -- the same distinction this PR is about, that a
rendering is a fact you measure rather than one you derive from the source.

Swept the class rather than the site: every string literal in the file was checked for embedded
space runs. One other hit, `FLOOR-COMPILE-CLEAN-OVER-BUDGET`, is pre-existing and not in this
diff, so it is left alone.

Selftest re-run after the change: arm preserving EQUIVALENT over 12 derived calls, arm changing
DIVERGENT at the authored difference. Both arms still discriminate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

End-to-end proof: the same tree, before and after

This PR's own CI cannot produce this evidence. The receipt phase selects changed .dag authorities, and this diff changes only Rust — so on #8743 the phase has nothing to select and the fix is never exercised against a real nondeterministic module. The selftest covers regression and false positives; it cannot show the fix working, because its fixture is deterministic by design.

So I ran it against a tree that does change std.algebra: a detached worktree merging this branch with #8726 (the algebra-nickname PR whose CI produced the original defect), full --required-ci, isolated so nothing could land on either PR branch.

Before — #8726 CI run 32451723349, same tree, unpatched gate:

behavioral-receipt: std.algebra DIVERGENT over 31 derived calls — seed:
  kernel_algebra_profile_value() = {"String": ..., "Bool": ..., ...}

...over a std_algebra.rs that required-regen had reported first_generation_equal=true for in that very run. A file compared against itself, answering DIVERGENT.

After — same tree, patched gate:

behavioral-receipt: std.algebra EQUIVALENT over 30 derived calls, with 1 EXCLUDED as
  nondeterministically rendered — kernel_algebra_profile_value. Those calls were NOT
  compared, so this green does not cover them
behavioral-receipt: nondeterministic_rendering=1 call(s) across 1 module(s) — FLOOR, not a
  total: instability is proved by two runs disagreeing, so a call whose randomized rendering
  happened to agree twice is not counted here and is compared as if it were deterministic.
  Not failures; each is a subject this fragment cannot ask about until emission is deterministic

The arithmetic is exact: 31 previously-compared calls become 30 compared + 1 excluded. The single excluded call is kernel_algebra_profile_value — the same function the 20-distinct-transcripts-in-20-runs measurement identified independently, reached here by the probe with no type knowledge and no hint. The other 30 calls in the same module still compare and still agree, so the module keeps its coverage instead of being refused wholesale.

The receipt-selftest phase in the same run stayed green with both pre-existing arms discriminating (preserving EQUIVALENT over 12, changing DIVERGENT at band_of(100i64) = High vs Mid).

What this run also confirms is NOT fixed

behavioral-receipt: gunbc.v1_interpreter_primitive_surface REFUSED — the emit produced no
  v1_interpreter_dispatch_generated.rs, so there is no candidate to compare.
  Not equivalence: a missing candidate is ignorance

That is a separate cause and this PR deliberately does not touch it. That artifact is generated by gunbc.generated_artifact_emit through main_wet, not by the mirror emit, so the fragment asks the wrong generator. The refusal is correct as written.

I nearly fixed it by excluding such authorities at selection, with the reason that byte coverage belongs to the generated-artifact drift gate. I checked, and that gate does not exist: dag/test/claim/generated_artifact_drift_test.dag is deleted (cli_run.rs still names the path twice), the surviving witness only checks that generation succeeds without comparing to the committed file, and DESIGN's CI paragraph lists the drift gates among what the floor cut left unguarded. So excluding it would delete the last observer of that artifact rather than route it. The real fix is to produce the candidate from the artifact's own generator — which would restore byte-level drift checking as a side effect — and it is not attemptable while main is red, since it resolves the corpus that currently refuses.

— sent from snappy-ferret-99

@gunbai-bot

gunbai-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

The red on this PR is main's, and this run proves the fix works on CI

Run 32455488884, required-ci: phases_run=6 failed=1. Every phase this PR touches passed:

required-ci: parse OK 50 file(s) parse-clean
required-ci: regen first_generation_equal=true
required-ci: regen-fixed-point fixed_point_equal=true
receipt-selftest: arm preserving EQUIVALENT over 12 derived calls — as required
receipt-selftest: arm changing DIVERGENT over 12 derived calls at the authored difference
required-ci: receipt-selftest OK both arms discriminate
required-ci: receipt OK every selected module is equivalent

receipt-selftest OK both arms discriminate is the load-bearing line: with the two-run instability probe in place, the pre-existing positive control and the pre-existing discriminating RED both still do their jobs, and the preserving arm additionally passed as a false-positive control (a deterministic fixture must yield nothing unstable, and the arm fails loudly if it does).

The single failure:

required-ci: FAILED PHASE floor refused: subject=c8784dd07c4b788e modules_resolved=3762
dag/gunbc/fleet_desired_admission.dag:169:7: error: non-exhaustive match:
    missing variant(s) FleetDesiredAbsent, FleetDesiredUndecodable

That file is not in this diff. Main is red for it — 2249df7d, e9e42f2f, 68ffa3ae all failed on main with the same line, starting ~3 minutes after #8701 merged. FleetDesiredRevision grew from two variants to four and this consumer was not updated in the same commit; #8643, which wrote the two-arm match, was exhaustive and correct when it landed. It is a resolve-time refusal, so every corpus-resolving phase hits it, and every PR that merges current main inherits it.

Worth knowing before anyone attempts the obvious fix: FleetDesiredAdmissionOutcome's AdmissionAdvanceAuthorized requires a non-optional from, so the FleetDesiredAbsent arm — the one case #8701's own comment says licenses a create — has no representable answer. Half of "just add the missing arms" does not typecheck.

— sent from snappy-ferret-99

@gunbai-bot
gunbai-bot Bot merged commit 3b40e68 into main Aug 21, 2026
1 check passed
@gunbai-bot
gunbai-bot Bot deleted the session/snappy-ferret-99-receipt branch August 21, 2026 08:56
gunbai-bot Bot pushed a commit that referenced this pull request Aug 21, 2026
…-merge was a hybrid

The conflict was in a HAND-MAINTAINED bin/ file, so the mirror-hold rule does
not apply. I first resolved the two conflict hunks mechanically, asserting that
the HEAD side of each was empty (it was, in both). THAT STILL DID NOT COMPILE:
the AUTO-MERGED region had pulled in main's call sites -- `admitted`,
`AdmittedPlan<'_>` -- without their definitions, which live in a region my
branch had diverged on. A hybrid whose halves are each authentic, produced this
time by git's own clean merge rather than by a hand resolution.

Root cause of the divergence: my branch was -362 lines against the merge base in
this file, which an earlier integration must have produced by taking the branch
side of an auto-merged region and reverting main's work. The namespace cut edits
.dag only, so it has no reason to touch this file at all -- verified: ZERO lines
in the branch's diff mention source-root, import, qualify or namespace.

Resolution: take main's file whole. Verified by execution, not by inspection --
cargo check -p v1-compiler --bin claim_executor now passes, where the auto-merge
failed with 3 errors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants