Skip to content

skills(pm-dispatch): pm:awaiting-maintainer owes a Maintainer-action: entry line, read by H55; 具名不升级类 gains the four bookkeeping classes - #17220

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-17017-awaiting-maintainer-carrier
Sep 10, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-17017-awaiting-maintainer-carrier

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #17017

Maintainer, 2026-09-09, verbatim and untranslated — the two instructions that opened the card. The first is the authority for Half B, the second for Half A:

「5986 这种任务不影响我们的产品质量,不应该让人类决策,项目经理自己当场决定就可以,而且这个应该开技能卡纠正」

「这个不应该是决策卡吗?哪个流程出了问题?」

Governed surface (.claude/**) ⇒ draft, human merge; skip-changeset (nothing here publishes: .claude/** and scripts/pm/** ship in no package files[]).

Half A — pm:awaiting-maintainer gains a machine carrier

The state had a semantic contract (决定已做, one action a seat cannot perform) and no machine carrier: pm:blocked owes Blocked-by:, pm:on-hold owes Restart-when:, and this state owed nothing, so a card waiting for a JUDGEMENT was indistinguishable from one waiting for a HAND.

  • references/state-machine.md §pm:awaiting-maintainerpm:retriage now specifies the entry line (the two placeholders are spelled as words in this PR body because the platform mutates angle-bracket fragments; the file carries them literally, in the same shape as Restart-when: closed OWNER/REPO#N):
    • awaiting 入态带 Maintainer-action: ACTION — done when EVIDENCE,双通道行锚定。 — ACTION = 席位做不了的动作, EVIDENCE = 可查证据; body OR comment; line-anchored and case-sensitive like the two sibling lines.
    • 写不出即决定待做;本态无机器出口:维护者完成后由总监席核验摘标 + 证据评论同笔。 — the classification test the card asked for (「裁完之后」 is the definition of needs-user-decision), folded onto the existing exit line.
  • SKILL.md 状态模型 row (pointer form, table row extended in place, 234 B ≤ the 342 B table pin): …;入态恒带行首 Maintainer-action: 行(细则见 references/state-machine.md),无行即半态.
  • references/core-rules.md twin (in place): pm:awaiting-maintainer 只剩站外人工动作,恒带 Maintainer-action: 行;pm:blocking ⛔ 不手工挂。
  • scripts/pm/check-half-states.mjs — H55, report-only, band state: an open card carrying the label whose body and thread carry no complete Maintainer-action: line. The line is read by the shared decorated-directive reader (directiveValues), so it is line-anchored, case-sensitive, decoration-tolerant, and a mid-sentence mention is prose. Both halves are required: a value without its done when half fires as "names an act but never its completion". The thread is bought only for a judged, body-clean card (needsMaintainerActionComments, H9's gate one field over) on the shared comment cache; three input states for the thread (unconsulted / unreadable / read), the unreadable one fires and says so. Remedy text: write the line if the act exists; if the line cannot be written because the card is asking for a RULING, the state is needs-user-decision (决定待做) and the entry was misfiled; the 台账 reader is the director seat's 职责三 (维护者动作台账). ⛔ Not a machine exit — the state still has none by construction; the row judges the ENTRY only.
    • Reconciliations, pinned on the source (H54's discipline): the H11 important-parked note now reads "has no machine exit BY CONSTRUCTION … the state now has an ENTRY predicate … and STILL no machine exit", and its awaiting remedy tells the re-ask to read the card's Maintainer-action: line first (still never prescribing a Restart-when: re-check — the existing pin at :19486 holds). H25's deferral note ("any requirement that the card NAME the awaited action … a protocol face the state-model row has not been written for yet") now says that face exists and H55 reads it; H25 stays the EXCLUSIVITY half, H55 is the ENTRY half, neither widened into the other.

Population scoping (ruling 2) — the landing day must not be red on the healthy case

Entries are split at a pinned instant, MAINTAINER_ACTION_LINE_SINCE = '2026-09-10T00:00:00Z' (the UTC day after the rule was written, in the file's own pinned-date idiom): a card last touched BEFORE it is a legacy entry and renders as ONE summary census clause — Awaiting-maintainer entries (H55): N open pm:awaiting-maintainer card(s) last touched before … — COUNTED here and filed as no row …, oldest #N (last touched YYYY-MM-DD); … — never as rows; a card touched ON/AFTER it is judged and can be a row.

The split reads updated_at, not the labeled event — the trade, stated. The entry instant is in no payload the sweep already holds (assumption C, measured: the loop holds the label pages' issue payloads, and the only event reader, H35, consumes the repo-wide stream filtered to gate-semantic labels — pm:awaiting-maintainer is not one), and this file's standing design makes no per-card timeline fetch. updated_at is the cheapest honest proxy and its error runs one way: updated_at is never earlier than the labelling, so a card last touched before the pin certainly entered before it (the census can never hide a post-pin entry); a legacy entry TOUCHED after the pin lands among the judged and can render as a row — an over-read costing one cheap idempotent act (write the line, or reclassify) on a card someone is already handling. An unreadable updated_at is judged, never counted as legacy.

Measurement — the live board at authoring (2026-09-09T17:4xZ; REST list endpoint + per-card /events; 0 MCP calls)

repo open pm:awaiting-maintainer cards (entry = last labeled event → last touch)
objectstack 5 #16737 (09-08T14:01 → 09-09T15:31, +25 h), #15233 (09-09T10:29 → same), #17129 (09-09T11:42 → same), #16804 (09-09T11:44 → 13:55, +2 h; also carries needs-user-decision — H25 already fires), #17151 (09-09T13:21 → same)
objectui 2 #5828 (08-29T06:45 → 08-29T06:46), #6596 (09-09T05:34 → same)
hotcrm 0
total 7 5 of 7 have updated_at within 3 s of the labeled event; 2 were touched after entering

Premise shift, reported rather than pressed: the card measured 55 (37 / 16 / 2) on 2026-09-09 and 55 → 55 across ~14 h. By dispatch the population was 7: the repo-wide events stream (H35's channel, read 30 pages per repo back to 2026-09-09T03:38Z / 2026-09-08T17:07Z) shows a reclassification pass that morning — objectui 15 unlabeled pm:awaiting-maintainer at 02:56–03:04Z, objectstack's named specimens at 02:29–05:12Z (#13636, #16500, #12675, #12884, #15406 unlabeled and closed; #12034 back to pm:queue). The three defects the card names (no carrier, H8 blind to the chosen state, the sweep reading shape and time only) are unchanged by the count, so the design stands; what changes is the landing-day shape — with the pin above, all 7 render as the census clause on the first sweep, not as rows. The search endpoint answers 403 from this container, so the control reading is the events stream plus a list-endpoint control on a populous label (pm:dispatched = 26 open).

Half B — the floor of what may reach the maintainer

具名不升级类 (SKILL.md 〈升级与决策〉) gains the four bookkeeping classes, each bounded by 「无产品可见行为变化」 so none reads as widening; the 人工地板 lines (SKILL.md :390–:392 after the shift; core-rules :95–:96) are byte-untouched and remain the exclusion set.

  • SKILL.md, after 具名不升级类(立即行动):…:
    • - 四类记账事同属不升级类,恒以无产品可见行为变化为界:去重与卡片合并;台账与记账整理; (120 B)
    • - 纯文档措辞更正(无契约声明改动);门禁内部参数与扫描器盲区修复(加强,非削弱)。 (110 B)
  • core-rules.md twin, after 具名不升级类:…: - 记账事不升级(无产品可见行为变化):去重并卡、台账整理、纯文档措辞、门禁盲区加强。 (119 B; the compressed spelling the 人读摘要 file uses for every twin).

Authority: the maintainer's first sentence above — cited here, ⛔ not inside the skill text (the skill states rules; check:pm-skill-id-lint keeps citations out).

Line budget — every file at its ratchet ceiling, headroom 0, line-neutral

pnpm check:pm-skill-ratchet on af85c612: SKILL.md is 812 lines (ceiling 812; headroom 0) · widest table row is 342 bytes (pin 342) · state-machine.md is 42 lines (ceiling 42) · core-rules.md is 151 lines (ceiling 151). No re-wrap, no ceiling raise, check-skill-line-ratchet.mjs untouched.

file ceiling before → after paid by (deleted line, verbatim, and why it is not a loss)
SKILL.md 812 812 → 812 (+0) row :111 extended in place. (+2) the two Half B lines. (−1) - 机会主义重启条件必须点名触发文件。 (:131) — the rule is stated in references/state-machine.md :18–:19 (Restart-touch: mechanics) and SKILL.md :124 already points there. (−1) - 先过升级门槛:明显的问题直接修,大多数感觉像决定的不是决定。 (:711) — restated by the three lines under it (:712–:713 the two thresholds and 其余归 PM 裁量; :714 具名不升级类(立即行动)); introduced by the rules-only rewrite, not a ruled clause.
references/state-machine.md 42 42 → 42 (+1) the entry-line spec. (0) :37 rewritten in place to fold the 写不出即决定待做 test onto the exit line (「维护者完成该操作后,由项目总监席核验」 compressed to 「维护者完成后由总监席核验」, meaning intact). (−1) - 标签须五仓存在,首次应用时创建。 (:42) — stated in references/lanes/hotcrm.md :46 (「pm 状态机词表五仓统一,幂等创建在 scripts/pm/ensure-pm-labels.sh」) and mechanised by that script (it creates pm:awaiting-maintainer idempotently, :212).
references/core-rules.md 151 151 → 151 (+1) the Half B twin. (0) :36 rewritten in place — the carrier joins the definition; pm:blocking keeps its ⛔ and loses only the WHY (「是反向索引推导的缓存」), which SKILL.md :112 keeps. (−1) - `pm:dispatched` 与摘 `pm:queue` 恒在同一次标签写入里成对落地。 (:30) — an intra-file duplicate of :109 (「认领原子对:一次标签写入完成认领与状态对调…」) and :38 (「转换恒一笔 replace」); SKILL.md :107 and :466 keep the rule, so the twin obligation (SKILL.md :44) is untouched.
references/lanes/director.md 72 72 → 72 untouched (assumption B, below).

Mechanism assumptions (派发词 — tested before acting)

  • A (pinned lines). check-governed-prose pins the SKILL.md region between **ACCEPT 之后的路径分叉 and 本段只适用本循环派发的 dev PR; check-half-states pins RELEASE_RULE_LINE (SKILL.md's 释放是显式动作 line) and the retriage answer line; check-skill-frame-sync pins the four-axis frame; check-clause2-carriers / check-widening-tells pin references/contract-review.md and the claim spelling. None of the deleted or edited lines is in any pinned set — all six gates are green below. Held.
  • B (director.md). :52 「pm:awaiting-maintainer 跨仓标签是待人工动作的唯一机器载体」 was read as the label being the unique carrier of the STATE (against seat-post prose, :55 「标签即状态」), while the new line is the label's machine half specified in state-machine.md, which :56 already points at (「出口条款见 ../state-machine.md」); :54 「台账与出口归本席」 is what the H55 remedy names. No sentence contradicts the line ⇒ left untouched, per the ruling. Noted in Acceptance notes as the one reading a reviewer may want to overturn.
  • C (entry date from what the sweep holds). Falsified — measured above; ruling 2's stated fallback (updated_at) taken, trade stated in the header, the row text and the summary clause.
  • D (line numbers). The card's SKILL.md:110/:126 are :111/:127 on a9550bf8; check-half-states.mjs:2298 is :2302 (the note) / :2307 (the remedy); 具名不升级类 :714 and 人工地板 :391–:393 as cited. Worked from the tree.

Gates (local, on af85c612; the list derived by node scripts/pm/dispatch-gates.mjs on a9550bf8 — 45 families — and re-derived from the real changeset on the final tree: identical 45; --ran reconciliation below)

Every exit captured before any pipe (cmd > log 2>&1; EXIT=$?).

family verdict
node scripts/pm/check-half-states.mjs --self-test (check:pm-half-states) ✓ check-half-states self-test: 3103 cases pass. (baseline on a9550bf8: 3019; +84 H55 cases)
pnpm check:pm-skill-ratchet exit 0 — the four ceiling lines quoted above
pnpm check:pm-skill-id-lint ✓ check-skill-id-lint: 26 file(s) clean (pattern /#[0-9]{3,}/g).
pnpm check:skill-frame-sync / check:skill-frame-freshness 2 copies of the decision frame are structurally isomorphic across 2 files / the frame itself is unchanged
pnpm check:pm-governed-prose 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.
pnpm check:pm-clause2-carriers / check:pm-widening-tells (self-tests) exit 0 / exit 0
pnpm check:nul-bytes + the control-byte grep over the four files no raw ASCII control bytes / empty
pnpm --filter @objectstack/lint run check:doc-formula-expressions first run exit 3 = PREREQUISITE NOT MET (unbuilt @objectstack/formula) — NOT a measurement; rebuilt formula + lint under os-verify-lock.sh (VERDICT command-exit 0 · held the lock 2s) and rerun: exit 0
the other 16 pnpm check:* families (agent-test-spelling, bash32-floor, changeset-gate-self-tests, cli-command-ids, cross-package-test-inputs, doc-authoring, driver-memory-census, entry-guard, parse-guard, partof-closing-keyword, pm-governed-merges, pnpm-filter-targets, ratchet-remedy-authority, refd-timer-probe, watch-hint-literal, pm-half-states) all exit 0
the 22 direct node families (reference-carrier-shape ×2, changeset-no-major ×2, ci-filter-parity, closing-keyword-parity ×2, comment-mask-corpus, declaration-mirrors ×2, scripts-symbol-anchors ×2 — 3094 anchors across 238 scripts resolve, self-test-wired ×2, self-test-workflow-commands ×2, whole-set-label-write ×2, bare-root-worklist --self-test — OK … none stale, none missing, none contradicted, governed-queue-guard --self-test, sweep-closed-cards --self-test, report-test-timings --self-test) all exit 0
pnpm check:pm-dispatch-gates (> 600 s foreground cap; run detached, tail --pid waited) run detached on the same tree (setsid nohup, waited with tail --pid): ✓ dispatch-gates self-test: 1624 cases pass., exit 0. node scripts/pm/dispatch-gates.mjs --ran RAN_FILE on the final tree: 45 derived famil(ies) accounted for — 45 run, 0 NOT-MEASURED
CI-measured only (not runnable here, per the derivation): check-governed-queue-guard.mjs (workflow payload), check-partof-closing-keyword.mjs (env), shard attestation, test completeness, the --format=markdown --provenance sweep run NOT MEASURED locally, by construction; CI

No package touched ⇒ no build closure owed; no changeset (skip-changeset: .claude/** and scripts/pm/** publish nothing — no gate demanded one; check-changeset-no-major exit 0).

Reverse verification (one-time ablation, committed state, restore proven by bytes)

Committed first (af85c612), then mutated under a trap restore EXIT INT TERM with absolute paths: the first statement of h55AwaitingWithoutMaintainerAction was made return null (marker ABLATION-17017-MARKER). Landing proven on disk before reading any result: marker count 0 → 1 on the anchor line, blob f015273c… ≠ HEAD blob 0ec90893…. Expected direction: RED (the positive control and every row-text case), the census/registry/summary cases unaffected — observed exactly that: ✗ check-half-states self-test: 20 of 3103 case(s) failed., the 20 being the six H55 fires: cases, the three thread-state cases, the undated case and the ten H55 row: sentence cases; every neighbour (H9, H11, H25, H54, summary clauses, band registry) stayed green. Restore leg: git checkout HEAD -- ABSOLUTE_PATH (never a bare checkout — the index is the mutation), proven by git diff HEAD --stat empty, git status --porcelain empty, git hash-object = 0ec90893d36c84e19c8721b755252781b8b8b805 = git rev-parse HEAD:scripts/pm/check-half-states.mjs, marker count back to 0; the restored run reads ✓ check-half-states self-test: 3103 cases pass. again. No dist/ is involved (the sweep runs from source), so no dist preflight applies; no permanent test file was left behind.

Acceptance notes

  • The bounded reclassification worklist is a LATER, separate act — named here, ⛔ not filed (ruling 2): the 7 live carriers above, each read per-thread and either given its Maintainer-action: line or moved to needs-user-decision (决定待做) / closed. objectstack dev has no https mode, so the advertised OAuth path for interactive MCP clients cannot be tried against a local dev server #16804 already carries both needs-user-decision and pm:awaiting-maintainer (H25 fires on it today) — first in that worklist. No live card was touched by this PR.
  • director.md :52 reading (assumption B): left untouched on the reading above. If the reviewer reads 「唯一机器载体」 as contradicted by a second machine-read carrier, the in-place edit is …唯一机器载体,其 Maintainer-action: 行即台账行。 — it measures 122 B, 2 over the cap, so it would cost a fold elsewhere in the 72/72 file; not done here.
  • done when required — H55 reads "both parts" literally: a Maintainer-action: value without a done when half fires as half a line (its own sentence). The dash spelling is not the contract (, -, -- all carry it); the KEY is byte-exact.
  • The EVIDENCE placeholder reads 可查证据, not 机器可查证据, in the state-machine line: 6 bytes were needed to fit the 120-byte cap; "evidence a reader can check" is stated in the H55 row text.
  • noted, not filed — 承接者:无: check-half-states.mjs's directiveValues JSDoc named only two keys; widened to three (comment only). noted, not filed — 承接者: the reclassification worklist above: the awaiting label's ensure-pm-labels.sh description (:212) still says "no machine exit" — true, and now incomplete (no mention of the entry line); a description string, no reader.
  • GET /search/issues answers 403 from this container (so did MCP-free dedup rely on the events stream + list endpoint); Maintainer-action had 0 hits on origin/main at dispatch and this PR is its first spelling.

维护者速读(草稿)

改了什么

pm:awaiting-maintainer(等您亲手做一件事的状态)加了一条必填的机器可读行:Maintainer-action: 要做的那件事 — done when 怎么验证做完了。写不出这一行的卡,说明它等的不是您的手而是您的裁决,应当放进决策箱(needs-user-decision)。巡查脚本新增 H55 报"进了这个状态却没写这行"的卡(只报告不改标签);今天之前已在状态里的卡只汇总成一行计数,不逐张报红。另外,四类纯记账事(去重合卡、台账整理、纯文档措辞更正、门禁内部参数与盲区加强)明确列为 PM 当场自决、不上报您。

为什么改

您 09-09 的两句话:5986 那种任务不该让人决策、该开技能卡纠正;以及"这不应该是决策卡吗?哪个流程出了问题?"。溯源结果是:这个状态只有定义没有载体,谁都能挂、没人能证伪,H8 只查有没有转状态、不查转对没有,巡查只看形状和时间不看含义。卡上当天量到 55 张里约 49 张挂错;派发时板上已剩 7 张(上午有一轮改判),缺陷本身没变。

风险与代价(含回滚)

三个技能文件都在行数上限,每加一行删一行(删的都是别处已有的重复表述,PR 正文逐行列出)。H55 判"新旧"用的是卡片 updated_at 而不是打标签时刻(不做逐卡 timeline 请求),代价是:老卡在 09-10 之后被碰过就会被当新卡报一次,补一行即消;绝不会漏报新卡。回滚 = revert 本 PR,无数据、无标签、无 workflow 变化。

席位意见

(留空)

你要做的

读完后人工合并本 PR(受管面,席位不合)。合并后如同意,由席位另开一张有界的改判工作单处理现存 7 张卡;本 PR 不动任何在板卡片。


Generated by Claude Code

…line, read by H55; four bookkeeping classes join 具名不升级类

Half A — the carrier. Every other parked state carried a mandatory
machine-readable line (`Blocked-by:`, `Restart-when:`); the awaiting state
carried nothing, so a card waiting for a JUDGEMENT was indistinguishable
from one waiting for a HAND. `references/state-machine.md` now specifies a
line-anchored, case-sensitive `Maintainer-action: <action a seat cannot
perform> — done when <checkable evidence>` in either channel, and states
the classification test: 写不出即决定待做. The SKILL.md state-model row and
its core-rules twin point at it. `check-half-states.mjs` gains H55, a
report-only ENTRY predicate (band `state`) with a gated thread read on the
shared comment cache; legacy entries — last touched before the pinned
`MAINTAINER_ACTION_LINE_SINCE` — render as one summary census line, never as
rows, so the landing day is not red on the healthy case. Not a machine
exit: the H11 note is reconciled to say the state now has an entry
predicate and still no exit; H25's deferral note points at H55.

Half B — the floor. 具名不升级类 gains the four bookkeeping classes, each
bounded by 无产品可见行为变化, in SKILL.md and its core-rules twin; the
人工地板 lines are untouched.

Line-neutral on all three governed files, each at its ratchet ceiling:
SKILL.md 812/812 (row extended in place; −2 restated lines, +2),
state-machine.md 42/42 (−1 line stated in lanes/hotcrm.md, +1),
core-rules.md 151/151 (−1 intra-file duplicate, +1; one line rewritten in
place). Self-test 3019 → 3103 cases.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
@github-actions github-actions Bot added the size/l label Sep 9, 2026
@os-justin os-justin added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 9, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

维护者速读

改了什么 — 给「等您亲手做一件事」的状态(pm:awaiting-maintainer)加一条必填的机器可读行:Maintainer-action: 要做的那件事 — done when 怎么验证做完了。写不出这一行的卡,等的是您的裁决而不是您的手,应进决策箱。巡查脚本新增 H55,只报告不改标签:今天之前已在该状态的卡只汇总成一行计数(现存 7 张),不逐张报红;之后进入的卡没写这行才报。另外,四类纯记账事(去重合卡、台账整理、纯文档措辞更正、门禁内部参数与盲区加强)明确列为 PM 当场自决、不上报您,以「无产品可见行为变化」为界,人工地板清单一字未动。

为什么改 — 您 09-09 的两句话:「5986 这种任务不影响我们的产品质量,不应该让人类决策,项目经理自己当场决定就可以,而且这个应该开技能卡纠正」和「这个不应该是决策卡吗?哪个流程出了问题?」。溯源结果:这个状态只有定义没有载体,谁都能挂、没人能证伪;H8 只查有没有转状态、不查转对没有;巡查只看形状和时间不看含义。卡上当天量到 55 张里约 49 张挂错;派发时板上已剩 7 张(上午有一轮改判),缺陷本身没变。

风险与代价(含回滚) — 三个技能文件都在行数上限,每加一行删一行,删的四行在别处都已成文(本席逐条核对;其中 SKILL.md「先过升级门槛:明显的问题直接修,大多数感觉像决定的不是决定」这一行是判断而非纯重复,请您过目)。H55 判新旧用卡片 updated_at 而不是打标签时刻,代价是老卡在 09-10 之后被碰过会被报一次,补一行即消,绝不漏报新卡。纯内部 PM 工具与技能文本,不发布、不进产品、无 changeset。回滚 = revert 本 PR,无数据、无标签、无 workflow 变化。

席位意见 — 本席以契约复审档复核通过:七条裁决逐条对分支核实,自测 3103 例全过,CI 31 项全绿(含线上巡查实跑),合并无冲突。建议合并;合并后本席另开一张有界的改判工作单处理现存 7 张卡。

你要做的 — 受管面走人工合并:看一眼新增那行的写法与被删的那四行,认可即批准并合并本 PR。是否合并?


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

Projects

None yet

2 participants