Skip to content

raw-handle ratchet red on main: #7811/#7815 landed 15 bare reads the same batch's #7825 now counts #7838

Description

@proggeramlug

Found by the post-landing audit of the 2026-08-11 batch. The Raw-handle debt ratchet lint step fails on current main (82f0e96): 1,013 bare reads vs baseline 998, four per-module violations. lint will go red on main's next CI run.

The +15 all come from the two #6949 rooting fixes that merged in the batch:

module new bare reads from
regex/replace_fn.rs 13 (ceiling 3) #7811
disposable.rs 3 (no ceiling) #7815
boxed_primitives.rs 1 (no ceiling) #7815
messaging.rs 1 (no ceiling) #7815

The code is not unsound — both PRs root their subjects in RuntimeHandleScope and re-derive raw pointers from the rooted handles after every allocating call; #7811's fragment records a clean run under the seeded schedule + quarantine. The debt is stylistic: the sites use manual get_raw_*_ptr re-reads where the ratchet's discipline wants RuntimeHandle::across_{mut,const,nanbox}. The ratchet only sees this now because #7825 (same batch) closed the hole that let a PR's own checkout carry the comparison baseline.

The fix, per scripts/raw_handle_debt_files.txt's own header

  1. fix(runtime): root constructor receivers across a later ToString coercion (#6949 shape b) #7815's five sites convert mechanically. Each is the exact shape across_* exists for: allocate receiver → one allocating coercion → writes through the re-read pointer. Convert all five; those modules stay unlisted (new code clean by construction).
  2. fix(runtime): root string/regex receivers across the ToString argument coercion (#6949 shape a) #7811's thirteen fit the header's ONE sanctioned join-the-list shape — a loop whose collection window is a user-visible callback (the replacer fn), with cur_str = || string_as_str(handle.get_raw_const_ptr(...)) re-deriving at every access across interleaved callback calls. across_* pairs one call with one re-read and cannot express this. Raise replace_fn.rs's ceiling 3 → 13 naming the loop and the trap, per the header.
  3. The header's condition for (2) is that the global baseline must not rise. After (1) converts 5, the total sits at 1,008 vs the 998 baseline — so either convert ~10 more pairs elsewhere in the same PR (the header's "honest move"), or the maintainer explicitly re-records the baseline at the new floor in the same commit that documents (2). The first is preferred; the second is at least a decision on the record rather than a silent raise.

Until this lands, every PR runs lint against a red step on main — the exact "required + red ⇒ every merge bypasses" gate-theatre shape CLAUDE.md warns about, so this is urgent for the ratchet's credibility, not just tidiness.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed defect or regression

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions