fix(pm): CONTRACT_REVIEW_TIER's docblock states a REVIEW tier, not a dispatch mandate - #17509
Merged
os-litant merged 1 commit intoSep 10, 2026
Merged
Conversation
…dispatch mandate The constant's docblock still described clause ② as the tier a card that changes contract accept/reject behaviour or widens the public surface "must be dispatched at". Since the 强制条款② narrowing landed, that is false: such a card is BUILT at the default judgment tier and REVIEWED at CONTRACT_REVIEW_TIER — which is what this same file already states in the MANDATORY_TIER_GLOBS clause-② bullet and prints from `tierLines` on every `--tier` run. The docblock was the one site left contradicting both. Prose only. `deriveTier` encodes clause ① and nothing else, so no code path and no printed line moves. Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 10, 2026
os-litant
marked this pull request as ready for review
September 10, 2026 18:46
os-litant
enabled auto-merge
September 10, 2026 18:46
os-litant
deleted the
claude/issue-16914-dispatch-gates-clause2-docblock
branch
September 10, 2026 19:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #16914
The residue of #16914 after PR #16915 (#16905) landed the 强制条款② narrowing: one docblock sentence in
scripts/pm/dispatch-gates.mjs. Prose only —deriveTierencodes clause ① and nothing else, so no code path and no printed line moves.The sentence
Before (
scripts/pm/dispatch-gates.mjs:10489-10492):After:
The same file already carries the post-narrowing shape at its two other sites — the
MANDATORY_TIER_GLOBSclause-② bullet (「built at the default tier and REVIEWED atCONTRACT_REVIEW_TIER— in the spec seat only」,:10553-10555) and theclause2stringtierLinesprints on every--tierrun (「owes a contract-review-tier REVIEW too (spec seat; default-tier build)」,:10759-10760). This docblock was the one site left contradicting both. Everything else in the docblock is byte-identical.Why this wording, on the four axes
The one judgement call was how far to rewrite: (A) swap "dispatched at" for "reviewed at" and stop, (B) the wording above, which names both halves of the review and states the build tier explicitly, or (C) B plus a new self-test case pinning the docblock's prose. 实际业务需求 is measured, not hypothetical: this docblock is what the next editor of the tier constant reads before touching it, and the drift it carried is exactly what a
--tierreader would have to reconcile against the instrument's own printout — A leaves that reconciliation unstated ("reviewed at" alone never says where the build happens), so B is the option that answers the real question the reader arrives with. 项目长远合理性 favours B over C: the file's own #15310 precedent pins a docblock only against something it can COMPUTE (COMPOUND_ANCHOR_LEDGER's counts), and clause ② is deliberately not encoded anywhere here, so any pin would have to hard-code the new sentence — a second hand-typed constant, the very shape that precedent argues against, and a workaround rather than an architecture. 防 AI 写代码犯错 is the axis that decides between A and B: an agent reading A can still conclude "so I dispatch clause-② cards at the ceiling" because nothing contradicts it in the same breath, whereas B states the build tier where the wrong reading would be made — declaration and enforcement said in one place, which is the same reasontierLinesprints its clause-② note unconditionally rather than only on a hit. 创业阶段不扩散需求 rules out C outright and keeps B to six comment lines: no new battery, no new declared surface, no staged wording, nothing for a later PR to retire. Recommendation: B, as landed.Verification
Gate families derived from the FINAL diff by the script itself (
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no hand-built path list — the tool takes the change set from the merge base with three-dot semantics,1 path(s) vs merge base 0ee32edef). Every derived family was run, each exit code captured BEFORE any pipe, and the record reconciled with--ran:All 31 exited
0. The heavy one — this file's own self-test — ran under the container's shared verify lock:Beside the derived set:
node scripts/pm/check-governed-merges.mjs --test scripts/pm/dispatch-gates.mjs✅ NOT governed — ordinary queue landing applies to a PR with exactly this file list.npx eslint --no-inline-config scripts/pm/dispatch-gates.mjsgrep -naPover the edited file)The seven artifact-roster families the derivation flagged with ⛔ (their roster sits in a directory this diff's path is in, so their silence is evidence in neither direction) were read rather than assumed:
check-published-list-mirrors.mjsand its--self-test,check:console-injection,check:engine-double-contract,check:i18n-stale-fill,check:pm-label-desc-capall exit0.check:published-readme-exportsexits3— NOT MEASURED, prerequisite: it reads 45 packages' builtdist/*.d.tsand this worktree has no build; a comment inscripts/pm/cannot move any package's built type surface, and the repo-wide build belongs to CI.The eslint run is a narrowing, and here is the proof it excludes nothing. ① Population read from eslint's own config, not guessed:
isPathIgnoredovergit ls-filesputs 6,570 of 8,303 tracked files in the lint population. ② Files this run actually linted, counted from--format json: 1, 0 errors, 0 warnings. ③ Invariance for the other 6,569:calculateConfigForFileon the edited file returnsparserOptions{"ecmaVersion":"latest","sourceType":"module"}— noproject, noprojectService, so type-aware linting is off and every rule judging an untouched file reads only that file's own text. Six comment lines in one file cannot move another file's verdict. The repo-widepnpm lintstays CI's run.Acceptance notes
skip-changeset:scripts/pm/**publishes nothing from any released package — it is not in any package'sfiles[], and the diff is a comment. Label applied.dispatched atoccurrences survive in this file (:10521,:21352). Both are the clause-① misclassification incident narrative ("a card ... was claimed as 'not under the fable-mandatory roots' and dispatched at opus"), which is a correct account of what happened and not a clause-② mandate statement — a different sentence class, off this card's declared surface, and correct as written. Successor: whoever next edits this file's tier section.COMPOUND_ANCHOR_LEDGER, [finding] COMPOUND_ANCHOR_LEDGER's docblock counts its own table wrong — says "all 22 / fifteen genuine / seven accidental" over a table that already held 25 rows (17/8) #15310) checks the docblock's counts against a computation over the table, never against a hand-typed second copy; clause ② is deliberately not encoded here, so there is nothing to compute a pin against. Not inventing a battery for one sentence — reported, per the dispatch. Successor: whoever next edits this file's tier section.Clause-②: no — this is prose in an internal PM tool; no schema, accept/reject behaviour or exported surface moves, and the derivation's own
--tierrun prints no path mandate forscripts/pm/dispatch-gates.mjs.Generated by Claude Code