Repository navigation
Record the observed judge-source revision on every admission receipt, and refuse to actuate when it cannot be observed - #8797
Conversation
… it cannot be observed The receipt named what the compare-and-swap DID (#8768: target and expected prior) and never which code DECIDED it. That fact is not recoverable from anything else the run leaves behind: the admission workflow's checkout carries no `ref:`, so on a workflow_run event it takes the DEFAULT BRANCH TIP AT RUN START rather than the triggering head_sha. J == C is therefore a timing coincidence -- it holds while main has not moved between floor completion and admission start, and #8733's bounded queue makes the divergence ordinary rather than rare, since an entry can wait while main advances and then be adjudicated by whatever main became. This is the RECORDING half only. Pinning the judge to the candidate is a separate change, ruled on separately, and deliberately lands after this one: without a recorded judge the pinning is a belief about GitHub's checkout semantics, and with it the receipts say whether J == C actually held. Recording is unconditional under either pinning, which is why it goes first. THE UNOBSERVABLE CASE REFUSES RATHER THAN FABRICATES. observe_local_tree_revision returns a bare GitObjectId?, so the run cannot distinguish "the judge is X" from "I could not tell what the judge is" -- and a receipt naming an unattributable judge is worse than no receipt. The advance therefore refuses to actuate with a typed, located reason instead of publishing an advance whose adjudicator is unknown. (That carrier's answer/ignorance conflation is real and already leaking: fleet_revision_standing renders its Absent arm as "not a git repository, or HEAD undecodable" -- an `or` in a cause string, because the carrier cannot tell the two apart. Splitting it is a separate change and is not required for this one to be correct.) WITNESSES, and the second one is here because the RED CONTROL CAUGHT IT PASSING VACUOUSLY: - the receipt names the judge, distinctly from the target and the prior - the judge operand is not the target or the prior -- which, as first written, was trivially true when the operand was DELETED ENTIRELY. It returned PASS against a receipt with no judge at all while its sibling correctly returned FAIL. It now asserts the operand is PRESENT before asserting what it is not, and fails under the same plant. RED CONTROL: removing the judge operand takes BOTH judge claims FAIL and leaves the three pre-existing receipt/lease claims PASS. The fixture uses a third distinct hex so a renderer echoing the target or the prior into the judge position cannot satisfy them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…misleading `ref:` on the checkout pins repository CONTENT. It does not pin the WORKFLOW TRANSPORT: for a workflow_run event GitHub requires the .yml to exist on the DEFAULT BRANCH and takes it from there regardless of the triggering branch, and GITHUB_SHA for such a run is the last commit on the default branch. Verified against the upstream reference, not inferred. WHY THIS LANDS NOW RATHER THAN WITH THE PINNING. Today, with no `ref:`, the checkout HEAD and GITHUB_SHA are THE SAME SHA -- judge and transport coincide by accident of configuration, so a receipt naming only the judge is harmless. They DIVERGE the moment the checkout is pinned to the candidate: the judge becomes the candidate while the transport stays main's. At that point a receipt carrying judge alone invites the reader to conclude every byte involved came from the candidate -- an inference that is false and, worse, UNFALSIFIABLE from the receipt itself. So the omission is named where the field would go, on the rule that an absent field reads as "not a subject". The judge is the revision of the checked-out tree this process was built from; it is not the transport, not the candidate, and not the subject the required floor judged. The full field set -- candidate, judge, required-CI receipt subject, workflow transport, the first two CHECKED equal and the transport RECORDED-not-equal -- belongs to the pinning change, because that is when the divergence exists. Shipping four fields whose values are provably identical today would land equality checks that cannot fail, which is the vacuous-claim failure the red control caught in this branch's own witness one commit ago. Annotation only; no behavior change. §4c grain checked locally: 0 `source annotation` diagnostics. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
What the read observes is the CHECKOUT's HEAD. What the receipt asserts is the provenance of the BINARY THAT DECIDED. Those are one fact only because the workflow builds that binary from that checkout inside the same job -- `cargo build --release -p v1-compiler --bin gunbc`, toolchain cache off -- which is a property of the CALLER, not of observe_local_tree_revision. Hand that job a cached, prebuilt, or externally-installed gunbc and HEAD still reports the checkout. The receipt would then name a judge that did not judge, confidently, with nothing in the receipt able to reveal it. That is the same defect this branch exists to fix, one level up: a field whose subject is narrower than its name. THE CONDITION, stated so it can be checked rather than assumed: the binary executing this decision was built, in this job, from the tree this read observes. It holds today. It is not enforced anywhere, and nothing fails if a future workflow edit breaks it. Closing it properly means the binary carrying its own build provenance rather than the run inferring it from a neighbouring checkout. Until then the field is honest evidence under a named condition, not a structural guarantee -- and a reviewer can now attack the condition instead of discovering it. Annotation only; no behavior change. §4c grain checked locally: 0 `source annotation` diagnostics. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e run establishes "judge" asserts the identity of the BINARY THAT DECIDED. What is established is an OBSERVATION OF A SOURCE REVISION, valid under a caller condition stated one commit ago: the binary was built in this job from this checkout, no other binary was substituted, and tracked source did not change between build and decision. The prose already said that, and the prose is not where this is read. The field sits in operator-facing run-log text, so a reader sees `judge <sha>` and the qualification lives in a .dag comment they will never open. A name that outruns its evidence in the one place the evidence is consumed is rung inflation -- §4b calls that worse than sitting low, because an inflated class never ranks for climbing. It earns the stronger name when the pinning cut binds the build: observe/pin J before build, build the judge from J, re-observe before actuation, require both observations equal the candidate. An embedded self-reported build revision is stronger still and is the real terminal. Verified after the rename: both judge claims PASS, including the vacuity-guarded one. The first returned NO-VERDICT twice in batch position -- that is the 700s timeout killing a cold first run, not a defect; run alone it passes, and its sibling sharing the same fixture, pattern and module passed in the same batch, which is what rules out a compile break. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…re merge-readiness (main advanced 10 commits since CI)
…1-judge-receipt # Conflicts: # dag/gunbc/fleet_desired_admission.dag # dag/test/claim/fleet_desired_admission_witness_test.dag
…rved
The field records the SOURCE REVISION THE ADMISSION CHECKOUT WAS SITTING ON when it
adjudicated. The previous naming -- parameter `judge`, PR title "which code adjudicated
the advance", refusal text "cannot record which code adjudicated it" -- claimed BINARY
IDENTITY, which nothing in this repository yet establishes: no binary embeds its own
source revision. Those identities coincide in today's workflow only because the job
checks out one tree, builds the deciding binary from it in the same job, and adjudicates
in that same checkout. That is a property of the CALLER, not of this function, and it
diverges the moment the binary is pinned or prebuilt -- precisely the cut this recording
exists to make falsifiable. Naming it for the inference rather than the observation is
the rung inflation of Sec 4b, surviving in the durable review and witness surfaces after
the run-log field had already been fixed. Raised in side-chat review.
Extended to BOTH no-op arms: "this source decided not to mutate" is exactly as
attributable an adjudication as an advance, and recording only the mutating arm would
leave the two most common outcomes unattributable.
Rung: mitigatable. The refusal is real and typed -- the wet entry point declines to
actuate when the revision cannot be observed, rather than publishing an unattributable
receipt -- but the caller-coupling is held by an annotation, not by construction.
Next-rung trigger: a self-reported embedded build revision, at which point the binary's
source stops being inferred from the adjacent checkout.
The refusal names no cause on purpose: observe_local_tree_revision returns a bare
GitObjectId?, conflating "not a git repository" with "HEAD undecodable". Splitting that
Optional is separate work and is not required for this change's correctness.
EVIDENCE (green-by-execution plus a discriminating red, both run):
green 26/26 PASS, 0 FAIL, 0 verdictless, 26 enrolled
red dropped the field from the CONVERGED arm only:
FAIL both_no_op_receipts_also_name_the_observed_judge_source
PASS the_advance_receipt_names_the_observed_judge_source_revision
PASS the_observed_judge_source_is_present_and_distinct_from_target_and_prior
PASS a_no_op_action_still_renders_a_nonempty_script
The two advance rows holding green proves the no-op row is not riding on
them; the nonempty-script control holding green proves the failure is the
missing field rather than a broken arm.
Sec 4c 0 annotation-grain diagnostics, against a compile confirmed to emit (243 files)
-- a bare grep -c zero cannot distinguish no-match from nothing-to-match.
REBASED over main after #8733 landed. That PR restructured the same decision path
(AdmissionAdvanceAuthorized -> AdmissionActionAuthorized over a three-variant coproduct),
so this change was RE-DERIVED against the new shape rather than textually merged: each
conflict hunk was a choice between two different programs, not two edits to one.
My own merged #8768 renderer fleet_desired_receipt_expected_phrase and its two creation
witnesses are NOT carried forward, and that is a rung CLIMB rather than lost work.
FleetDesiredRemoteAdvance { accepted, expected_prior } now carries the prior
structurally, so RemoteRefMustBeAbsent has no spelling in the advance arm -- the state
that renderer existed to serve is unwritable. Restoring it would have re-opened exactly
what #8733 closed. Only the evidence carries forward: the surviving
the_receipt_names_the_expected_prior_beside_the_target covers the same subject one rung up.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Re-derived over main — the prior approvals were given against a different program, so please re-read rather than relying on the tally. Two things changed since the approving reviews: 1. #8733 landed underneath this. It restructured the same decision path — Worth flagging explicitly: my own merged #8768 renderer 2. The naming was narrowed, which was the substantive review objection and it was correct. The field recorded a checkout-HEAD observation while the title, body, parameter, refusal string, and witness names all claimed "which code adjudicated." Nothing here establishes binary identity — no binary embeds its own source revision. The identities coincide today only because the job checks out one tree, builds the deciding binary from it in the same job, and adjudicates in that same checkout: a property of the caller, not of this function, and it diverges the moment the binary is pinned. That is §4b rung inflation surviving in the durable surfaces after the run-log field had already been fixed. Now Also extended to both no-op arms: "this source decided not to mutate" is as attributable as an advance, and recording only the mutating arm would leave the two most common outcomes unattributable. Rung: mitigatable. Typed refusal is real; the caller-coupling is held by an annotation, not by construction. Next-rung trigger is a self-reported embedded build revision. Evidence — green plus a discriminating red, both executed: The targeted red is doing two jobs: the advance rows holding green proves the no-op row is not riding on them, and the nonempty-script control holding green proves the failure is the missing field rather than a broken arm. One process note against myself: my first batch run ended in §4c: 0 annotation-grain diagnostics, against a compile confirmed to have emitted (243 files) — a bare — sent from nimble-fox-671 |
Residue of this branch's conflict resolution: #8733 restructured the module and already imported gunbc.fleet_desired_observe, while my side added a second clause for observe_local_tree_revision. Taking "ours" for that hunk kept both, so the module carried two import authorities for one module and named observe_fleet_desired_revision twice. Raised by review 54484 (non-blocking). Verified by execution rather than assumed, because an import edit can break resolution: 26/26 PASS, 0 FAIL, 0 verdictless, no resolve error. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Fixed in You correctly diagnosed the cause too: it was residue of this branch's conflict resolution. #8733 restructured the module and already imported I went looking for whether the class was broader, and it is — but it is more benign than it first looked. Census over That looked like a live specimen of the silent last-import-wins hole DESIGN §4b records at zero live exposure. It is not. Worth noting the class is decidable and therefore a construction-wall candidate rather than a permanent ratchet, but at 151 sites it is its own change, not this PR's. — sent from nimble-fox-671 |
…re-cut, re-qualify, re-apply emitter fixes
…er the decision (#8831) WHAT WAS WRONG. The annotation above the advance witness said the receipt records the revision the admission checkout "was sitting on when it adjudicated". The wet entry point does not read HEAD at the moment of adjudication. Its order is: derive the authorized action -> observe HEAD -> materialize the action script so the observation lands AFTER the decision and BEFORE the actuation is written. The consequence the old wording concealed: a tree mutated in that interval would be reported instead of the tree that actually decided. Nothing in today's single-checkout job does that -- which is, once again, a property of the CALLER rather than of this function, and so belongs in the annotation rather than in a claim. WHY THIS IS THE SAME DEFECT AS THE ONE #8797 FIXED, ONE LAYER FINER. That PR narrowed `judge` to `judge-source-observed` because the name claimed binary identity the run does not establish. This clause claimed TEMPORAL ATOMICITY the run does not establish either, and I wrote it in the same diff that narrowed everything around it. Prose outrunning the mechanism is not a lesser class for being prose: Sec 4c is explicit that an annotation may preserve rationale but must not restate what the declaration does not say, and no `Accepted` program can read one, so nothing but review catches it. Raised in side-chat review after the merge. The refusal string moves with it: "which code this run adjudicated from" becomes "which source this run was running from". The old phrasing asserted the same atomicity in the one place an operator actually reads at failure time. Nothing here changes behavior -- the sole non-comment edit is that string. EVIDENCE, on the exact shipping bytes (re-run after the comment rewrap, not inferred from the pre-rewrap run): 26/26 PASS, 0 FAIL, 0 verdictless, 26 enrolled. Sec 4c: compile.frontend completed and emitted 0 `source annotation` diagnostics. Scope note: that compile's EMIT phase later hit the 900s timeout under host load (exit 124), so this is a parse-stage result only. Parse is the stage that produces annotation-grain diagnostics, so the claim holds -- but it is narrower than a full-compile receipt, and the bare `0` alone would have been a FALSE ZERO. The emitted-files positive control is what distinguished the two. Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…witness its wording (#8839) * Give the admission refusal a consumer: extract the reason, witness the wording WHY THIS EXISTS. The operator-facing refusal string outran its mechanism TWICE and execution caught neither time. It first said the run could not record "which code adjudicated" the advance (#8797 narrowed it), then "which source this run was running from" (#8831 narrowed that), and both invite the reader to infer the provenance of the EXECUTING BINARY. The mechanism establishes only that the admission checkout's HEAD was read after the action was derived and before it was materialized; no binary embeds its own source revision. Both narrowings were correct and both were caught by REVIEW, because a reason string built inline at its throw site has no consumer. Nothing in the corpus could go red for it. That is specification-without-execution in the place it is easiest to miss -- the typed decision stays right while the sentence beside it drifts -- and it is the same class #8787 landed for: a correct refusal coexisting indefinitely with misleading operator prose. Raised in post-merge side-chat review of #8831. WHAT CHANGES. `fleet_desired_unobservable_judge_source_refusal_reason` is extracted as a pure formatter and the wet entry point calls it, so the wording becomes a SUBJECT a claim can fail on rather than a literal buried in an exit path. The text is also narrowed one final step -- it now names the missing receipt field (`judge-source-observed`) and says "could not be observed after adjudication", which states the missing observation without inviting the binary-provenance inference. Behavior is unchanged: same arm, same typed refusal, same exit. WHY A WITNESS AND NOT A GREP. The new annotation QUOTES both retired phrasings to record why they were wrong, so a grep over the file would false-positive on the explanation of the defect. The witnesses read the function's RETURN VALUE, so the prose and the claim cannot collide. EVIDENCE (green plus the discriminating red the reviewer specified, both executed): green 28/28 PASS, 0 FAIL, 0 verdictless, 28 enrolled red restored the exact pre-#8831 wording: FAIL the_unobservable_judge_source_refusal_names_the_field_it_could_not_record FAIL the_unobservable_judge_source_refusal_claims_no_binary_provenance PASS the_advance_receipt_names_the_observed_judge_source_revision The untouched advance row holding green proves the two new rows fail for the wording rather than because the module stopped resolving. Presence before absence on the second row, for the reason the distinctness row upstream already carries it: three bare negations are satisfied by an empty or deleted string, so the positive conjunct pins the subject the negations must be true OF. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Attach the annotations to their own declarations again The formatter was inserted by anchoring on the `fn fleet_desired_authorized_action_script` line, which placed it AFTER that renderer's existing annotation. Under Sec 4c module-item grain a contiguous `//` run attaches to the NEXT declaration, so the two blocks merged into one and bound to the formatter: it acquired the CAS wire-word, no-op-arm and NonEmptyStr rationale that describes the renderer, and the renderer -- the subject all of that prose is actually about -- was left with none. The grain was VALID the whole time, which is why the frontend check I ran reported zero `source annotation` diagnostics and why I read that as clean. Syntactic attachment and correct attachment are different properties, and only the first is decidable at parse. An annotation on the wrong subject is worse than a missing one: it reads as authoritative rationale for a declaration it was never written about. Caught by review, not execution. Repair is placement only -- the formatter and its annotation move above the renderer's block, restoring the adjacency that existed before the insertion. No text edited, no behavior touched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
What this records
Every admission receipt now names the source revision the admission checkout was sitting on when it adjudicated:
on all three authorized actions — the advance and both no-ops. A no-op is also an adjudication: "this source decided not to mutate" is exactly as attributable as an advance, and recording only the mutating arm would leave the two most common outcomes unattributable.
The wet entry point refuses to actuate when that revision cannot be observed, rather than writing a receipt nobody can attribute.
What the name deliberately does NOT claim
An earlier revision of this PR called the field
judgeand said it recorded "which code adjudicated the advance." That outruns the evidence, and the overclaim is the interesting part:CFCby acceptanceJWGITHUB_WORKFLOW_SHA)What is actually established is a checkout-HEAD observation. It is not the revision of the binary that ran — nothing embeds that yet. Those identities coincide in today's workflow only because the job checks out one tree, builds the deciding binary from it in the same job, and adjudicates in that same checkout. That is a property of the caller, not of this function, and it diverges the moment the binary is pinned or prebuilt — which is exactly the cut this recording exists to make falsifiable.
So the field is named for the observation, not for the inference. The recording rung lands before pinning so that the pin has something to contradict rather than something to assume.
Rung
Mitigatable → the refusal is real and typed, but the caller-coupling is held by an annotation, not by construction. Next-rung trigger: a self-reported embedded build revision, at which point the binary's source stops being inferred from the adjacent checkout.
Evidence
Three claims added, and the second one earned its shape:
the_advance_receipt_names_the_observed_judge_source_revisionthe_observed_judge_source_is_present_and_distinct_from_target_and_priorboth_no_op_receipts_also_name_the_observed_judge_sourceThe middle row originally asserted only the two negations. Both are satisfied vacuously by deleting the operand altogether, so it returned PASS against a receipt carrying no judge field at all while its sibling returned FAIL — a claim that could not fail for the reason it existed. Presence-before-distinctness fixes it. Caught by a deliberately-emptied receipt, not by review.
Separately, the required floor was confirmed to both enrol and discriminate on this module: a planted deliberately-false witness produced
planned=10254 executed=10254 terminal=10254 passed=9946 failed=1with the probe named in the failure. A green floor alone would have established neither.Rebase note
Rebuilt over
mainafter #8733 landed. The creation arm is gone —FleetDesiredRemoteAdvance { accepted, expected_prior }now carries the prior structurally, soRemoteRefMustBeAbsenthas no spelling in the advance arm. My earlierfleet_desired_receipt_expected_phraserenderer and its two creation-witnesses dissolved into that shape rather than being carried forward; the survivingthe_receipt_names_the_expected_prior_beside_the_targetcovers the same subject at a higher rung.