Skip to content

Commit 3270826

Browse files
os-steveclaude
andauthored
fix(pm): check-prior-rulings parses the ## Decision shape and names the corpus repo (#19353)
Fixes #19132 Clause-②: no Run from an **objectui** checkout, `scripts/pm/check-prior-rulings.mjs` refused — `docs/adr` parsed to zero decision units — so every objectui decision card was entitled to exactly one paste line, `Prior rulings read: unresolved`, and could never cite a prior ruling. Both halves of the lane direction (comment 5738994087) land here. ## Measured first — the structural difference between the two corpora The direction required the measurement **before** any widening. Taken this act at `objectui@0c2eb5e` and `objectstack@13d5294`. ### What counted as a decision unit before this PR Two shapes, both keyed on a **D-number**: a level-3/4 heading (`### D8 — One predicate, computed once`) and a decision bullet (`- **D4** — A tenancy kernel service…`) with the separator rule that rejects prose about a decision. Nothing else was a unit. ### Which marker objectui's ten files use | file | `**Status**:` line | D-number units | `## Decision` anchor | units (before → after) | |:--|:--|--:|:--|--:| | `0001-master-detail-subform.md` | yes | 0 | `## Decision` | 0 → 5 | | `0034-unified-runtime-metadata-persistence.md` | yes | 0 | — none — | 0 → 0 | | `0036-field-conditional-rules.md` | yes | 0 | — none — | 0 → 0 | | `0053-list-view-navigation-modes.md` | yes | 0 | `## Decision detail` | 0 → 7 | | `0054-ui-testability-contract.md` | yes | 0 | `## Decision detail` | 0 → 7 | | `0055-parameterized-bare-data-surface.md` | yes | 0 | — none — | 0 → 0 | | `0056-permission-editing-studio.md` | yes | 0 | `## Decision` | 0 → 6 | | `0057-console-ai-chat-one-conversation-docked.md` | yes | 0 | `## Decision` | 0 → 6 | | `0058-cascading-select-options.md` | yes | 0 | `## Decision: per-option …` | 0 → 5 | | `0059-action-params-shared-field-widgets.md` | yes | 0 | `## Decision` | 0 → 5 | | **total (10 files)** | **10 of 10** | **0** | **7 of 10** | **0 → 41** | **The dispatch's mechanism assumption 2 is REFUTED on its status half.** It read: no numbered D-units and 「as far as the seat can see」 no `**Status**:` line. The D-number half holds — zero across all ten. The status half does not: **all ten carry a `**Status**:` line**, in spellings this file already supports (`**Status**: Accepted — implementing (2026-06-05)`, `**Status**: Proposed (2026-06-22)`, …). So `extractStatusLine` and the positional `classifyStatus` needed **no change at all**, and objectui units arrive correctly classified. One measured consequence: `0034`'s `**Status**: Implemented (2026-06-06)` carries no word in `STATUS_WORDS`, so it classifies `unknown` — the intended loud bucket, not a regression. The whole structural difference is therefore **the decision unit, and nothing else**. objectui's decisions live under a level-2 `## Decision` / `## Decision detail` / `## Decisions` / `## Decision: TITLE` section whose parts are level-3 headings (`### C1 — Idempotent, direct triggers`) or numbered bold items (`1. **Two orthogonal fields, no mode discriminator.**`). ### The same blind spot is 57% of THIS repo | corpus | ADR files | files with zero D-number units | of those, carrying a `## Decision` anchor | |:--|--:|--:|--:| | objectstack `docs/adr` | 139 | **79** | **59** | | objectui `docs/adr` | 10 | **10** | **7** | This is not a foreign dialect the reader is being taught to tolerate — it is a shape the reader was already blind to in the corpus it was written for. ## The fix ### Half ① — the line names the repository whose `docs/adr` was read Derived from **this checkout's** `origin`, never `PM_SWEEP_REPO`: the corpus is a property of the working directory, and the two diverge in exactly the case the card names. Named in **both** arms, so the wrong-corpus case is visible in the line itself: ```text Prior rulings read: gate,required,spec,shape → 11 hits; ADR-0001 Decision §1; thread: not read (no --card); repo: objectstack-ai/objectui Prior rulings read: unresolved (repo: objectstack-ai/fakerepo) ``` The refusal headline names it too (`docs/adr` in objectstack-ai/fakerepo parsed to zero decision units), and with `--card` the report says **WRONG CORPUS** outright when the board and the corpus disagree — the card's second reading, the one six objectui cards were corrected in place for. ⛔ Still no `--repo` flag: the corpus is *reported*, never redirected. An unresolvable `origin` prints `repo: unknown` rather than dropping the clause, because a line that omits the repo reads like one that agrees with the board. The paste line stays **additive**: `references/decision-analysis.md` pins the terms / hits / named / thread field order, and the repo clause is appended **after** it, so the documented order and the literal `^Prior rulings read: ` grep are both unchanged. ### Half ② — a THIRD shape, scoped as a FALLBACK It runs **only on a file the two D-shapes parsed to zero units**. That is what keeps it from being a widening: the **53** D-carrying objectstack ADRs that *also* head a `## Decision` section are untouched, so a heading that merely *contains* their D-units can never double-count them. Prose is refused by three guards, each pinned: 1. the **structural** level-2 anchor — a heading whose title *opens* with `Decision`/`Decisions`, never a sentence that mentions one; 2. the **section-lead** unit needs a non-empty first paragraph, so a bare `## Decision` with nothing under it yields **0** — and an empty `docs/adr` still exits 3, the control kept; 3. the file must carry an ADR number, and a file that already speaks D-units is never re-read. A structural *part* carries its own line instead of needing a following paragraph, because a one-line item says everything on it (`ADR-0050`'s `1. **FormView.type = layout only**: …` would otherwise be dropped). Unit ids are positional (`Decision §1`, `Decision §2`, …): this shape has no D-number to *be* an identity, so the author's own label (`C1 — …`) rides in the heading beside it, and a bare `## Decision` takes the ADR's H1 so its lead unit is never nameless. ## Before / after, both checkouts, with exit codes | run — `--terms gate,required,spec,shape` | before | after | |:--|:--|:--| | `cwd` = `/home/user/objectui` (`0c2eb5e`) | **exit 3** — `docs/adr` parsed to zero decision units | **exit 0** — 41 units, 11 hits, line resolved | | `cwd` = objectstack | **exit 0** — 465 units, 117 hits | **exit 0** — 758 units, 180 hits | | empty `docs/adr` fixture (control) | **exit 3** | **exit 3** — and now names the repo | **The no-double-count invariant, measured rather than argued.** Every `docs/adr/*.md` in both repos parsed with the `origin/main` parser and this one, comparing unit id, line and text: | corpus | files | units before → after | files changed | of those, changed **from a non-zero count** | |:--|--:|:--|--:|--:| | objectstack | 139 | 465 → 758 | 59 | **0** | | objectui | 10 | 0 → 41 | 7 | **0** | Every changed file went `0 → N`. No file that already had units moved by a single unit, so no existing rank moved under them. ## Pins added — self-test 143 → 155 cases (`pnpm check:pm-prior-rulings`) Pins from both sides, as the direction required: - objectui's real structure (a `## Decision detail` of numbered bold items) → 2 units, ADR id from the filename, `accepted` from the status line objectui does carry, the item body present in the unit text so a term can match it, and the following `## Consequences` contributing nothing; - `## Decision` with an **empty body** → **0 units**; - a sentence *mentioning* a decision under `## Context` → **0 units**; - a file that **has** a `D1` heading *and* a `## Decision` section → `D1` only, ⛔ no double count; - a path with no ADR number → 0 units, anchor or not; - the repo clause in the resolved line, in the refusal, and its `unknown` fallback. The pre-existing fixture ranks are **unmoved**: the #16934 fixture still surfaces `ADR-0131 D8` at rank 1, the superseded ADR is still found-but-unnamed, the substring-noise control still holds, and the fixture corpus still parses to exactly 6 units — it carries no `## Decision` section, so the fallback never fires on it. Seven paste-line pins were updated for the appended repo clause; each is the same assertion with `; repo: unknown` added. ## Gates 30 of 30 derived families run at head `8ba9049`, each exit code captured **before any pipe**; `dispatch-gates --ran` reconciles **30 derived / 30 run / 0 NOT-MEASURED — a DERIVED zero** (every family recorded a code and none is 3). Derivation asserted with `--repo objectstack-ai/objectstack`. `origin/main` moved to `2277d1f` while the battery ran (`check:pm-dispatch-gates` alone took 1047 s on a box running three copies of it for three parallel agents), so the family list is current as of merge-base `13d5294`; CI and the merge queue are the authority past that point. ## Acceptance notes - **noted, not filed:** the `owner/name` parse from an `origin` URL now exists twice — the new local helper here, and the regex inside `localCheckoutServes` in `scripts/pm/check-half-states.mjs` (landed in #19288 while this branch was open). They answer different questions (a display name vs a boolean "does this checkout serve that board"), so neither can call the other today. The clean fix is one exported parser in `check-half-states.mjs`, which needs a file outside this card's surface **and** a new export against a `Clause-②: no` claim. Carrier: the next card in the #19191 / #19288 checkout-serving lane. - **noted, not filed:** `0034`'s `**Status**: Implemented (…)` classifies `unknown` because `Implemented` is not in `STATUS_WORDS`. The raw line prints beside it and `unknown` is the designed loud bucket, so this is not a defect. Carrier: whoever next widens `STATUS_WORDS`. - **noted, not filed:** 20 objectstack ADR files still parse to zero units — they carry neither a D-unit nor a `## Decision` anchor. Shrinking that further means a fourth shape, which this card's direction does not authorize and no measurement here justifies. Carrier: none today. - `scripts/pm/**` is not on the governed register (`docs/adr/**`, `.claude/**`, `skills/**`, `AGENTS.md`, `CLAUDE.md`, `docs/NORTH-STAR.md`), so no landing-tier record is owed. - Not published → `skip-changeset`, no changeset file. Net **+119** lines in the one file (141 added / 22 removed) against the PM's ≤ +120 budget. - The objectui copy is **not** edited here; it follows through the upstream port pin. --- _Generated by [Claude Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 231283a commit 3270826

1 file changed

Lines changed: 141 additions & 22 deletions

File tree

0 commit comments

Comments
 (0)