Skip to content

Shift-close releases the seat; linger mode fences the briefing's named tails (pm-dispatch protocol) - #12682

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-12678-shift-close-release
Aug 27, 2026
Merged

Shift-close releases the seat; linger mode fences the briefing's named tails (pm-dispatch protocol)#12682
os-zhuang merged 1 commit into
mainfrom
claude/issue-12678-shift-close-release

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12678

Governed protocol change (.claude/skills/pm-dispatch/**) — DRAFT for human merge, per the governed-surface rulings.

Ruling (verbatim, untranslated)

Maintainer proposal-question (2026-08-27, live PM chat):

「是否建议项目经理下班的日常流程应该是立刻进行交接,并继续处理完手上的任务到合并,这样可以方便下一任项目经理尽快接手。」

The seat answered with the three-part design on the card; the maintainer's execution ruling on that exact shape, verbatim: 「落协议」. The three parts are the ruled scope — not a menu.

The three changes

1. Close-out briefing = seat release — the SKILL.md 开轮互斥读法 clause is rewritten. The recency window is scoped to un-closed activity only (近期窗口只管未收班活动; the recusal condition now reads 未收班活动任一未满一个轮次 ⇒ 自退). New release rule: 收班简报 = 前任「不再写」的显式声明,是释放标记不是锁 — a briefing that is the latest event seats the successor immediately; a lagging title is a repairable half-state fixed on the way in (⛔ 不是阻塞); the briefing's named tails are fenced. Close-sequence ordering is defined in the seat-post-protocol.md 收班 bullet (收班序列): seat-post body/title refresh first, briefing comment as the final stroke; the successor's release condition is the briefing's presence.

2. Linger mode (离任留守) — new bullet in seat-post-protocol.md, carried as the extension of the 2026-08-25 清标即落地 ruling (谁评审谁落地; provenance lives in contract-review.md and is pointed at, not copied). Post-close write surface = exactly the briefing-named items (accepted PRs awaiting queue, review-chain carriers mid-landing); ⛔ no queue reads, no new dispatches, no un-named cards; residual timers only touch the named set; one tail-clear note on the seat post when the last tail merges. The successor seats immediately and fences the named set declaratively (same collision shape as the hot-file serial queue). Title vocabulary NOT extended: a closed seat shows the vacant state word; the linger register (who lingers, which tails) is one line in the 说明 section. The exit checklist gains the linger branch in steps ② and ⑥ and marks the briefing/audit comment as the final stroke in ⑤.

3. Reading-③ cross-seat filter + explicit-summon override — reading ③ counts only claims claiming this seat's lane dispatch (只计认领本席车道派发的); review-chain / Director-seat strokes on lane cards are cross-seat work, never occupation (claims carry session ID and seat identity). The maintainer's explicit summon is the arbiter: briefing present ⇒ seat directly; no briefing (predecessor possibly dead mid-round) ⇒ the conservative path stays — ask the maintainer to confirm termination, the confirmation seats.

Non-goals held (binding on the card)

  • 宁少跑 unchanged for the un-closed case: the four readings and the one-round window stay intact against live or silently-dead predecessors.
  • No new labels; no new seat-post title state word (the state-word table is untouched).
  • check-half-states.mjs untouched; the dead-claim reclaim path and the over-24h liveness rules untouched (the liveness bullet was not edited).
  • references/dispatch-runbook.md untouched (274/274): the four-readings detail rows do NOT live there — its mutex content is the tail-page reading recipe whose own text says 读数定义在主文件, so the release semantics belong to the SKILL.md clause.

Zero-headroom ratchet accounting (net 0 per file)

pnpm check:pm-skill-ratchet — exit 0 (captured before any pipe), verdict lines:

check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 1005 lines (ceiling 1005; headroom 0).
check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md: widest table row is 765 bytes (pin 765; headroom 0).
check-skill-line-ratchet: .claude/skills/pm-dispatch/references/seat-post-protocol.md is 105 lines (ceiling 105; headroom 0).
check-skill-line-ratchet: .claude/skills/pm-dispatch/references/seat-post-protocol.md: widest table row is 0 bytes (pin 0; headroom 0).
check-skill-line-ratchet: .claude/skills/pm-dispatch/references/dispatch-runbook.md is 274 lines (ceiling 274; headroom 0).

Growth: the SKILL.md Routine/mutex paragraph grew 14 → 16 lines (+2); the seat-post 收班/离任留守/退场 block grew 20 → 21 lines (+1) plus the ruled content inside it. Every added line is paid by a same-file cut.

Cut ledger — SKILL.md (each cut names its surviving home):

  1. Routine principle ① detail (repo-sources credential rule, no-GitHub-connector-in-Routines-UI 2026-08-23 measurement, create_trigger silent-zero-output trap) cut to the bare principle — surviving home: seat-post-protocol.md 座位 Routine 创建细则, which carries every clause verbatim including the date and failure mode.
  2. Principle ② wording 创建后…一轮 trimmed to 手动 fire 烟测 — surviving home: the same 创建细则 section (先手动 fire 一轮烟测, verbatim).
  3. Fourth-reading incident condensed (一趟合并五个 PR dropped; 叠加过期座位贴后 dropped) — the distilled failure mode survives in place: 不用 pm:dispatched 的会话对前三读隐形,与空席同形, with the 16-minute measurement kept.
  4. The rate-limit bullet under 平台读数纪律 deleted (2 lines) — surviving home: platform-readings.md API 配额 rows: 开轮先读配额 via the zero-quota rate-limit endpoint; 重试对齐整点(REST core 整点重置)优于指数退避,⛔ 绝不忙轮询; 公开仓零配额读法两档 with 渲染层 WebFetch 仍在. The section header already routes every platform operation to that table at the moment of use.
  5. The subagent same-ID sentence condensed (读作本会话在飞 folded into 不自退; the trailing 见「认领」 pointer folded into 甄别靠分支) — meaning survives in place.

Cut ledger — seat-post-protocol.md:

  1. Cloud-card evidence prose in the 收班 bullet (等它归零曾挂住座位数小时 and the dev-vs-cloud elaboration) condensed to 云卡与队列尾巴是持久、GitHub 锚定的进程 — the failure mode distilled in place.
  2. The create_trigger not-an-escape-hatch clause deleted from the 收班 bullet — surviving home: same file, 座位 Routine 创建细则 (fired sessions get no GitHub tools; silent zero output).
  3. 已入队 PR 的看护同样点名接手座位 absorbed by the generalized per-item hot-handoff sentence (收单注记 + 点名接手看护者).
  4. 热移交把评审交给下任座位,⛔ 不是跳过评审 condensed to 看护只守落地,评审判断不可外包 — same rule, in place.
  5. The poke-trigger parenthetical condensed (绑定会话 ID dropped; the runbook pointer kept) — surviving home: dispatch-runbook.md carries the delivery detail.
  6. 读侧边界 rationale compressed in place (而正文有界 dropped; both platform-stamped timestamps and the main-file provenance kept).
  7. Exit-checklist ⑥ʹ trailing rationale 那是一条它做不到的待办 folded into the ⛔ clause.

Re-wrap declaration: line re-flow is confined to the rewritten paragraph and bullets; sentences surviving verbatim inside them (Routine principle ③; exit-checklist steps ①③⑦) re-wrapped only because neighboring sentence lengths changed. No untouched passage was re-wrapped to buy lines.

Gates (exits captured before any pipe; run at commit 2119da4, the PR head, after the final commit)

Derived union: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (exit 0) — derivation stderr names this checkout and commit 2119da4; 9 matched families:

  • pnpm check:pm-skill-ratchet — exit 0; verdict lines quoted above (57 green lines, all files).
  • pnpm check:pm-skill-id-lint — exit 0; verdict: "check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g)."
  • pnpm check:skill-frame-sync — exit 0; verdict: "check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files; binding sentence present in all 4; 4 count mention(s) agree; 42 markdown files scanned for undeclared copies."
  • pnpm check:skill-frame-freshness — exit 0; verdict: "check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)." (dispatch-named; not in the matched list)
  • pnpm check:pm-governed-prose — exit 0; verdict: "check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others."
  • pnpm check:pm-governed-merges — exit 0; verdict: "check-governed-merges --self-test: 206 assertions … live: the real generator declared 9 output(s) and certified this tree"
  • pnpm check:agent-test-spelling — exit 0; verdict: "check-agent-test-spelling: 0 violations — 387 file(s) · 4168 bare launcher tokens · 1190 launcher-rooted run(s) · 9 separator(s) JUDGED · 5 vitest-backed script name(s) derived from 80 manifest(s)"
  • pnpm check:doc-authoring — exit 0; verdict: "doc authoring guard: 535 refusal-message string(s) across 661 spec sources clean — no internal issue-id references."
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions — first run printed PREREQUISITE NOT MET (compiled deps absent — not a measurement); after building @objectstack/formula and @objectstack/lint, exit 0; verdicts: "check:doc-formula-expressions (spec TSDoc): 9 example(s) judged clean across 1052 packages/spec/src files" and "(field-level When predicates): 14 predicate(s) on a statically determinable field layer judged clean; 6 skipped as undeterminable."
  • node scripts/pm/check-governed-queue-guard.mjs — CI-only in this environment: NOT MEASURED locally; runs on the PR.
  • pnpm check:nul-bytes (any-edit discipline; outside the derived list) — exit 0; verdict: "check-nul-bytes: OK (scanned 7030 text file(s) … no raw ASCII control bytes)."

No changeset: the diff is entirely .claude/skills/pm-dispatch/** — publishes nothing; the skip-changeset label is applied to this PR as a step (whole-set label write with compare-style read-back, recorded in the card report).

Acceptance replay (reasoning over the card's engine transcript)

The 2026-08-27 04:19Z case replayed under the new text: the summoned engine PM runs the four readings. Reading ① finds the predecessor's shift-close briefing posted 4 minutes earlier and it is the latest event ⇒ release marker, not a lock — the recency window no longer applies to it (只管未收班活动). Reading ③ finds fresh non-self claims on two lane cards, but they are the skills seat's review-chain strokes claiming no engine-lane dispatch — cross-seat under the new filter, not occupation. Result: the session seats immediately, repairs the lagging 🟢 title (the recorded half-state) on the way in, and fences the briefing's named tails as the linger set. No 40-50 minute wait, no question bounced to the maintainer. Counterfactual guard: a predecessor with NO briefing (dead mid-round) still presents un-closed activity inside the window ⇒ the conservative path verbatim — recuse; on an explicit summon, ask the maintainer to confirm termination, and the confirmation seats.


Generated by Claude Code

…named tails
Executes the 2026-08-27 maintainer ruling (「落协议」 on the three-part
shift-close design; proposal quote carried in the protocol text) fixing the
round-open mutex's two false positives observed when a summoned engine-lane
PM self-recused against a predecessor that had already closed out.
Three ruled changes, in the clauses where the four readings live (SKILL.md)
and where the close sequence lives (seat-post-protocol.md):
1. Close-out briefing = seat release. The recency window now applies only to
un-closed activity; a briefing that is the latest event releases the seat
immediately. Close sequence defined: seat-post body/title refresh first,
briefing comment as the final stroke; the successor's release condition
is the briefing's presence, and a lagging title is a repairable
half-state fixed on seating, never a blocker.
2. Linger mode (离任留守), the default post-close custody: the outgoing PM
may keep driving the items named in its briefing to merge — no queue
reads, no new dispatches, no un-named cards; residual timers only touch
the named set; one tail-clear note when the last tail merges. The
successor seats immediately and fences the named set declaratively (same
shape as the hot-file serial queue). Title vocabulary is not extended: a
closed seat shows vacant, the linger register is one line in the
description section.
3. Reading-3 cross-seat filter + explicit-summon override: only claims
claiming this seat's lane dispatch count as occupation (claims carry
session ID and seat identity); with a briefing present a summoned session
seats directly, with none the conservative confirm-termination path
stays.
Non-goals held: 宁少跑 unchanged for the un-closed case; no new labels or
title state words; check-half-states.mjs and the dead-claim/liveness rules
untouched. Both files stay at their zero-headroom ratchet ceilings
(1005/1005, 105/105); every added line is paid by same-file cuts whose
surviving homes are listed in the PR body.
Claude-Session: https://claude.ai/code/session_01MnijPVVDakqK2J335JoJtq
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 27, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude