Repository navigation
Commit fd12471
fix(pm): judge a review of record's
Fixes #18174
`check-clause2-carriers --pair` read a review of record's `Served-tier:`
line only beside a gate clear, so `references/contract-review.md` :29's
「无此行不成裁决」 was enforced on one path of two.
## The defect, measured
One spelling, two answers, same script, same day:
| pair | gate hung? | the record's `Served-tier:` | `--pair` |
|---|---|---|---|
| objectstack PR #18157 / card #17991 (record 5661052272) | no —
`Clause-②` never declared `yes` | a stamp control, then prose, then the
constant — unreadable to this file's own reader | **0** |
| objectui PR #9486 / card #9191 (record 5662548425) | hung and cleared
| the same spelling | **4**, C7 |
The seam: `reviewOfRecord` answered `not-owed` before reading a thread
unless the pair was in C6's completed state (`needsRecordRead` →
`gateBindingState(pair).state === 'completed'`), and `c7ServedTierBelow`
returned `null` for anything but `found`. Measured on this branch's base
`b3b43b6`: a non-gated pair carrying an unreadable record, one carrying
the live shape, and one carrying no record at all were indistinguishable
— `pairRows` empty for all three, `reviewOfRecord` `not-owed` for all
three.
## The change
- **`locateReviewOfRecord(pair)`** — the gate-independent locator: the
same imported H51 heading / head-sha recognition, the same
`Reviewed-by:` third fact, the same newest-governs choice, with no
reference to the gate. No recognition moved.
- **`reviewOfRecord(pair)`** — that locator under C6's population gate.
C6's row, its 「not-owed」 scope, its shape sentence and its remedy are
unmoved, and both rows still read ONE comment chosen once.
- **C7** and the **C6-RECORD note** read the locator. C7's accept set
(one token, the constant's NAME), its exactness, its refusal of a
missing line and its remedy are untouched — widened in POPULATION only,
in the direction its own rule text names. Its opening sentence is now
gate-aware: it names a clear only where a clear rides on the record. The
note's citation half stays C6's, because the act it names is C6's.
- **`gather`'s `landingReads`** (was `readFiles`) buys the PR thread for
every pair on the `--pair` path, where the ruling puts this reading
(「清标前」); the sweep's population is unchanged, for the budget reason C5's
identical split already records. **`locatedRecordUnjudged`** is that
path's own #4690 half, so an unread thread is UNJUDGED and never clean.
- **Consequence pinned, not left to be discovered:** with the PR thread
in hand, `verdictThreadRows` hands C4 a thread it previously saw only on
completed pairs, so a verdict on a non-gated or still-hung pair is now
judged for the independence pair it declares. That direction only adds
verdicts to a reading whose newest-governs rule already lets a later
independent verdict displace an older self-review. Pinned in both
directions; the sweep's blindness there is restated as the limit that
survives.
## Evidence
**Reproduction on the real historical pair, replayed offline.** Both PRs
are merged, so `--pair` cannot form the pair from the live board; the
document carries the fetched `/pulls/18157`, `/issues/17991`, both
comment threads and the file list, and nothing else.
- before (`origin/main` `b3b43b6`): `--pair 18157 --pair-json …` → exit
**0**
- after: exit **4** — C7 naming comment 5661052272, the unreadable line
quoted back, and its stamp control read as NOT total (the 「回退证据」 half)
**Live control**, PR #18243 / card #18229 — open, non-gated, `Clause-②:
no`, record 5673963268 in the template's shape: exit **0** before and
after. After, the run also prints the C6-RECORD note naming that record
and saying the pair owes no clear (4 reads → 5).
**The sweep is unmoved, deterministically:** the same document in sweep
mode produces byte-identical `--json` output before and after. A live
gated pair (#18212) reads exit 4 with the same rows on both.
**Self-test:** 629 → 658 cases, `pnpm check:pm-clause2-carriers` exit 0.
A new battery (`#18174: …`, 28 cases) carries the measured non-gated
spelling beside the live one; the roster floor moves 22 → 23 and C7's
own floor 42 → 43. Four of C7's population pins were re-triaged rather
than left green for the wrong reason: each now spells a pair whose
threads were READ and carry no record, instead of passing because no
thread was ever fetched.
**Reverse verification**, from the committed fix: `c7ServedTierBelow`'s
locator call mutated back to `reviewOfRecord`. On-disk proof — injected
marker grep = 1, deleted anchor grep = 0, blob hash `5a79776b` →
`c4757e7a`. Self-test under the ablation: **5 of 658 red** (the measured
pair, its two sentence pins, the still-hung pair and the 重挂 pair).
Restored with `git checkout HEAD --`: `git diff HEAD` empty and the blob
back at `5a79776b`. Direction: turns red, as predicted.
**Gates**, union re-run at `7af15586` (`git rev-parse --short HEAD`),
working tree clean: `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` with no paths derives **35**
families; all 35 ran in the foreground with exits captured by redirect,
all **exit 0**; `--ran` reconciles **35 derived / 35 run / 0
NOT-MEASURED / 0 UNRUN**, every exit code recorded. Beyond the
derivation: `pnpm lint` (repo-wide, `eslint . --no-inline-config`) exit
0, and the two siblings that import this module —
`check-governed-queue-guard.mjs --self-test` (238 cases) and
`check-half-states.mjs --self-test` (4042 cases) — exit 0.
`skip-changeset`: `scripts/pm/**` is repo tooling that no package
`files[]` ships.
## Acceptance notes
- noted, not filed: in a SWEEP a record on a non-gated pair stays
invisible, because the sweep buys no PR thread for it. That is a
declared limit, written into this file's budget paragraph beside C5's
identical one, not a defect — and 承接者: nobody today; it becomes a card
only if a seat ever prices a per-pair sweep thread.
- noted, not filed: an existing pre-fetched `--pair-json` document that
omits the `comments` entry for the PR now reads UNJUDGED (exit 2) on a
pair that owes no record, where it read 0 before. That is this change's
own documented owing, restated in the doc-shape paragraph, not a
separate finding. 承接者: the MCP-only seats that hand this file a document
— the file's own refusal text names the key to add.
- The C4 reach on the landing path widens as a consequence of the bought
thread (see above). In scope, documented and pinned in both directions.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr)_
---------
Co-authored-by: Claude <noreply@anthropic.com>Served-tier: line on every pair that has one (#18251)1 parent b8ec127 commit fd12471
1 file changed
Lines changed: 358 additions & 87 deletions
0 commit comments