Repository navigation
Commit eff0a96
fix(pm): a pure-regeneration head move keeps the contract-review record, decided on the committed trees (#19634)
Part of #19244 (the card stays open for the ruling's fourth bullet —
arm-time drift re-measurement in `references/landing-operations.md`, PR
#19379's region — and for the `check-governed-merges.mjs` CURRENT-head
prose; the seat returns it to the queue at this PR's landing)
Clause-②: no
A review record binds to a head, so any push re-owes the review. On a
generated-artefact-dense surface that is a loop the reviewed seat cannot
exit: somebody else lands, baselines drift, the seat regenerates, the
head moves, the record is owed again — measured four times in one round
on this card, with two PASSed pull requests left unlanded.
The maintainer ruled it (2026-09-20, director seat batch #193 item 2,
letter B′, comment 5749024878), verbatim and untranslated:
> 纯重生成提交不需要开达档复核记录
## What lands
**The rule text** — `references/contract-review.md` gains ONE line under
the head-binding sentence at :20 and retires one, so the file stays at
its ceiling of 60 (headroom 0), the new line at 110 bytes — it names the
literal `Regen-provenance:` token the reader matches, which is what the
ruling's execution paragraph orders into this line:
- 例外:纯重生成 head 后移原记录继续管;判据机读已提交树;PR 落 `Regen-provenance:` 行。
Retired as a provable duplicate: 「0 = 确定性行全清;4 = 任一不成立,只确定性行红才挡落地;3 =
环境答不了 ⛔ 不作干净。」 — its surviving homes are the checker's own header
section `## Exit codes — the refusal to read as clean, in one table`
(which AGENTS.md makes the authority on that detail, and which shows the
retired line had also drifted: 3 is PREREQUISITE NOT MET there, and 2 is
the cannot-answer verdict) and `SKILL.md` 〈入队与落地〉 :657 for 「只确定性行红才挡」.
The `Regen-provenance:` exact format now lives in the checker's C3
`moved-after-clear` remedy, the row a seat whose head moved lands on.
**The criterion, both arms, on committed trees**: of the paths `git diff
-z --name-only OLD NEW` lists, drop every one carrying `merge=os-regen`
(`git check-attr --source NEW -z merge --stdin`), then drop every one
this pull request never touched at either head — a path absent from both
`git diff --name-only MERGE-BASE-OLD OLD` and `git diff --name-only
MERGE-BASE-NEW NEW` moved only because the base moved, which is the
ruling's own 「the merge commit's own carry-over from main」. Empty is the
whole criterion. The second arm is what makes the exception fire at all:
without it a merge-forward lists every path main carried over and reads
them as hand-written.
**The mechanism**, once, in `scripts/pm/check-clause2-carriers.mjs`, and
reached by the queue guard through the lazy import it already takes (⛔
no second parser):
- `REGEN_PROVENANCE_LINE` reads one hop off either thread — the PR's or
its card's — in the shape `Regen-provenance: RECORD-ID · OLD-HEAD →
NEW-HEAD · COMMAND → (empty)`. Everything after the second sha is the
seat's own transcript and is deliberately unread.
- `regenChainToHead` walks back from the pull request's current head
over as many hops as the thread carries. Hops are de-duplicated on
record + from + to BEFORE the ambiguity test — the reader searches both
carriers and the governed text trains the dual-carrier habit, so one hop
posted on the PR and on its card is one hop — while two DIFFERENT hops
arriving at one head still end the walk rather than being ranked.
- `unexplainedPathsBetween` runs the ruled test on the two **committed**
trees: the two-dot name-only diff, the attribute read with `--source
NEW` (so `.gitattributes` itself is read out of a commit, never out of
the working tree), and the PR's own delta at each head against
`merge-base BASE head` — the base is `origin/main` in the carriers
reader and the merge group's own base sha in the queue guard.
- `regenCarry` answers four states that are never folded: `none` (no
line — today's rule, untouched), `carried`, `refused` (a line that does
not certify), `unreadable` (the environment could not answer — a commit
or the base ref this reader cannot reach).
- `gateBindingState` no longer reports `moved-after-clear` for a carried
move, and `locateReviewOfRecord` re-reads the record at the carried head
— pinned to the record id the chain names, so a line pointing at a
comment the thread does not carry certifies nothing.
**The line is a pointer, never the evidence.** Every reader re-runs the
test itself. A reader that cannot reach both commits or the base answers
with a gap: the pair is UNJUDGED in `--pair` and the queue guard refuses
on `EXIT_REFUSED_UNREADABLE` — ⛔ never clean, in either reader. A seat
that writes the line and nothing else has certified nothing.
The committed-trees half is not stylistic: it is comment 5748085403's
reading, where one un-added regeneration answered `git status`, `git
diff --cached` and `git diff` three different ways and the `--cached`
reading was main's side, which looks exactly like the answer.
## Measured, on real committed trees
Measured with the installed git (2.43.0), on this branch's OWN history
rather than a fixture:
| range | what it is | moved paths | verdict |
|---|---|---|---|
| `60c99d8` → `180ce09` | the merge-forward this PR made in round 1 | 2
hand-written `.changeset/*.md` that main brought; unexplained = 0 |
**CARRIED** (round 1's one-arm test refused exactly this commit) |
| `744a0a3` → `180ce09` | this PR's own base to its head — the lit
control, same reader, same run | unexplained = 3, this PR's own three
files | refused (correct) |
| `0b4022b` → `744a0a3` | a source change on main | 28 moved, 10 dropped
by the attribute, 18 kept | refused (correct) |
Both directions demonstrated on real trees. The line reader was also run
against the real specimen this card recorded (record 5746847791,
`5dd391125e` → `e1ae025756`) and parses it.
Ablation, one-shot through `scripts/ablation-replace.mjs` on the
committed tree: removing the hop de-duplication (blob `9203b8a3c258` →
`4369e387fbc9`, anchor 1 → 0, proved on disk) fails exactly the two pins
that cover it — 2 of 1140, by name — and the restore is byte-identical
to the HEAD blob with a clean `git diff HEAD`.
## Gates — every one, with the exit code captured before any pipe
`node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` derived 44 families for these three paths at the final head;
all 44 ran and `--ran` reconciles 44/44 with 0 NOT-MEASURED (a derived
zero: every row recorded an exit code and none is 3).
- 44 of 44 exit 0, including `check:pm-clause2-carriers` (1140 cases;
1115 on main), `node scripts/pm/check-governed-queue-guard.mjs
--self-test` (312 cases; 301 on main), `check:pm-skill-ratchet`,
`check:pm-skill-id-lint`, `check:skill-frame-sync`,
`check:pm-dispatch-gates`, `check:pm-governed-merges`,
`check:nul-bytes`, `check:doc-authoring`,
`check:cross-package-test-inputs`.
- Also run, outside the derivation: `check:pm-governed-prose` exit 0,
`node scripts/check-skills-token-ratchet.mjs` exit 0.
- `pnpm --filter @objectstack/lint run check:doc-formula-expressions`
first exited **3** (PREREQUISITE NOT MET — nothing measured). Re-run
after `turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint`: **exit 0**.
- `git merge origin/main` at the final head brought `49d5069` (17 files:
`packages/spec` field-scale and `scripts/pm/post-stamped.mjs`) — no
conflict, no `merge=os-regen` path moved, no deferral (`node
scripts/check-regen-pending.mjs` exit 0), `pnpm-lock.yaml` unmoved;
every gate above was run AFTER that merge, on the final head.
## Line ratchet — green, paid in the file's own currency
`pnpm check:pm-skill-ratchet :: exit 0` — 「contract-review.md is 60
lines (ceiling 60; headroom 0)」. The ceiling was NOT raised and
`scripts/pm/check-skill-line-ratchet.mjs` is untouched: round 1's two
lines compress to one and one provably duplicated line retires, the only
currency a line ratchet takes. Two other duplicate candidates were
examined and left in place because each carries a residue with no
surviving home (a scheduling clause at :26; the ③ of a numbered list at
:47).
## Concurrency
PR #19379 (draft, `claude/pm-superseded-references-tier`) is open on
`scripts/pm/check-governed-queue-guard.mjs`. Its diff was read first: it
rewrites the THIRD-leg header prose around the superseded
references-tier wording (lines ~279–310) and one self-test summary
string. This PR touches neither — its hunks are `git()`'s stdin,
`runGuard`'s reader parameter, the pair it builds, `recordVerdict`'s
carried fields, the CLEAR rendering and a new self-test battery. The
later lander merges once. `origin/main` was merged into this branch
before this PR opened.
`#19068` — the `exports`-map sentence in the same reference file — is a
different card and a different region; it is not addressed here and
remains open.
## Acceptance notes
- `check-half-states.mjs` H51 was measured, as the ruling's execution
stroke asks: it does **not** refuse a moved head. It fires only on a
verdict for the **current** head while the label is still hung, and says
so itself — "A review naming an OLDER head is NOT this row". It is
report-only patrol input and writes nothing, so nothing there needed
changing.
- `check-governed-merges.mjs` is the post-merge audit and refuses
nothing; its Tier S prose says a record "for the CURRENT head". That
sentence is now narrower than the rule, but it is prose in a report-only
tool and outside this card's file surface.
- The ruling's fourth bullet — arm-time re-measurement of drift becoming
standing practice — is about landing operations, not carrier discipline,
and `references/landing-operations.md` is PR #19379's region. It is not
landed here.
- The queue battery's former duplicate specimen is now a real class-(ii)
case — a generated path moved BESIDE one of this pull request's own. The
queue renders a refused carry as an absent record and does not print the
path, so the battery asserts the name at `unexplainedPathsBetween`, the
reader that owns the reason. Making the queue print it is a ~9-line
change, named and not taken.
- The de-duplication key is the exact record + from + to triple: the
same hop spelled with DIFFERENT sha abbreviations on the two carriers is
still two hops and still ends the walk — the refusing direction.
- `skip-changeset`: `.claude/**` and `scripts/pm/**` are in no package's
`files[]`; this diff publishes nothing.
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 80ca0b1 commit eff0a96
3 files changed
Lines changed: 363 additions & 15 deletions
File tree
- .claude/skills/pm-dispatch/references
- scripts/pm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
40 | 41 | | |
41 | 42 | | |
42 | 43 | | |
43 | | - | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
0 commit comments