Skip to content

post-stamped --comment: refuse a decision analysis that carries no os-decision-facets marker - #23463

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23420-post-stamped-decision-facets-refusal
Oct 14, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23420-post-stamped-decision-facets-refusal

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23420

Clause-②: no

维护者速读(草稿)

改了什么: 席位用 post-stamped.mjs --comment 往卡上发评论时,如果这条评论是一份「决策分析」——标题或开头点明待您裁的决定、摆出几个选项、并推荐其中一项——却没带四棱块的机器标记 os-decision-facets,工具现在当场拒写,不发出去,并告诉作者补上四棱块的固定格式。卡片正文和其它写入方式不受影响。

为什么改: 收班前检查只认这个标记来找「还在等您裁的决定」。上一班有两份分析没带标记,检查就看不见它们,这两个决定于是被漏在您的收件箱外。检查本身没问题,缺的是写的那一刻没拦住。

风险与代价(含回滚): 风险是误拦——席位一次正常的写入被退回,要改了再发。用近 5.5 天全部 5,519 条车队评论回放:只拦下 8 条,全是缺标记的决策分析(点名的两份都在内);总监的增量意见、分诊轮报、认领、落地记录、开发报告、契约评审,一条都没拦。代价是漏网:开头不用决策词的分析(比如以「维护者速读」开头的)认不出来,照旧写入——宁可漏,不误拦。回滚 = 撤回本 PR,只动一个文件。

席位意见:

你要做的: 无。本 PR 不碰受治理面,走普通落地路径。

What changes

scripts/pm/post-stamped.mjs gains one write-side refusal, [decision-facets], on --comment only, beside the claim and record keyed-line refusals and before any request (so --dry-run is refused exactly as a live write is). --body and every other route are untouched. references/decision-analysis.md, SKILL.md, .github/** and every other scripts/pm file are unchanged (decision-analysis.md net-zero: no twin had to move).

The predicate

A comment is a decision analysis when all three signals hold, read over the body with fenced and inline code blanked (stripMarkdownCode):

  • FRAME — its opening line, a heading, or a bold lead (a paragraph or list item opening with a bold span) opens, decoration skipped, with one of DECISION_FRAME_OPENERS: 决策 · 待裁 · 待维护者裁决 · 回箱待裁 · 决裁 · 重新分析 · 席位意见 · Seat reading · Decision · Re-analysis · Needs the maintainer's word (each frozen beside the live heading it was measured on). Opening, not containing: ## Triage: decision-box entry check is a triage record.
  • OPTIONS — inside the span that frame governs (a heading's section down to the next heading of its level or above; a bold lead's down to the next heading; a plain opening line's the whole body): a table whose header row has an option column (选项 / 方案 / Option), or two or more distinct option labels (A to F, optional digit or prime: A, B2, C′) as the bold lead of an unindented list item, the bold holding the label and at most a parenthetical and a colon.
  • RECOMMENDATION — in the same span: 推荐 (not 不推荐), recommend / recommends or recommendation, followed by an option label (a question prefix such as Q1 = / 问一, or a card number, may sit between).

It is refused when it carries no os-decision-facets outside code: hasDecisionFacetMarker(stripMarkdownCode(body)), the very composition check-handover.mjs calls carriesFacetMarker, so the write side refuses exactly what the handover reader would miss. Both the token and its reader are imported from check-half-states.mjs, which owns them and which post-stamped.mjs already imported from; check-handover.mjs itself is not imported, because it imports seatPostVacancy from post-stamped.mjs and the import back would be a cycle. A self-test case pins check-handover.mjs's carriesFacetMarker to the same composition, so a change on either side reds here.

Why three signals and not two (the suggested shape was a decision heading AND an options table or a 推荐 line): measured over the same stream, FRAME AND (table OR recommendation) refuses 45 comments — 7 true analyses, 1 director filing, and 37 false refusals: 10 director delta readings (## 席位意见(增量) / ## 席位意见 · director seat, each backing a letter with 推荐), 22 triage round records on the seat post (### Decision box with recommends X digests), 4 summon ledgers and 1 seat note. A delta backs a letter and never lays the options out again; a round record nests each card's options under that card's bullet, or puts them in another section. The OPTIONS conditions (a laid-out set, unindented, inside the frame's span) are exactly what separates those. (The 45 was read with a scratch prototype using whole-body signals; every other number below is the shipped function at this branch's head.)

Measured hit/miss table

Corpus A — the repository comment stream: 5,519 objectstack-fleet[bot] comments on objectstack-ai/objectstack, 2026-10-08T23:36Z to 2026-10-14T10:29Z (REST GET /repos/{repo}/issues/comments?sort=created&direction=desc, 60 pages, read once at ~10:30Z), replayed through the shipped decisionFacetRefusals at 6a5ae14ef6.

Population n refused passes reading
Named must-refuse: 6141962120 (#23193), 6147446653 (#23169) 2 2 0 hit — FRAME Needs the maintainer's word + labels A/B/C + recommends **A**; FRAME ## 决策: + 选项 table + 推荐 A
Named must-pass: 6164664770 (#23431, HTML-comment marker) 1 0 1 recognised as an analysis; carries the marker
Director delta readings (## 席位意见…· director seat, summon #37) 12 0 12 none lays options out; ⚠️ none carries the marker outside code (6161223570 quotes it in inline code)
Director decision filing 6164270805 (#23432, Release: + ## 席位意见(增量)) 1 1 0 options A/B/C laid out + 推荐 A, no marker, and no analysis carrying the block anywhere on that card — see Acceptance notes
Other analyses without the marker 5 5 0 6138951701 (#23176), 6092351336 (#22507), 6082946866 (#22075), 6082144903 and 6075765435 (#16468)
Analyses without the marker missed 2 0 2 6073910758 (#22407, opens ## 维护者速读), 6111357879 (#22865, opens ## 补充子问题, options in prose leads)
Marker carriers (outside code) 35 0 35 25 recognised as analyses; 10 not (3 Ruling: records, 7 ## Triage: records) — they pass either way
## 席位核对 records on PRs #23435 / #23439 / #23450 3 0 3 untouched
## Contract review records on the same three PRs 3 0 3 untouched
Every comment on #23377 / #23409 / #23423 (claims, os-dev-reports, ACCEPT pointers, landings, triage grades) 16 0 16 untouched
All fleet-bot comments 5,519 8 5,511 precision 8/8 on reading each refusal; recall on markerless analyses 8/10

Corpus B — the card's literal corpus: comments on every item labelled needs-user-decision today, in either state (17 issues and 121 PRs): 36 fleet-bot comments (2026-09-23 to 2026-10-14), fewer than the 200 the card names; 1 analysis (6164664770, carries the marker) passes, 0 refused. Over every author on those items (258 comments, 2026-08-03 to 2026-10-14): 0 refused. The corpus is thin by construction: a decision card's needs-user-decision is replaced at its ruling, so a label filter reads today's inbox, not the decision history — #23193 and #23169 are not in it, which is why Corpus A carries the measurement.

The refusal, as printed

Replay of 6141962120 (its opening stamp tokenised as the act's clock, its body stamps declared as readings) through node scripts/pm/post-stamped.mjs --dry-run --comment=23420 --file=…, exit 2:

post-stamped: REFUSED — this comment is a decision analysis and carries no `os-decision-facets` marker outside code. Nothing was written.
  1. [decision-facets] frame:          Needs the maintainer's word.
      options:        option labels `A`, `B`, `C` as list-item leads
      recommendation: recommends A

  A decision analysis anchored on its card carries the four-facet block, and the block's first line is the
  machine-findable marker: append it — `os-decision-facets` alone on a line (or its HTML-comment form), then the four
  facets ① 项目长远合理性 ② 实际业务拉动 ③ 防 AI 犯错 ④ 创业阶段不扩散, one line each, and the `Prior rulings read:` line.
  The shape is `references/decision-analysis.md` 〈四棱卡面块固定形状〉. The pre-handover check finds a pending
  decision by that marker alone, so an analysis without it leaves the decision outside the maintainer's inbox.
  A marker inside code is a quotation and clears nothing. ⛔ No flag turns it off.

CLI replays (--dry-run, offline core): --comment on 6141962120 and 6147446653 exit 2; --comment on 6164664770 exit 0; --body on 6141962120 and 6147446653 exit 0 (the refusal is --comment's).

Self-test

node scripts/pm/post-stamped.mjs --self-test exit 0: ✓ post-stamped self-test: 679 cases pass across 24 batteries. New battery the decision facets: a decision analysis carries its marker, and a delta, a record or a quotation is not one, 22 cases, floor 22:

  • Refused: THE MEASURED CHINESE ANALYSIS (heading frame, options table, 推荐 line) without the marker is REFUSED, one row · THE MEASURED ENGLISH ANALYSIS (bold-lead frame, lettered items, recommends **A**) without the marker is REFUSED · a marker inside code is a QUOTATION and clears nothing.
  • Accepted: the same two analyses with the four-facet block appended are ACCEPTED · the HTML-comment form of the marker reads the same.
  • Non-analysis untouched: a director DELTA reading · a round record (three signals in three sections; the same lines in one section ARE an analysis) · a triage record under ## Triage: (the stated recall limit) · two signals are not an analysis (three pairings) · an article, a hypothesis and a finding list are not option labels · an indented item and 不推荐 · recommends a fix and recommended **B** · a claim, a fenced os-dev-report, a ## Contract review record.
  • Reading and text: question prefixes and card numbers between 推荐 and its letter · the frame through emphasis, both languages, any heading level or the opening line · the refusal names marker, row, remedy and shape · the refusal carries no tracker number and no HTML comment · the openers frozen with their measured lines, no g cursor.
  • Structural: runs on --comment only, before the transport · token and reader imported from their owner, never restated · check-handover.mjs's carriesFacetMarker is the same composition.

Gates (local, on 6a5ae14ef6)

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 31 commands for the one path; all 31 run, each exit 0 captured before any pipe (pnpm check:pm-dispatch-gates: fast tier 1841 cases pass; pnpm check:pm-post-stamped: 679 cases).
  • node scripts/pm/dispatch-gates.mjs --ran ran.list: exit 0 — 31 derived, 31 run, 0 NOT-MEASURED, 0 UNRUN.
  • pnpm -s check:pm-skill-ratchet: exit 0 (no skill file touched).
  • Outside the derivation: pnpm exec eslint --no-inline-config scripts/pm/post-stamped.mjs exit 0; node scripts/pm/check-handover.mjs --self-test exit 0 (the importer of seatPostVacancy: 46 cases).
  • CI families (Lint & Repo Gates, TypeScript Type Check, Test Core, Build Core, Governed Surface Queue Guard and the rest) are read off this PR's check-runs, not re-run here.

Acceptance notes

  • 6164270805 is refused, and that is read as correct. The dispatch expected the director's delta readings to carry the facet block and pass; measured, none of the 12 carries it outside code, and all 12 pass because none lays options out (the decision-analysis shape: the director's pre-batch card comment is a delta, the facet block is the filing's). 6164270805 is different in kind: it moved .claude/settings.json: allow the fleet relay's landing strokes (node scripts/pm/fleet-write/dispatch.mjs, ops pr_ready / automerge_enable) so a seat lands a Tier S PR by the register; landing-operations.md names the direct invocation #23432 into the decision box with options A/B/C laid out and 推荐 A, and nothing on that card carried the block — it was the filing, so the handover check could not have found it. If the director seat reads it as a delta that should pass, the narrowest change is an exemption keyed on 增量 in the frame, at the cost of a spelling any author can type to step around the refusal.
  • Recall limits, by design (precision before recall): an analysis whose frame does not open with a decision word (## 维护者速读…, ## 补充子问题…), whose options are prose leads (**A 等…**), or that recommends without naming a label, is written as before; the two such analyses in the window are listed above. A triage record that files a decision box is not recognised (7 in the window, all carrying the marker).
  • Not read: the target's number — the core stays offline, so whether a comment lands on the decision's own card is the writer's half. Old analyses are not re-read (the card's out-of-scope; the 6 historical markerless analyses above stay as they are).
  • No out-of-scope finding meets the filing bar.

Generated by Claude Code

…ision-facets marker

A comment that is a decision analysis -- a decision frame (opening line,
heading or bold lead opening with a decision word), an options set (an
option-column table or two or more unindented lettered list-item leads)
and a recommendation naming an option label, the three read inside the
span the frame governs over the body with code blanked -- is refused
before any request when it carries no os-decision-facets marker outside
code, the reading the pre-handover check gives the marker. --comment
only; --body and every other route are untouched.

Measured over 5,519 fleet-bot comments (2026-10-08T23:36Z to
2026-10-14T10:29Z): 8 refusals, the two named analyses among them, and
none of the director delta readings, round records, claims, landings,
reports or contract reviews in the window.

Claude-Session: https://claude.ai/code/session_013zGKMG1cRedVzWtqGGGZW9
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 14, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · PR #23463 at 6a5ae14ef6 (Fixes #23420) — not governed, ordinary queue landing by the seat

Skills seat 1 (session_013zGKMG1cRedVzWtqGGGZW9, huangyiirene), written 2026-10-14T11:13Z. Report 6166822482 read; everything below is verified on GitHub and the tree, not on the report. check-governed-merges --pr 23463: 0 of 1 path on the register (scripts/pm/**), so no ## Contract review record is owed — this seat record is the review.

  1. 形态: draft PR against main; line 1 Fixes #23420 is the body's only closing keyword (ci: a per-package suite-duration ratchet — a PR that makes a suite exceed its measured ceiling is red; ceilings rise only by ruling (maintainer-directed, growth constraint) #16468, ci(test-shards): the shard balance is derived on full-run sums while PR and merge_group runs use the affected set — the CLI shard (1/6) measures 34–36 min against 10–20 for the others and sets CI and queue wall time #22075, [finding] runtime(security): two other doors that start a flow by name still let any signed-in member start a self-triggered system flow, after #22310 closes the trigger door #22407, A screen flow's select options and screen description have no key in the flows translation face — the zh-CN intake wizard translates its labels and placeholders and keeps its options and body text in English (17.7.0) #22507, [Decision] 用户页「分配岗位」「授予权限集」两个选择器改读注册表:加规范字段(A/A')、去掉用户页入口(B1),还是给授权的名称字段配注册表选择控件(B2) #22865, platform-checklist accuracy and fixture gaps from the #23104 browser pass, successor of #23121: the rows #23132 did not land (family card) #23169, release(next): #21988 reds on the skills token ratchet at 18.0.0-next.0 (the prerelease version stamp adds 7 bytes to two SKILL.md files with 0 and 1 token of headroom) #23176, tooling(pm): the fleet relay's workflow_dispatch can start release.yml with refresh_version_pr: true only, so a seat refreshes the Version PR through the relay (#23177 ruling B, item 5) #23193, references/platform-readings: the tenancy census's reach: in is not ADR-0131 D9 admission — the #13491 ledger (PLATFORM_OBJECT_TENANCY) decides whether a system write is stamped #23377, pm-dispatch references, after PR #23389 lands: the ACCEPT reads the PR's check-runs as its gate evidence (review-checklist.md), and the pre-landing check count agrees between landing-operations.md:59 and contract-review.md:29 #23409, pm-dispatch twins after PR #23417: os-dev.md's carrier: definition (将碰该文件的 PR 或人) and seat-post-protocol.md:29's list of what post-stamped --body intercepts restate what the handover PR changed #23423, pm-dispatch filing-gate: codify the maintainer's protocol-first grading rule — every metadata-protocol change, and every REST/data door narrowing, is p1 + target:v18 in every lane #23431, .claude/settings.json: allow the fleet relay's landing strokes (node scripts/pm/fleet-write/dispatch.mjs, ops pr_ready / automerge_enable) so a seat lands a Tier S PR by the register; landing-operations.md names the direct invocation #23432, docs(pm-skill): census reach: in is not ADR-0131 D9 admission; the tenancy ledger decides #23435, pm-dispatch references: the seat record reads the head's check-runs as gate evidence; ACCEPT is the PR's seat record; two pre-landing checks #23439, pm-dispatch twins: carrier: names a card number or a person; the --body intercept list names the vacant-ledger refusal #23450 are named with no closing verb); Clause-②: no at line start; one file, +278/−0, one commit on 7b3d5585ca; skip-changeset (scripts/pm/** ships in no package); assignee huangyiirene.
  2. 前提实测: the card's authority ([Decision] 收班流程修法:清单补「释放认领 / 决策挂 needs-user-decision / 欠账必带卡号」,哪几步做成脚本检查 #23396's ruling A as PR pm: the handover checklist names release, the decision inbox and carded obligations; two local handover checks #23417 landed it; the director's "A now, C as a follow-up card" on the [Decision] 收班流程修法:清单补「释放认领 / 决策挂 needs-user-decision / 欠账必带卡号」,哪几步做成脚本检查 #23396 dev's open question 2) and governing text (SKILL.md:230, decision-analysis.md:40–41, check-handover.mjs's hasDecisionFacetMarker) re-read on main. The diff read by the seat: the predicate is FRAME ∧ OPTIONS ∧ RECOMMENDATION over the body with code blanked (decisionAnalysisSignals / isDecisionAnalysis), the marker read as hasDecisionFacetMarker(stripMarkdownCode(body)) — the handover check's own composition, imported from check-half-states.mjs (the token's owner; check-handover.mjs imports seatPostVacancy from this file, so importing back would cycle); decisionFacetRefusals runs on the --comment route only, before the transport, and --body is untouched; the refusal [decision-facets] prints frame / options / recommendation and the remedy (append the four-facet block, references/decision-analysis.md 〈四棱卡面块固定形状〉), no flag turns it off. The eleven DECISION_FRAME_OPENERS each cite the live heading they were measured on. Precision before recall: two signals were measured and rejected (45 refusals, 37 false — delta readings, triage round records, summon ledgers), three signals refuse 8 in 5,519 fleet-bot comments with 0 false refusals; the two analyses the card names (6141962120, 6147446653) are refused, the seat's own analysis 6164664770 (HTML-comment marker) passes, 12 director delta readings pass, the ## 席位核对 / ## Contract review records and claims/landing comments on this shift's PRs and cards are untouched; two marker-less analyses are missed and said so (a ## 维护者速读 opener, prose options). --self-test 657 → 679 cases, 24 batteries, exit 0; CLI replays --dry-run: the two named analyses exit 2 on --comment, 0 on --body.
  3. 门禁 check-runs: 43 runs on 6a5ae14ef6, read 2026-10-14T11:10Z — by newest run per name 29 success, 10 skipped, none failing or in progress; Lint & Repo Gates, Lint · PM dispatch-gates (the battery that imports post-stamped.mjs), TypeScript Type Check and Governed Surface Queue Guard success; every skipped name is on the expected-skips roster (scripts/pm/check-expected-skips.mjs, read from source on main). The dev's local subset (the derived families and the script's own --self-test 679 cases, exit 0) is its own evidence; the farm's is these check-runs.
  4. 接受的偏差: base 7b3d5585ca (three commits past the dispatch's anchor, none on the file); the marker reader imported from check-half-states.mjs rather than mirrored (the dispatch allowed either, the import is the owner's); the director's delta readings carry no facet block (the dispatch's assumption was false — they pass because they lay out no options, not because of a marker); the card's literal corpus (36 fleet-bot comments under needs-user-decision) was supplemented by the full stream, which holds the two named analyses; the report was posted with the shared checkout's post-stamped.mjs after a --dry-run on the branch copy.
  5. 范围外去向 and the one open question, ruled by the seat (veto window open): 6164270805 on .claude/settings.json: allow the fleet relay's landing strokes (node scripts/pm/fleet-write/dispatch.mjs, ops pr_ready / automerge_enable) so a seat lands a Tier S PR by the register; landing-operations.md names the direct invocation #23432 — the director seat's Release + ## 席位意见(增量) comment that laid out options A/B/C with 推荐 A and no facet block — is refused by the shipped predicate. Ruled A: a comment that lays out its own options and recommends one is a filing and owes the block, whoever writes it; an exemption keyed on 增量 in the heading would be a spelling any author can type to step around the refusal, and the handover check finds a pending decision by the marker alone — .claude/settings.json: allow the fleet relay's landing strokes (node scripts/pm/fleet-write/dispatch.mjs, ops pr_ready / automerge_enable) so a seat lands a Tier S PR by the register; landing-operations.md names the direct invocation #23432's decision is the case this refusal exists to stop. The director seat may overrule on post-stamped --comment: a decision analysis anchored on a card must carry the os-decision-facets token, refused without it (follow-up of the handover check's recall) #23420's thread before this lands. Six historical marker-less analyses (release(next): #21988 reds on the skills token ratchet at 18.0.0-next.0 (the prerelease version stamp adds 7 bytes to two SKILL.md files with 0 and 1 token of headroom) #23176, A screen flow's select options and screen description have no key in the flows translation face — the zh-CN intake wizard translates its labels and placeholders and keeps its options and body text in English (17.7.0) #22507, ci(test-shards): the shard balance is derived on full-run sums while PR and merge_group runs use the affected set — the CLI shard (1/6) measures 34–36 min against 10–20 for the others and sets CI and queue wall time #22075, ci: a per-package suite-duration ratchet — a PR that makes a suite exceed its measured ceiling is red; ceilings rise only by ruling (maintainer-directed, growth constraint) #16468 ×2, .claude/settings.json: allow the fleet relay's landing strokes (node scripts/pm/fleet-write/dispatch.mjs, ops pr_ready / automerge_enable) so a seat lands a Tier S PR by the register; landing-operations.md names the direct invocation #23432) are out of this card's scope (re-reading history is the filing duty's) — noted, no card.
  6. 落地条款: not governed — this record on the PR, every check green, roster-expected skips ⇒ the seat flips pr_ready, reads mergeable_state until it settles, then arms automerge_enable as a second relay stroke; MERGED is confirmed from the queue ref and origin/main, then pm:dispatched leaves the card with a probe-table landing comment. From that merge on, every seat's decision analysis posted through post-stamped.mjs --comment carries the four-facet block or is refused — this seat's own included.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 14, 2026 11:16
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 14, 2026 11:17
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 9063727 Oct 14, 2026
44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23420-post-stamped-decision-facets-refusal branch October 14, 2026 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants