Skip to content

docs(pm-dispatch): a decision analysis recommends exactly one option - #24520

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-24444-one-recommendation
Oct 19, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-24444-one-recommendation

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24444

Clause-②: no

What

Two lines of .claude/skills/pm-dispatch/references/decision-analysis.md, nothing else (1 file, +2 / −2):

  • line 9 (the director's pre-batch increment): 「推荐/回退/口径」 → 「推荐/口径」, the card's wording verbatim.
  • line 26 (the recommendation item of the card-face template): 「推荐 + 回退 + 置信缺口:荐一项、给回退项、明说看不见什么;⛔ 不沿用他席推荐。」 → 「推荐 + 置信缺口:只荐一,余各一句不取理由;盲区明说,⛔ 不因此另荐;⛔ 不沿用他席推荐。」

The four facets, the 自检 line and the 裁后执行 paragraph are untouched; SKILL.md is untouched.

Why

The maintainer, 2026-10-19: 「你的决裁总是有一个回退合理吗?是完全不同的开发方向。最终结论应该只有一个吧?是 skills 的问题吗」, then 「同意」 on the card's change. Ruling of record: director ledger comment 6259199455 (on #12708).

Route A: compressed in place, line count unchanged

The card's line-26 text measures 150 bytes; the ratchet's MAX_LINE_BYTES is 120 (scripts/pm/check-skill-line-ratchet.mjs), and the file sits at 50 lines against its 50-line ceiling (headroom 0). So the ruled wording cannot land verbatim on one line. Route A (compress the wording, keep every clause, add no line) loses no clause, so route B (fold the verbatim text into two lines and raise the ceiling 50 → 51 under the ruling) was not taken and the CEILINGS row is unchanged.

Clause survival, ruled text → landed fragment:

Ruled clause (card text) Landed fragment Change
item name 推荐 + 置信缺口 推荐 + 置信缺口 verbatim
① 只荐一项 只荐一 measure word 项 dropped
② 其余选项各一句不取理由 余各一句不取理由 其余选项 → 余 (the remaining options, set against 一)
③ 看不见什么明说 盲区明说 看不见什么 → 盲区 (blind spots)
④ ⛔ 不因此给第二推荐 ⛔ 不因此另荐 给第二推荐 → 另荐 (recommend another); 因此 and ⛔ kept
⑤ ⛔ 不沿用他席推荐 ⛔ 不沿用他席推荐 verbatim, byte-identical to the old line's tail

Nothing is added: no new clause, no new term, each clause keeps its own separator and its own ⛔. A shared-⛔ variant that kept 只荐一项 whole (…盲区明说,⛔ 不因此另荐,不沿用他席推荐。, 119 B) was weighed and refused, because it lets 因此 read across clause ⑤.

Line budget

before after ceiling
file lines 50 50 50
line 9 bytes 119 112 120
line 26 bytes 110 120 120

Control: with the card's verbatim text placed at line 26, the gate's own scanLineLengths reports [{"line":26,"bytes":150}]; on the landed tree it reports [].

Premise checks on origin/main f4755a68a

  • The card's line numbers 13 and 30 are off: the two strings sit at lines 9 and 26.
  • git grep -n "回退" f4755a68a -- .claude/skills/pm-dispatch/ .claude/agents/ gives 15 hits. Only these two are decision-analysis uses; the rest (os-dev wording ×4, SKILL.md line 249's ?? fallback, dispatch-runbook.md, execution-duties.md, lanes/triage.md, platform-readings.md ×3, reading-discipline.md) are untouched.
  • No script, test or doc pins the old wording: git grep for 回退/口径, 给回退项 and 推荐 + 回退 finds only the two lines themselves.

Verification, all at head ddf97945b

The 17 families node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives for this diff, each exit code captured before any pipe:

Command Exit
node scripts/check-closing-keyword-parity.mjs 0
node scripts/check-closing-keyword-parity.mjs --self-test 0
node scripts/check-comment-mask-corpus.mjs 0
node scripts/pm/check-harness-current.mjs --self-test 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions 0 (first run 3, PREREQUISITE NOT MET: @objectstack/formula and @objectstack/lint unbuilt in the fresh worktree; built under the verify lock, rerun 0)
pnpm check:agent-test-spelling 0
pnpm check:cross-package-test-inputs 0
pnpm check:doc-authoring 0
pnpm check:driver-memory-census 0
pnpm check:gitlink-declared 0
pnpm check:nul-bytes 0
pnpm check:pm-governed-merges 0
pnpm check:pm-skill-id-lint 0
pnpm check:pm-skill-ratchet 0, decision-analysis.md is 50 lines (ceiling 50; headroom 0), no line-length offender
pnpm check:refd-timer-probe 0
pnpm check:skill-frame-sync 0
pnpm check:watch-hint-literal 0

dispatch-gates --ran with the exit-coded record: 17 derived, 17 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero). Also run: pnpm check:pm-settings-deny-roster exit 0 (its roster lives under .claude). node scripts/pm/check-governed-merges.mjs --branch answers GOVERNED, Tier S (exit 3, the governed code). Text-only change: no tests, no ablation. The type-check lanes, test:repo and pnpm lint belong to CI.

Acceptance notes

  • Tier S (.claude/** only). This PR stays a draft; ready and queue belong to the owning seat after an isolated contract-tier review.
  • No changeset: .claude/** publishes nothing; skip-changeset is declared with this PR's creation.

维护者速读(草稿)

  • 改了什么: 决策分析写法删掉「回退项」。总监批前增量从「推荐/回退/口径」改为「推荐/口径」;卡面推荐条改为「推荐 + 置信缺口」:只荐一个方案,其余方案各用一句话说明为何不取,看不见的地方明说,但不因此再给第二个推荐。只动这两行,文件仍是 50 行。
  • 为什么改: 您指出「最终结论应该只有一个」。旧模板要求每次附一个回退项,实际常是另一条完全不同的开发方向,等于把决定又推回给您。
  • 风险与代价(含回滚): 纯文本,不发布,不影响产品运行。第 26 行为了压进每行 120 字节的上限做了措辞压缩(「其余选项」→「余」、「看不见什么」→「盲区」、「给第二推荐」→「另荐」、「只荐一项」→「只荐一」),五个分句全部保留,但不是卡上原文逐字。回滚 = revert 本 PR 的一个提交。
  • 席位意见:
  • 你要做的: 无。本 PR 属 Tier S,由席位隔离复核通过后入队落地。

Generated by Claude Code

Retire the fallback option from the decision-analysis template: the
director's pre-batch increment lists recommendation and wording only,
and the recommendation item becomes "recommendation + confidence gap" -
one recommendation, one sentence per other option on why it is not
taken, blind spots stated without turning into a second
recommendation. Line count unchanged (50 against the 50 ceiling); the
rewritten line is compressed to the 120-byte line budget.

Claude-Session: https://claude.ai/code/session_01HEdP5tPhqQfzwRmKDxwn85
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿,事后记录)· PR #24520 · domain:skills seat 1 · os-justin · session_01HEdP5tPhqQfzwRmKDxwn85 · 2026-10-19T23:03Z

  • 改了什么: 决策分析写法删掉「回退项」。总监批前增量从「推荐/回退/口径」改为「推荐/口径」;卡面推荐条改为「推荐 + 置信缺口」:只荐一个方案,其余方案各一句为何不取,看不见的地方明说,不因此再给第二个推荐。只动两行,文件仍 50 行。
  • 为什么改: 您 2026-10-19 的话:「最终结论应该只有一个吧」,随后对卡上改法「同意」。旧模板要求附回退项,实际常是另一条开发方向,等于把决定推回给您。
  • 风险与代价(含回滚): 纯文本,不发布。第 26 行为压进每行 120 字节上限做了措辞压缩:「只荐一项」→「只荐一」、「其余选项」→「余」、「看不见什么」→「盲区」、「给第二推荐」→「另荐」;五个分句与两个 ⛔ 全在,但不是卡上原文逐字。回滚 = revert 一个提交。
  • 席位意见: 接受路线 A。卡上原文 150 字节装不进 120 字节的行,文件又已顶满 50 行;压缩版五分句逐条可对照,不丢义、不添义。「只荐一」读起来略省,但在行预算下是最忠实的一版;若您更想要原文逐字,一句话即可换路线 B(折两行、上限 +1)。
  • 你要做的: 无。已由 os-zhuang 批准并经队列合并。

席位核对

  • 形态: draft、base main、首行 Fixes #24444、行首 Clause-②: no、assignee os-justin、skip-changeset 随创建同笔;1 文件 +2/−2;正文闭合关键词只有首行一处,另一个卡号 [PM seat] director(项目总监) — ⏳ vacant · 第 47 场(os-bill)已收班 · 第 43 场续场 5(os-zhuang)、第 44 场(os-project-manager)与第 46 场(huangyiirene)无收班简报 · 台账在评论 #12708 旁无动词。
  • 前提实测(席位,origin/main f4755a68a): 两段原文在第 9、26 行(卡写 13、30,已过时);git grep "回退" 在 .claude/skills/pm-dispatch/ 与 .claude/agents/ 下 15 命中,决策分析用语只此两行。分支 tip 上实测:第 9 行 112 字节、第 26 行 120 字节、文件 50 行,与报告一致。
  • 门禁 check-runs(head ddf97945b,2026-10-19T11:46Z): 38 条,26 success、12 skipped、0 failed、0 in_progress;check-expected-skips --pr 24520:OK,12 skipped 全在名单。dev 本地 17 条派生门禁全 0,--ran 17/17。check-governed-merges --pr 24520:GOVERNED,Tier S,4 行。
  • 接受的偏差: 路线 A 的措辞压缩(见速读);doc-formula-expressions 首跑 exit 3 为前置未建,补建后 0。
  • 范围外去向: dev 的中继 pr_create 读回行不列 labels 的观察 —— 平台事实,记座位贴 Notes,不立卡。
  • 落地条款与实际落地: Tier S。本席派出的隔离 CONTRACT_REVIEW_TIER 复核子代理在 2026-10-19T11:50Z 前后撞上账号周额度墙(HTTP 429,resets 23:00Z),未落任何记录;本席会话同时停摆。其间 os-zhuang(GOVERNED_APPROVERS 账户)APPROVED 本 head(review 5573069631),翻 ready、挂 auto-merge、入队,队列于 2026-10-19T14:45Z 合并为 5876b5474。按 SKILL.md 〈路径分叉〉②,授权账户的批准与合并即审核记录;本记录为事后补录,⛔ 不是第二次放行。

ACCEPT


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review — PR #24520 (card #24444), after-the-fact audit record rendered 2026-10-19T23:27Z

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ddf97945bf8f22609b3986e4052794d044987a96
Local-runs: none
Scope: .claude/skills/pm-dispatch/references/decision-analysis.md + scripts/pm/check-skill-line-ratchet.mjs (the line-byte budget and the CEILINGS row the deviation rests on), .claude/skills/pm-dispatch/SKILL.md and .claude/skills/pm-dispatch/references/lanes/director.md (the two pointers at the template), scripts/pm/check-half-states.mjs, scripts/pm/check-prior-rulings.mjs and scripts/pm/post-stamped.mjs (the readers of decision-analysis comments)

Read: the card body and its three comments (claim, os-dev-report, landing), the director's ledger comment 6259199455 on #12708, the PR body, its one-file list, the diff against main at the head (base f4755a6), the 40 check-runs on the head, and the governed file at base and head via git show. Not read: the dispatch order, the seat's own conclusions, the PR's reviews. The PR has since merged as merge commit 5876b54; this record is the audit of that landing, asked for by the maintainer (「两张 PR 你可以重新复审」).

① Derived judgments

  • D1 Public surface: none. .claude/** ships in no package and reaches no exports map; no schema, type or generated artefact moves. Right.
  • D2 Governed rule, the ruling: the maintainer's words 「你的决裁总是有一个回退合理吗?是完全不同的开发方向。最终结论应该只有一个吧?是 skills 的问题吗」 then 「同意」, recorded on ledger 6259199455 as "a decision analysis recommends exactly one option; no 「回退项」". After the diff the template asks for exactly one recommendation, one sentence per other option on why it is not taken, the confidence gap stated and ⛔ never turned into a second recommendation, ⛔ no borrowed recommendation. The accept-set of a decision analysis narrows from "recommend plus fallback" to "recommend one". Right, and the whole of what the ruling orders.
  • D3 Line 9: 「推荐/回退/口径」 → 「推荐/口径」, the card's text verbatim, 119 → 112 bytes. Right.
  • D4 Line 26: the card's 「推荐 + 置信缺口:只荐一项;其余选项各一句不取理由;看不见什么明说,⛔ 不因此给第二推荐;⛔ 不沿用他席推荐。」 measures 150 bytes; the landed 「推荐 + 置信缺口:只荐一,余各一句不取理由;盲区明说,⛔ 不因此另荐;⛔ 不沿用他席推荐。」 measures 120. Clause by clause: 只荐一 = 只荐一项 (measure word dropped); 余各一句不取理由 = 其余选项各一句不取理由 (余 reads as the remaining options, set against 一); 盲区明说 = 看不见什么明说; ⛔ 不因此另荐 = ⛔ 不因此给第二推荐; ⛔ 不沿用他席推荐 verbatim. Nothing added, no clause lost, each ⛔ on its own clause. Right. One narrative inaccuracy with no effect on the rule: the PR body says each clause keeps its own separator, but the separator between clauses ① and ② is 「,」 where the card wrote 「;」; the resulting grouping (recommendation pair ; gap pair ; independence) reads soundly.
  • D5 Nothing else in the file implies a fallback: the 骨架 line names 选项 / 推荐 singly, line 28 already forbids 分期半量 as a recommendation, the 自检 line and the 裁后执行 paragraph are untouched. Right.
  • D6 Nothing else in the repo carries the retired term: at base, 「推荐/回退/口径」, 「给回退项」, 「推荐 + 回退」 and 「回退项」 occur only on the two changed lines; at main after the merge, nowhere. Of the 15 回退 hits under .claude/skills/pm-dispatch/ and .claude/agents/ at base, the 13 that remain are shell, ??, promote and rewrite fallbacks, not the decision-analysis term; a sweep for fallback in other words (备选, 次选, 退路, fallback, 第二推荐, B′) finds only REST and MCP fallbacks. Right that the diff stops at two lines.
  • D7 Pointers and readers: SKILL.md line 231 and lanes/director.md line 53 point at the template without naming its items (director.md's 「四件」 is the 受管草稿批 four of line 12, unchanged). The machine readers of decision-analysis comments read the facets block (check-half-states H62), the Prior-rulings paste line (check-prior-rulings) and a frame plus options plus a recommendation letter (post-stamped decisionAnalysisSignals); none reads or requires a 回退 clause, so their accept-sets are unchanged. Right.
  • D8 Ratchet: 50 lines before and after against the 50 ceiling, CEILINGS row untouched, which is the route the ratchet header prefers (compress in place rather than raise); MAX_LINE_BYTES is 120 and the widest line is 120; the file's MAX_TABLE_ROW_BYTES pin of 0 holds (no table row). Gate verdict: Lint · PM dispatch-gates success. Right.
  • D9 Check-runs on the head: 40, all completed; 28 success, 12 skipped, none failed. Governed Surface Queue Guard success, Check Changeset success, every Lint and Type Check lane success. The gate verdicts are green.

② Semver level

  • .claude/** publishes nothing from any released package; the PR carries skip-changeset, no changeset file is in the diff, and Check Changeset is green. Correct: that label is for exactly this class of diff.
  • Clause-②: no on the PR body, no (widening) or (narrowing) arm. Correct: no accept-set of a published surface moves.

③ Boundary flags

  • F1 (claim) The card and the ledger cite lines 13 and 30; the strings sit at lines 9 and 26 at base, and the dev edited those. Answered: the text identity governs, the numbers were stale; no action.
  • F2 (claim and landing comment) The card's acceptance says draft until the maintainer's hand merge; the claim planned the SKILL.md 路径分叉 route (isolated review, then the seat queues); what happened is an authorised approval and merge by os-zhuang, an account in GOVERNED_APPROVERS, with the queue guard green on the head, while the seat's dispatched at-tier review never posted (account limit). Answered: the landing matches the card's own acceptance line and SKILL.md's 「授权批准 ⇒ 席位落地」; this record is the at-tier review, rendered after the fact at the maintainer's request. It does not adjudicate landing conduct (AGENTS.md feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14: the post-merge audit does, no seat judges it) and finds nothing in its inputs to file.
  • F3 (deviations 1) Route A, compressed line 26 instead of the card's verbatim text. Answered, accepted: the ruling is the maintainer's words and the card's five clauses, not a byte string; the verbatim string cannot land on one line under the binding 120-byte rule, and the card's one-file surface excludes route B; every clause survives (D4); the dev disclosed it in the PR body, in the 维护者速读 draft and in the report.
  • F4 (deviations 2) The 119-byte shared-⛔ variant was refused. Answered: right refusal; a shared ⛔ would let 因此 govern clause ⑤ and change its meaning.
  • F5 (deviations 3) The doc-formula-expressions gate needed a lock-held build before it could measure. Answered: immaterial; the check-run conclusions on the head are the gate verdicts and the Lint lanes are green.
  • F6 (deviations 4) Commit trailers are the model-free pair, not the harness's model-named trailer. Answered: correct per AGENTS.md (the pre-push hook refuses a model identifier in the pair); the head commit carries Claude-Session and Co-authored-by only, and no model identifier appears in the PR title or body.
  • F7 open_questions: none.
  • F8 (out_of_scope_findings) The relay's pr_create read-back names assignees but never labels. Answered: the label landed (the PR's labels read documentation, size/xs, skip-changeset by REST); the gap is relay tooling outside this card and is passed to the seat as a candidate tooling card, no action owed by this PR.

Implemented-by: claude/issue-24444-one-recommendation
Reviewed-by: session_01HEdP5tPhqQfzwRmKDxwn85

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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants