Repository navigation
fix(guards): pin origin/main to the run's build base, so a re-run judges the main it was built on - #4996
Merged
Conversation
… first parent, not main's moving tip Refs #4983 A pull_request run checks out GitHub's merge commit at depth 1, so there is no merge-base and every baseline ratchet fell back to the origin/main TIP. A re-run keeps the old merge commit but fetches main fresh, so once main moves, main's own shrinks read as this PR's growth and an unchanged PR turns red on files it never touched (#4970 run 37945794011, m17). - lib_baseline_ratchet.sh: new FIRSTPARENT comparand, ahead of TIP, only for origin/main, only with no merge-base, only when the event is pull_request and HEAD is GITHUB_SHA with two or more parents. The parent is read from the commit object (HEAD^1 does not resolve under a depth-1 graft). Fail-closed: parent not fetched -> UNRESOLVABLE with a fetch-by-sha hint, never the tip; parent lacks the path -> BOOTSTRAP or ABSENT, never the tip. - ci/sections.yml (guard-tree and guard-cargo setup steps): on pull_request, fetch that first parent at depth 1. - census, complexity and readme callers: FIRSTPARENT admitted by census; UNRESOLVABLE hints name the fetch that resolves the ref. Red/green: ratchet_semantics_test.sh --class complexity C8 (control: the tip path reproduces the false red), C9 (parent unfetched -> RED at preflight, nothing measured), C10 (re-run GREEN on FIRSTPARENT), C11 (first run gives the same verdict on both paths), C12 (registered mutation at RATCHET-FIRSTPARENT-MUTATION-POINT turns C10 RED again). check_baseline_ratchets.sh --self-test gains 10 resolver/end-to-end rows; the same mutation turns 5 of them RED. Agent: aprender-a7n Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…first-parent comparand too The q-4983 sign-off round's minority lane found a second resolver with the same defect in the same guard job: check_no_fabricated_baselines.sh had its own resolve_base_ref, merge-base then the origin/main TIP. On a pull_request re-run after main shrank the Rust ledger, the PR's merge commit still carried the removed entries, so the ledger read as GROWN on a PR that never touched it. It now sources scripts/lib_baseline_ratchet.sh and takes the same FIRSTPARENT step: only with no merge-base, ref origin/main, a pull_request event and HEAD == GITHUB_SHA with two or more parents. Fail-closed as before: the first parent not fetched is UNRESOLVABLE, and fetched without the ledger it is ABSENT (this ledger has no bootstrap). Neither falls through to the tip. The UNRESOLVABLE text prints the fetch that is actually missing. Red/green, --selftest comparand table 3 -> 12 rows, all green with the event unset and with GITHUB_EVENT_NAME=pull_request. Rows: push keeps TIP and its verdict reds on main's shrink (the defect, reproduced); HEAD != GITHUB_SHA keeps TIP; parent unfetched -> UNRESOLVABLE, rc 1; parent fetched -> FIRSTPARENT and the re-run verdict is green; a single-parent head keeps TIP; a parent without the ledger -> ABSENT. Mutation: blanking p1 at FABBASE-FIRSTPARENT-MUTATION-POINT turns 4 rows RED (UNRESOLVABLE, FIRSTPARENT, re-run verdict, ABSENT all read TIP). The full scan still passes (36 entries, 0 added, 0 removed vs the merge-base). Refs #4983 Agent: aprender-a7n Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ges the tree it built against the main it was built on Every ratchet in guard-tree and guard-cargo compares the PR's tree with origin/main, and the setup step fetched main's TIP at depth 1. The tip moves while the merge commit does not, so a run that starts after main shrank a baseline or fixed a function goes red on lines the PR never touched: - #4813: the pipe-into-grep-q ledger read 62 on the PR against 60 on a tip that had moved on. - #4983: #4970's complexity step, run 37945794011 attempt 2, checked out the unchanged merge commit 60a5903 and judged it against main's moved tip acd599e. Attempt 1 and attempt 2 of the same commit disagreed. scripts/ci/pin_build_base.sh now replaces both jobs' fetch step. It points refs/remotes/origin/main at the commit this run was BUILT on: - pull_request: HEAD's first parent. HEAD must be a two-parent merge whose second parent is pull_request.head.sha, else the pin refuses. - merge_group: merge_group.base_sha. - any other event: the tip, deepened by one on push. On any doubt it prints ::error::pin_build_base and exits 1, so the guards skip RED, never green. Its --self-test (22 rows) runs in guard-tree before the pin. The library's own first-parent comparand (FIRSTPARENT, the commits before this one) stays as defence in depth: with the pin in place the tip path and FIRSTPARENT name the same commit. The pin also covers readers of origin/main that do not use the library, and the merge queue. Falsifier (ratchet_semantics_test.sh --class complexity, 22 checks, 0 failed): - C14: a stale-merge re-run, pinned, goes GREEN on the tip path (TIP = B1). - C15: a real complexity rise, pinned, stays RED (RED NEW newbie, TIP = B1). - C13: the same rise stays RED on the library's FIRSTPARENT path. - C16: a planted mutant of the pin (its pull_request arm disabled) turns the stale re-run RED again, against B2. Measured mutants: - MA (library first parent forced to HEAD): C9, C10, C12, C13 fail. - MB (pin takes parents[1]): C14 and C15 fail. C15 wanted 1, so the real rise went green under it. Also green on this head: the readme (12/0) and satd (10/0) classes, check_baseline_ratchets --selftest, check_no_fabricated_baselines, the fat_driver self-test (60/60), check_sourced_libs_option_neutral, and the 13 ci/sections.yml guards. Refs #4861 Refs #4983 Refs #3997 Agent: aprender-df Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
§13.11 rung 1 — quorum shadow verdict Shadow mode: this records a verdict and merges nothing. A refusal |
This was referenced Oct 10, 2026
Merged
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.
What
Every ratchet in guard-tree and guard-cargo compares the PR's tree with
origin/main. The setup step fetched main's tip at depth 1. The tip moves while the merge commit does not. So a run that starts after main shrank a baseline, or fixed a function, goes red on lines the PR never touched.Fix
scripts/ci/pin_build_base.shreplaces the fetch step in both jobs. It pointsrefs/remotes/origin/mainat the commit the run was built on:pull_requestpull_request.head.sha, else it refusesmerge_groupmerge_group.base_shaOn any doubt it prints
::error::pin_build_baseand exits 1, so the guards skip red, never green. Its--self-test(22 rows) runs in guard-tree before the pin.The ratchet library's own first-parent comparand (
FIRSTPARENT, from the #4983 commits on this branch) stays as a second line of defence. With the pin in place, the tip path andFIRSTPARENTname the same commit. The pin also covers readers oforigin/mainthat do not use the library, and the merge queue.Falsifier
scripts/tests/ratchet_semantics_test.sh --class complexity: 22 checks, 0 failed.NEW newbie)Measured mutants, both caught:
Also green on this head:
ratchet_semantics_test.sh: readme class 12/0, satd class 10/0;check_baseline_ratchets.sh --selftestandcheck_no_fabricated_baselines.sh;fat_driver.py self-test60/60;check_sourced_libs_option_neutral.sh;ci/sections.yml.Not in this PR
A second pin. The refinement gate in workspace-test pins
origin/mainwith its own event map (batch/ont-10: every remaining ONT-10 row for 0.70.0 (one PR, one quorum, one CI) #4502,ci/sections.yml:430-440):pull_request.base.sha,merge_group.base_sha, pushbefore. This PR leaves it alone. On the two real runs read, it names the same commit as this pin:On merge_group both read
base_sha. Two maps with no row comparing them can still drift apart without anyone noticing. Follow-up: one guard row that asserts both give the same commit per event, or the refinement step callingpin_build_base.sh. Changing a second gate here would widen this gate change.Self-test gaps. The second review's mutation run tried 27 mutants and killed 21. The six survivors are missing rows, not wrong results on the plants:
origin/main;|| true;FIRSTPARENTarm without itsorigin/maincondition, and without its empty-merge-base condition (two mutants);check_no_fabricated_baselines.shwithout itsorigin/maincondition;check_census_derived.shwithoutFIRSTPARENTin its accepted modes.They go in the same follow-up as the comparing row.
Gate change
This changes what a gate accepts on PR runs. Before merge it needs:
keep-open: #4861 and #4983 stay open for the follow-up named under "Not in this PR" (the row comparing the two pins, and the six self-test rows). #3997 is the parent epic.
Refs #4861
Refs #4983
Refs #3997
🤖 Generated with Claude Code