fix(ci): ratchet the raw-handle debt baseline across the PR boundary - #7825
Conversation
The `Raw-handle debt ratchet` step compared the counted sites against
`scripts/raw_handle_debt_baseline.txt` FROM THE PULL REQUEST CHECKOUT — a
number the same diff is free to move. Add bare `get_raw_{mut,const}_ptr` reads,
raise the baseline and the per-module ceilings to match, and the step passes:
the ratchet measured the diff against a value the diff had already edited.
`--update` refuses to raise, but nothing made CI run `--update`.
`--no-raise-vs <ref>` reads both recorded files out of the pull request's merge
base and fails if the checked-out copies are larger anywhere: the total, an
existing module's ceiling, or a module absent from the base's list (which is a
raise from zero, not a fresh start). Unchanged and lower both pass, so paying
debt down stays a one-step change.
THE WAY THIS RULE DIES IS BY PASSING.
An unfetched merge base makes `git show <ref>:<path>` report every file as
absent, which is indistinguishable from "the gate did not exist on that side" —
and that reads as a legal no-op. So the ref is RESOLVED FIRST, and an
unresolvable one raises rather than comparing against nothing; the workflow
gates the step on `github.event_name == 'pull_request'` rather than on an empty
variable, so a push build skips it by declaration instead of by silence.
`--self-test` grew eight cases: three raises that must fire, four legal diffs
that must not, and the unresolvable ref that must fail rather than pass.
Verified end to end against `origin/main` in a real checkout — clean tree
passes, `999` in the baseline file fails with the specific diagnostic, and a
bogus SHA exits 1 with the fetch hint.
Fixes #7659
📝 WalkthroughWalkthroughThe raw-handle debt checker now compares pull-request totals and module ceilings with the merge base. CI resolves or fetches the base commit and runs this check only for pull requests. Self-tests cover increases, reductions, unchanged debt, and unresolved references. ChangesRaw-handle debt ratchet
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/test.yml:
- Around line 262-267: Update the workflow step around BASE_SHA and
raw_handle_debt.py to also obtain the pull request head SHA, fetch both commit
histories with sufficient depth, compute their actual merge base using git
merge-base, and pass that resulting SHA to --no-raise-vs instead of BASE_SHA.
Preserve the existing commit-availability handling while ensuring the comparison
targets the PR’s merge base.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e60ebfaa-bf6c-41d7-a71a-4034f5bf20ba
📒 Files selected for processing (3)
.github/workflows/test.ymlchangelog.d/7825-raw-handle-merge-base-ratchet.mdscripts/raw_handle_debt.py
| env: | ||
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | ||
| run: | | ||
| git cat-file -e "$BASE_SHA^{commit}" 2>/dev/null \ | ||
| || git fetch --no-tags --depth=1 origin "$BASE_SHA" | ||
| python3 scripts/raw_handle_debt.py --no-raise-vs "$BASE_SHA" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Use the actual Git merge base.
Line 263 passes the base branch tip, not git merge-base of the pull request head and base. If the base branch advances after the pull request branches, this gate compares against a different revision than the PR objective requires.
Fetch both histories with sufficient depth. Compute git merge-base "$BASE_SHA" "$HEAD_SHA". Pass that SHA to --no-raise-vs. GitHub Actions checks out a pull request merge commit by default and exposes the head SHA separately. (docs.github.com)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/test.yml around lines 262 - 267, Update the workflow step
around BASE_SHA and raw_handle_debt.py to also obtain the pull request head SHA,
fetch both commit histories with sufficient depth, compute their actual merge
base using git merge-base, and pass that resulting SHA to --no-raise-vs instead
of BASE_SHA. Preserve the existing commit-availability handling while ensuring
the comparison targets the PR’s merge base.
Covers the 32 PRs admin-merged in one pass (audited in principle at the maintainer's direction): PerryTS#7768 PerryTS#7772 PerryTS#7779 PerryTS#7784 PerryTS#7785 PerryTS#7786 PerryTS#7788 PerryTS#7789 PerryTS#7797 PerryTS#7798 PerryTS#7801 PerryTS#7802 PerryTS#7804 PerryTS#7805 PerryTS#7806 PerryTS#7807 PerryTS#7808 PerryTS#7810 PerryTS#7811 PerryTS#7815 PerryTS#7816 PerryTS#7818 PerryTS#7819 PerryTS#7820 PerryTS#7821 PerryTS#7822 PerryTS#7823 PerryTS#7824 PerryTS#7825 PerryTS#7826 PerryTS#7827 PerryTS#7828. (PerryTS#7787 closed as already-landed via the PerryTS#7786 stack.) Per-change history lives in each PR's changelog.d fragment as usual. Claude-Session: https://claude.ai/code/session_01Y1QZ5wUP9gRSwpiweT4Wix
…ss_* (#7838) (#7840) * fix(runtime): convert #7811/#7815's new bare raw-handle reads to across_* (#7838) The raw-handle debt ratchet went red on main: 1,013 bare reads against a baseline of 998, with four per-module violations. The +15 all arrived with the two #6949 rooting fixes in the 2026-08-11 batch, and #7825 -- same batch -- closed the hole that had been letting a PR's own checkout carry the comparison baseline, so the ratchet only started seeing them once it landed. All fifteen convert. None needed a ceiling raise and the baseline is untouched: the total lands back on 998 exactly, and regex/replace_fn.rs returns to its recorded ceiling of 3. #7815 (5 sites, three modules, all previously unlisted -> all now zero) disposable.rs, messaging.rs, builtins/formatting/boxed_primitives.rs. Each is the exact shape across_* exists for: allocate the receiver, run one allocating coercion, then write through a re-read pointer. #7811 (10 sites in regex/replace_fn.rs) NOT the sanctioned "loop across a user-visible trap" shape that raw_handle_debt_files.txt permits joining the list for -- that shape is the three PRE-EXISTING reads (`cur_str` in the two string-replacer loops, plus the subject re-read in call_string_replace_callback), which is what the ceiling of 3 was recorded for. The ten new ones are plain root -> one allocating js_string_coerce -> read-for-the-call, which across_* expresses directly. Two small local combinators carry the four two-receiver call sites; two receivers compose by NESTING across_const, the same way path::value_args::with_two_headers already does it. Two of the conversions are not purely mechanical, because writing the ordering out made a latent stale-address use visible in disposable.rs: - set_nonenum ran crate::object::set_property_attrs(obj as usize, ..) AFTER js_object_set_field_by_name, which allocates when the object grows. That side table is keyed on the address, so a pre-call copy does not fault -- it files the attributes under an address nothing looks up, and `error` / `suppressed` / `message` silently become enumerable on a SuppressedError that grew during the set. - js_nanbox_pointer(obj) was built BEFORE the SuppressedError.prototype lookup and returned afterwards. A NaN-box is a frozen address the collector cannot rewrite, so the returned value named from-space if the lookup collected. The box is now built last, after every allocating call. Both are the #7192 shape (the store is in-frame but after a call that allocates), and neither is reachable without evacuation moving the receiver, so this is ordering hygiene rather than an observed crash. Verified: scripts/raw_handle_debt.py exits 0 at 998/998, "110 module(s) within ceilings; every other runtime module is locked at zero". * docs(changelog): fragment for #7840 --------- Co-authored-by: Ralph Küpper <ralph@skelpo.com>
Fixes #7659. Reported by @jdalton in #7389.
The
Raw-handle debt ratchetstep compared the counted sites againstscripts/raw_handle_debt_baseline.txtfrom the pull request checkout — anumber the same diff is free to move. Add bare
get_raw_{mut,const}_ptrreads,raise the baseline and the per-module ceilings to match, and the step passes.
--updaterefuses to raise, but nothing made CI run--update.What changed
scripts/raw_handle_debt.py --no-raise-vs <ref>reads both recorded files outof the merge base and fails if the checked-out copies are larger anywhere:
Covering the per-module ceilings as well as the total closes the "clean one
module, dirty another" path, where the total can stay flat while a ceiling
moves.
The way this rule dies is by passing
An unfetched merge base makes
git show <ref>:<path>report every file asabsent — indistinguishable from "the gate did not exist on that side", which is
a legal no-op. So the ref is resolved first, and an unresolvable one raises
rather than comparing against nothing:
The workflow gates the step on
github.event_name == 'pull_request'ratherthan on an empty variable, so a
pushbuild skips it by declaration instead ofby silence.
Acceptance criteria
--self-teststill runs, and grew eight cases (three raises that mustfire, four legal diffs that must not, and the unresolvable ref)
git cat-file -efirst, thengit fetch --no-tags --depth=1 origin "$BASE_SHA"only if missing —actions/checkout's default depth does not include the base commitValidation
Run in a real checkout against
origin/main:test.ymlparses; thelintjob now has bothRaw-handle debt ratchetandRaw-handle debt ratchet vs. merge base.Summary by CodeRabbit
New Features
Documentation
Tests