docs(pm-dispatch): release is an explicit act — clear the assignee and post a Release: line whenever a card leaves a session's hands (#15846) - #15848
Conversation
…d post a `Release:` line whenever a card leaves a session's hands (#15846) Ownership had an explicit entry (assign + `Claim:`) and no explicit exit. Under the maintainer's 2026-09-05 design ruling (R3), whoever moves a card out of a session's ownership — re-route, hand-back on a falsified premise, an abandoned flight with no takeover, a cross-lane hand-off — clears the assignee and posts a line beginning `Release:` (session, reason, destination) in the same write; the next owner claims afresh. The two definitional readings follow: a `pm:queue` card never carries an assignee, a `pm:dispatched` card always does. Line-neutral on both files, both at headroom 0 (SKILL.md 811/811, table pin 342; state-machine.md 42/42): every new fact is folded into an existing line or takes the place of a line whose content survives in its neighbour. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
|
ACCEPT — contract-tier in-seat review of PR #15848, head Implemented-by: Verified in a detached compare worktree at the PR head, three-dot against Seat gate runs on this head in the compare worktree: skill-line-ratchet exit 0 (both files at headroom 0, as ruled), skill-id-lint 24 files clean, half-states self-test 2267 (no H-row prose pin fired), governed exit 3. The dev's evidence beyond that: 16 derived families all exit 0 and reconciled 16 of 16, frame-sync green (two declared copies), the formula-expressions gate green after building its prerequisites (its one-build-short refusal filed as #15850 for devx), whole-repo lint through the lock, the negative control (+1 line on each file reds the ratchet, restore proven by blob hash), widest line this PR writes 119 bytes; CI on Landing regime: governed surface ⇒ this PR stays a draft; reviewers Generated by Claude Code |
|
Tally correction to the ACCEPT above (skills seat, 2026-09-05T11:2xZ): the seat's REST read of the check runs on Generated by Claude Code |
Fixes #15846
What
Ownership had an explicit entry (assign +
Claim:) and no explicit exit. Under the maintainer's 2026-09-05 design ruling (R3, recorded on the ownership-contradiction card by the skills seat: the assignee field stays a presence bit under one shared identity — 「暂时不区分」 — and a presence bit is only truthful if its exit is written down), release is an explicit act: whoever moves a card out of a session's ownership — re-route, hand-back onpremise_still_valid: false, an abandoned flight with no takeover, a cross-lane hand-off — clears the assignee and posts a line beginningRelease:(session ID, which of the four reasons, destination = the new label state or lane) in the same write; the next owner claims afresh. Two definitional readings follow: apm:queuecard never carries an assignee; apm:dispatchedcard always does (what H1 and H24 read).Line-neutral on both files, both at headroom 0. Every new fact is folded into an existing line or takes the place of a line whose content survives in its neighbour; no ceiling moves and the ratchet script is untouched.
.claude/skills/pm-dispatch/SKILL.md— 811 → 811 lines, widest table row 342 → 342 bytesState-model table (状态模型):
open + 队列标签 + 无 assigneerow, 85 → 128 bytes: adds 「pm:queue卡恒无 assignee,有即半态」.assignee 已设row, 63 → 216 bytes: adds 「离手恒走释放 —— 四因 = 改路由、前提证伪、弃飞无接管、跨车道移交,去向 = 新标签态或车道;⛔ 不静默摘 assignee」.pm:dispatchedrow, 106 → 122 bytes: adds 「恒带 assignee」.认领 family (beside 「assignee 字段归 PM」, which is unchanged):
Release:行(会话/因/去向);下一任重新认领。」pm:dispatched与摘pm:queue放进同一次标签写入。」 (119 bytes). Nothing dropped.Release:行载因)」. Reclamation is the abandoned-flight reason of this same rule; left as it was, the file would spell the same exit two ways..claude/skills/pm-dispatch/references/state-machine.md— 42 → 42 linesRelease:(会话/因/去向)与清 assignee 同笔;下一任重新认领。」Byte widths (
LC_ALL=C awk, bytes)domain:enginerow, pre-existing, unchanged). Line 810 at 172 bytes sits inside the claim template's code fence (pre-existing, fence-exempt). No line this PR writes exceeds 120 bytes; the widest new line is 119.Where the four reasons and the destination live — the dev's call inside the ruling
The 120-byte cap on a 认领 line cannot hold the act, the four reasons and the three fields at once; the
assignee 已设row has ~240 bytes of room under the 342-byte pin. So the act and the fresh claim sit in the 认领 line and in state-machine.md (the 行契约: 行首Release:with its three fields, same write as the clear), while the four reasons, the destination definition and the ⛔ on silent clearing sit in the assignee row of the state model, and the two definitional readings sit in thepm:queue/pm:dispatchedrows they define.Four-axis note. 实际业务需求: measured, not speculative — H1/H24 report residue as live half-states and a seat's list view shows taken cards that are free; all four exits already exist in the protocol (改路由 in the
pm:retriagerow,premise_still_valid: falsein 收集 / 报告契约, 死认领回收, 跨车道 接手). 项目长远合理性: the exit is written where the entry is written — the state model and the 认领 section — not as a patrol heuristic. 防 AI 犯错: the definitional readings turn the field into a checkable invariant, and 「⛔ 不静默摘 assignee」 forbids the tolerant path. 创业阶段不扩散: no new label, field, comment marker or gate row; the patrol row for aRelease:newer than the lastClaim:stays the declared follow-up.Not changed
The claim's first-line spelling
Claim:(ruled 2026-08-11);CLAIM_COMMENT_MARKER; the H1/H24 code inscripts/pm/check-half-states.mjs(its prose is a follow-up once this lands); the two declared frame-block copies; the ratchet script's CEILINGS and pins.Verification — all at
ec0a7f8d8c, the PR headFamily derived by
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the two files (16 commands: 9 by path, 7 whole-tree), cross-checked by the no-path derivation from the merge-base (same 16), every command run with the exit code captured before any pipe, then reconciled:✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 16 run, 0 NOT-MEASURED.✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md: widest table row is 342 bytes (pin 342; headroom 0).✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 811 lines (ceiling 811; headroom 0).✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/state-machine.md is 42 lines (ceiling 42; headroom 0).(widest table row 0, pin 0)✓ check-skill-line-ratchet self-test: 155 cases pass.✓ check-skill-id-lint: 24 file(s) clean (pattern /#[0-9]{3,}/g).(+ self-test 14 cases)✓ check-skill-frame-sync: 2 copies of the decision frame are structurally isomorphic across 2 files✓ check-half-states self-test: 2267 cases pass.— no H-row prose pin fired on the edited sentences.✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.;check-governed-merges --self-test: 274 assertions;check-governed-queue-guard self-test: 144 cases pass;check-closing-keyword-parity --self-test: 24 assertions;comment-mask corpus sweep: 5998 files, 0 disagree;check-agent-test-spelling: 0 violations;doc authoring guard: 46 published skill files clean;check-nul-bytes --self-test: 75 assertions;check-refd-timer-probe self-test: 11 cases pass;check-watch-hint-literal: 61 declaration(s) across 4 rostered name(s);check:driver-memory-censusexit 0.check:doc-formula-expressions: first runPREREQUISITE NOT MET(exit 3:@objectstack/formula, then@objectstack/lint, not built — NOT MEASURED, not a finding); afterturbo run build --filter=@objectstack/lintthrough the lock:✓ check:doc-formula-expressions self-test: 58 cases passedand✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 428 files / 1370 TS blocks judged clean by @objectstack/formula.pnpm lint(eslint . --no-inline-config) throughscripts/pm/os-verify-lock.sh(slotissue-15846):os-verify-lock: VERDICT command-exit 0 · held the lock 67s (1m07s) · waited 65s (1m05s).grep -naPover the C0/DEL range): no hits.Negative control on the ratchet, run from the committed state: one line appended to each file →
✗ … SKILL.md is 812 lines; the ratchet ceiling is 811and✗ … state-machine.md is 43 lines; the ratchet ceiling is 42(exit 1); restored withgit checkout HEAD -- …, proven bygit hash-objectequal to the HEAD blob on both paths (a32af80219…,b3b537e59a…) andgit diff HEADempty.check-governed-merges --teston the two paths: exit 3 (.claude/**, governed) ⇒ draft PR, in-seat contract-tier review, human merge,skip-changeset(no package publishes anything from this diff).Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
Generated by Claude Code