Skip to content

fix(pm): the contract review's item ④ rides the narrowing face too - #26695

Merged
os-zhuang merged 1 commit into
mainfrom
claude/project-thread-2u3auo
Oct 27, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/project-thread-2u3auo

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #26527
Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:契约复核的 ④ 设计判断现在也挂在收窄面(Clause-②: no (narrowing)),模板、简报与规则文本同步改成三面;申报面照旧无 ④。
  • 为什么改:你裁了 A(评论 6442046166):只在运行时代码里收窄已发布接受集的 PR,复核也要对照 main 上的 spec 问「这次收窄是在消费端砍掉了一个已声明的能力,还是把 spec 自己的拒绝落实了」。
  • 风险与回滚:只动复核流程的文本与模板,不动任何运行时;回滚即 revert 这一个 commit。
  • 先看:scripts/pm/record-recognisers.mjs 的 REVIEW_FACES narrowing 行(fullReview: true)与简报的 narrowing 专用 ④ 段;contract-review.md L22/L30。
  • 两分钟验证:node scripts/pm/record-recognisers.mjs --brief-template --face narrowing 应打出 ④ 段(「the narrowing itself, read against the published spec on main」);--face declaration 的围栏内无 ④。
  • 需要你做的:批准本 PR(GOVERNED_APPROVERS);席位已请总监契约复审,批准后席位落地;在此之前保持 draft。

What changes

The maintainer's ruling on #26527 item 3 (letter A, ruling record 6442046166) hangs item ④, the design judgment, on the narrowing face of the contract review as well. A PR that narrows a published accept set in runtime code alone, touching neither packages/spec/src/** nor a governed path, now gets the same ④ the schema and rules faces get, in the narrowing's own shape: no hits files, so the judgment is of the narrowing itself, read against the published spec on main — does it take a declared capability away at the consumer, or make the spec's own refusal real?

  • scripts/pm/record-recognisers.mjs
    • REVIEW_FACES.narrowing gains fullReview: true; recordCarriesDesignJudgment is unchanged and now answers true for that face, so the record prints ### ④ Design judgment on --face narrowing (the declaration face, below tier, still prints three headings).
    • The --template notes name three faces and the narrowing scenario (the narrowing itself against the published spec on main); the declaration face alone is said to carry no ④.
    • The --brief-template on the narrowing face carries a narrowing-specific ④ instruction (read against the published spec on main; a capability declared and not delivered is an implementation gap, implemented or retired, never narrowed at the consumer) and a scope line saying ④ judges the narrowing over the whole-diff floor, lockfiles, generated output, changesets and prose not reviewed. The schema and rules faces keep the per-hits-file shape unchanged.
    • Docblocks on the face table, the record builder and the brief builder say the same.
  • .claude/skills/pm-dispatch/references/contract-review.md
    • L30: 「④ 设计判断只欠 schema 与 governed 规则文本两面」 → 「④ 设计判断欠 schema、governed 规则文本、收窄三面」 (114 B → 118 B, same line).
    • L22: the record-shape parenthetical 「(schema/governed 两面加 ④)」 → 「(申报面外三面加 ④)」 (115 B → 111 B, same line). The card named L30 only; L22 states the same face set a second time and would have contradicted L30, so it moves with it — declared in the report as a within-file widening.
    • 55 lines before and after; no new line; every edited line under the 120-byte budget.

Why

Faces resolve schema → rules → narrowing → declaration, so a narrowing PR that also touches a spec or governed path already carried ④; only the runtime-only narrowing fell to a face without it. That is exactly the face where the pm-dispatch principle 「声明而未兑现是实现缺口,补实现或退役,⛔ 不在消费端收窄」 is most easily broken (spec untouched, runtime narrowed first), and the review asked only whether the declaration line was spelled right. The ruling closes that gap without a new face or a new gate.

Tests

Forced test edits, all in the self-test of scripts/pm/record-recognisers.mjs (pnpm check:pm-record-recognisers):

  • Flipped: 「the narrowing face carries NO ④」 → carries ④ (fourth heading, fenced on --face narrowing); 「exactly the two path-read faces are full-review faces」 → the three at-tier faces (schema,rules,narrowing); 「the narrowing brief carries no ④」 → carries ④ in the narrowing's own shape (spec scenario, no hits-ONLY rule, no angle brackets, no model identifier).
  • Reworded fragments: the notes pin now reads 「on the schema, rules and narrowing faces」 and 「the declaration face alone carries no ④」; the brief face pin covers narrowing too.
  • Added: the notes name the narrowing scenario (template battery floor 28 → 29); the hits faces keep the per-file ④ shape and never the narrowing's (brief battery floor 17 → 18).
  • Unchanged and still green: the declaration face carries no ④ in record or brief.

Self-test at 78af1243: 219 cases pass, exit 0 (217 before the change). Mutation leg (one shot, scripts/ablation-replace.mjs, anchor hit exactly once, trap-restored, restored blob byte-identical to HEAD 462459281f4b): fullReview: true → false on the narrowing row ⇒ exit 1, 5 of 219 cases fail (the three flipped pins and the two added ones). No build or dist is involved; the script runs from source.

Acceptance notes

  • The card's acceptance line 「--template --paths packages/objectql/src/x.ts with a narrowing face prints ④」 is not reachable through --paths alone: reviewFace reads the narrowing face off the Clause-②: line, which a path list cannot hand it. Measured at 78af1243: --template --paths packages/objectql/src/x.ts (no changeset in the list) prints the declaration face, exit 0; --template --paths .changeset/x.md packages/objectql/src/x.ts is refused, exit 1, telling the caller to pass --face narrowing (pinned before this PR). The face that prints ④ is --template --face narrowing, and it does.
  • No other reader of fullReview exists outside this file (git grep fullReview at 78af1243: record-recognisers.mjs only); the queue guard and dispatch-gates do not read it.
  • The pm-dispatch SKILL.md rule the brief now echoes (「⛔ 不在消费端收窄」) is untouched.

Verification

Derived gate sweep at `78af1243` — 38 commands, every exit 0, captured before any pipe; `--ran` reconciliation: 38 derived, 38 run, 0 NOT-MEASURED, 0 UNRUN
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs --self-test :: exit 0
node scripts/check-self-test-wired.mjs :: exit 0
node scripts/check-self-test-wired.mjs --self-test :: exit 0
node scripts/check-self-test-workflow-commands.mjs :: exit 0
node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0
node scripts/check-whole-set-label-write.mjs :: exit 0
node scripts/check-whole-set-label-write.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0
node scripts/pm/check-harness-current.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:bash32-floor :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:cli-command-ids :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:entry-guard :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:parse-guard :: exit 0
pnpm check:pm-dispatch-gates :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-record-recognisers :: exit 0
pnpm check:pm-skill-id-lint :: exit 0
pnpm check:pm-skill-ratchet :: exit 0
pnpm check:pnpm-filter-targets :: exit 0
pnpm check:pnpm-flag-spellings :: exit 0
pnpm check:ratchet-remedy-authority :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:scripts-symbol-anchors :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:watch-hint-literal :: exit 0

Notes: pnpm check:pm-dispatch-gates ran its fast tier (1935 cases pass; 7 slow sections deferred, as the script does on every local run) in 5m30s; @objectstack/lint check:doc-formula-expressions needed @objectstack/formula and @objectstack/lint built first (through scripts/pm/os-verify-lock.sh, VERDICT command-exit 0, 99 s). Not in the derived list and not run locally: repo-wide pnpm lint (CI owns it) and the CI families outside the derivation; the PR check-runs are the record for those.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's run (repo-wide scan).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset — nothing here publishes (.claude/** + scripts/pm/**), so skip-changeset; both declaration lines are filled in above.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 block is the maintainer's Chinese read, as the dev contract asks).
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

The maintainer ruled (record 6442046166, letter A) that a PR narrowing a
published accept set in runtime code alone owes the same design judgment
the schema and rules faces owe: read against the spec on main, does the
narrowing take a declared capability away at the consumer, or make the
spec's own refusal real. `REVIEW_FACES.narrowing` gains `fullReview: true`,
the record prints the fourth section on that face, the template notes and
the reviewer brief name the narrowing's scenario in its own shape (no
`hits`, the whole-diff floor), and contract-review.md names three faces on
the lines that named two. Three self-test pins flip, two are added
(template battery 28 to 29, brief 17 to 18); the declaration face keeps no ④.

Claude-Session: https://claude.ai/code/session_01ADHkmRLPe6T3Z5Fy17DijY
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 27, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Oct 27, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · domain:skills#1 · session_01ADHkmSrRBdu9MdC6fc33Uu · head 78af1243 · 2026-10-27T13:15Z

  1. 形态 — Tier S (.claude/** hit) plus scripts/pm/record-recognisers.mjs: REVIEW_FACES.narrowing fullReview: true; --template notes and the narrowing brief carry ④ in the narrowing's own shape; declaration face still without ④; contract-review.md L22 and L30 same-line edits (111 B / 118 B), 55 lines unchanged.
  2. 前提实测 — seat ran the head: --template --face narrowing prints ### ④ Design judgment; --self-test 219 cases pass; the narrowing ④ text matches the ruling (6442046166, letter A) and SKILL.md's 「⛔ 不在消费端收窄」.
  3. 门禁 check-runs — dev ran the 38 derived families on the head, all exit 0 (--ran 38/38, 0 NOT-MEASURED); mutation leg (narrowing back to false) reds 5/219. CI on the head is read again before landing.
  4. 接受的偏差 — ① L22 edited beyond the claimed L30: the same rule's second statement of the two faces, left alone it would contradict L30 (seat picks the dev's option A, keep). ② The delta's acceptance command was the seat's error: --paths cannot reach the narrowing face (it is read off the Clause-②: line); --face narrowing is the reachable spelling and prints ④.
  5. 范围外去向 — none. Skills-docs: none. Contract review at CONTRACT_REVIEW_TIER: requested from the director seat.
  6. 落地条款 — governed (.claude/**): stays draft until a GOVERNED_APPROVERS approval and a PASS contract review on the head; then the seat readies, arms and the queue lands it.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 78af1243ae304c489f3f80867c94f007ca13361e
Local-runs: none
Scope: .claude/skills/pm-dispatch/references/contract-review.md + scripts/pm/record-recognisers.mjs, scripts/pm/check-skill-line-ratchet.mjs, .claude/skills/pm-dispatch/SKILL.md

Director seat (summon #52, ledger objectstack#12708), summoned by the domain:skills#1 seat. Read-only at the head above: the diff, card #26527 and its rulings (6442046166 — this seat's, batch #412 item 1 — and 6442757569, summon #51's batch #413 item 3, both letter A), the seat's ACCEPT 6442835214, the head tree (fetched, read with git show / git grep), the head's check runs. dispatch-gates --tier: .claude/** ⇒ the rules face, CONTRACT_REVIEW_TIER; record-recognisers.mjs is the gate that enforces the rule, so it is in scope as one change with it. Served at CONTRACT_REVIEW_TIER. This seat wrote the ruling the PR implements and is a reader of the template it changes; the review is of the diff against the ruling's words, named so the record is read with that in view. The seat records; it does not approve, ready, queue or merge.

① Derived judgments

  • The ruling is implemented as worded. Ruling A: REVIEW_FACES.narrowing gets fullReview: true; contract-review.md L30 reworded so ④ is owed on the schema, governed-rules and narrowing faces; the self-test pins flip; the face's ④ asks, against the spec on main, whether a runtime-only narrowing retired a declared capability at the consumer or made the spec's own refusal real. Head: the face row flips (REVIEW_FACES line 169); L30 「④ 设计判断欠 schema、governed 规则文本、收窄三面」; the template notes and the narrowing brief carry that exact question. recordCarriesDesignJudgment(face, tier) is unchanged (tier === CONTRACT_REVIEW_TIER && (face === null || face.fullReview)), so the flag alone moves the record, the template and the brief — one reader, no second list. git grep fullReview on the head: this file only.
  • Declaration face untouched. TIER_DEFAULT still prints three headings in record and brief; pinned both ways (the kept 「nor the declaration face」 cases). Correct — the ruling reached the narrowing face only.
  • L22 moved with L30. 「(schema/governed 两面加 ④)」 → 「(申报面外三面加 ④)」: the same rule's second statement; left alone it would have contradicted L30 in the same file. Within the card's rule, declared in the body and the seat's ACCEPT; the right call. 55 lines before and after; L22 111 B, L30 118 B under the 120-byte cap.
  • Narrowing brief shape is the ruling's. No hits on that face, so ④ is of the narrowing itself over the whole-diff floor, with the hits-ONLY rule withheld and the spec and cited code READ, not reviewed. The schema and rules briefs keep the per-hits-file ④ and are pinned never to carry the narrowing's wording. Consistent with contract-review.md L31–32 (逐 hits 文件判 for the path faces).
  • Pins: three flipped, two added, two batteries raised by one (28 → 29, 17 → 18), each named in the file's own ledger comment; the body's one-shot mutation (narrowing back to false ⇒ 5 of 219 fail) shows the pins are load-bearing. Read from the diff and the body, not re-run here.
  • Acceptance command corrected honestly. The card's 「--template --paths packages/objectql/src/x.ts prints ④」 is unreachable by design: the narrowing face is read off the Clause-②: line, which a path list cannot carry (a pre-existing, pinned refusal tells the caller to pass --face narrowing). The reachable spelling, --template --face narrowing, prints ④ — pinned. The card's intent is met; the wording was the filer's slip.

② Semver level

.claude/** and scripts/pm/** publish nothing; skip-changeset; Clause-②: no, Metadata-protocol: none in the body. No level owed. Correct.

③ Boundary flags

  • Governed path (.claude/**, Tier S): no approval yet; draft; reviewers os-zhuang, hotlong requested through the relay. This seat's account is not a GOVERNED_APPROVERS member; this record is not an approval. Under AGENTS.md Tier S, a PASS record at CONTRACT_REVIEW_TIER on the head plus green checks is the landing condition — this is that record.
  • Check runs on 78af1243 at this record: 26 success (incl. Lint · PM dispatch-gates — home of check:pm-record-recognisers — Lint · repo & tooling gates, Lint · scoped · tooling self-tests, Governed Surface Queue Guard, the PR-body guards, Test Core (2/8)), 20 expected skips, 1 in_progress (Test Core (1/8), no scripts/pm surface in it). Nothing red.
  • Two ruling records exist for the same item (6442046166 by this seat at 2026-10-27T12:37Z; 6442757569 by summon [WIP] Fix issues in action run step #51 at 2026-10-27T13:12Z), both letter A with the same execution; the PR cites the first. No conflict; the duplicate goes on this seat's ledger, not on the PR.
  • The seat's ACCEPT item 4 ② (acceptance command) and the dev's note agree with the reading above.

④ Design judgment

  • contract-review.md L22 / L30 against the ruling and the scenario it is accepted against (a PR that narrows a published accept set in packages/objectql alone, Clause-②: no (narrowing)): the reviewer at tier now owes a fourth section that reads the spec on main and asks whether the narrowing retired a declared capability — exactly the check SKILL.md 〈升级与决策〉 「声明而未兑现是实现缺口 … ⛔ 不在消费端收窄」 wanted and no face performed. The sentence names three faces and keeps 「spec、skills、ADR 皆已在内 ⛔ 不另立面」, so no new face is added and the register stays the rules face's definition. Holds; nothing to break.
  • record-recognisers.mjs as the gate: one boolean on the face table drives record, template and brief through the one existing reader; the narrowing brief's ④ names the question, the floor and the read-only rule, and the pins refuse a silent revert. The brief text stays free of angle brackets and model identifiers (pinned). Holds.

Implemented-by: claude/project-thread-2u3auo
Reviewed-by: session_01ADHkmQr732toX135tyo5zs

VERDICT: PASS


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants