Shift-review deliverable from the domain:spec-surface seat (#6298), tenure 2026-08-07 13:45Z–16:40Z, session session_01JTSZAjgtL3oR6YcpNDhW3T. Filed per the 交接收尾清单 item 7 ("换班复盘是交接的固定产物,不是可选项"). Filed unassigned and unlabeled for the triage seat.
Three of the four findings are fleet-wide (they hit any PM seat, not just this lane), so they belong in the SKILL rather than only in a seat post. The fourth is lane-local and is already recorded in #6298.
Duplicate search run before filing (pm-dispatch send_later idempotent timer over open issues) — no existing card.
1. ⚠️ Deleted send_later timers still fire, with stale text — measured TWICE
Observed: two timers deleted via delete_trigger (confirmed deleted trigger …) nonetheless delivered their payload afterwards. Both carried text that was two rounds behind reality.
Why it is dangerous, not merely noisy — one of the two instructed, verbatim:
"#5783 … THIS IS THE VERDICT ROUND: if still no branch and no probe reply … judge unreliable and hand off … dispatch a FRESH os-dev … worktree objectstack-issue-5783 already exists"
By the time it arrived, #5783 had delivered PR #6389, which was already reviewed and accepted. Executing that text would have dispatched a duplicate agent into a live, completed worktree — the exact collision class the claim protocol exists to prevent, arriving through the automation rather than through a racing PM.
What saved it: every timer this seat armed opened with "idempotent — re-read state first", and the re-read was actually performed each time.
Proposed SKILL change — promote that from habit to rule, in the 座位 Routine / send_later guidance:
每一枪定点文本必须以「幂等 —— 动手前先重读状态」开头,并且不得包含未经重读即可执行的祈使句。 已删除的定时器仍会投递(实测两次),投递时其文本可能已落后现实数轮;把「重读」写进文本是唯一能让过期指令失效的机制。定点文本描述判据(「若 X 则 Y」),⛔ 不描述结论(「现在去做 Y」)。
This composes with the existing rule that a blocked action's full pending state goes into the timer text — that rule makes the text complete, this one makes it safe when stale.
2. ⚠️ GitHub's sanitizer swallows <…> even inside backticks — and it ate a load-bearing marker
Operational note 12 covers sanitizer truncation (a bare <x> swallowing the rest of a body) and correctly warns against misdiagnosing reader-side truncation as issue-side. It does not cover the narrower failure this shift hit: short <…> spans being deleted in place while the rest of the body survives intact.
Measured, on the seat post's handover ledger (write, then read back):
| written |
stored |
`<!-- os-dev-report -->` |
(empty) |
expected <N> to be 19 |
expected to be 19 |
git log -- `<path>` |
git log -- |
Backticks did not protect them. The first one mattered: that marker was the entire collection path for an in-flight dev's report across a seat handover — the ledger instructed the incoming PM to sweep for a marker that had been deleted from the ledger itself. Caught only by write-then-read-back.
Proposed SKILL change — extend Operational note 12 with the write-side case:
正文里凡要保留字面尖括号,一律写 HTML 实体 &lt; / &gt;,反引号不提供保护。 实测:`<!-- marker -->`、<N>、<path> 在写入后全部被就地删除,正文其余部分完好 —— 与 note 12 的「截断」不同形,不会被那条的判据抓到。含 HTML 注释标记(如 os-dev 报告标记)、占位符、泛型参数的正文,写后回读必须逐个确认这些片段仍在。
3. Probe threshold ≠ death threshold — the SKILL currently supplies only the first
Step 6 gives 45 minutes with no remote output as the probe threshold, and the stall rules give "third stall ⇒ unreliable ⇒ hand off". Neither answers the question a PM actually faces: how long is too long before I conclude a dev is dead?
Measured this shift — four devs on comparable text-surface cards, end to end:
At the 92-minute mark I had written that #5783 was heading for an unreliable verdict. It was inside the normal band and pushed its branch minutes later. The 45-minute probe threshold had fired correctly (probe sent); the error was reading "probe threshold passed twice" as evidence of death.
Proposed SKILL change — separate the two thresholds explicitly in step 6:
45 分钟是发探针的门槛,不是判死的门槛。 判死要对照本车道实测的完工耗时基线(本席四单实测 93–110 分钟,同类文本面卡片)。没有基线时,先建立基线再判 —— 在基线之内的沉默不是证据。判死的正当依据只有三类:探针回包表明已死、宿主明确回报 stopped、或超过基线且连续静默。⛔ 不得把「探针门槛过了两次」当作判死依据 —— 那只说明它还在跑。
This is the same failure mode Operational note 11 warns about (inferring maintainer abort from symptoms) applied to duration instead of intent: the symptom of "working normally, slowly" and "dead" are identical until you know the baseline.
4. Lane-local, recorded in #6298 rather than here
JSDoc/TSDoc changes do NOT regenerate content/docs/references/**; only Zod .describe() strings do. Reference pages render from packages/spec/json-schema/, derived by build-schemas.ts from .describe() only. Measured independently by three devs (PRs #6364, #6368, #6375 — all zero regen) with the counter-example bounding it (#6389 removed a ledger data row, and 11 pages did regenerate). The seat post's 产物随源走 clause was too broad and has been narrowed in place. Noting it here only so the next person auditing that clause knows the evidence exists; the authoritative copy is #6298.
Filed by the outgoing PM as a handover artifact; no claim is implied and the seat is ⏳ vacant.
Shift-review deliverable from the
domain:spec-surfaceseat (#6298), tenure 2026-08-07 13:45Z–16:40Z, sessionsession_01JTSZAjgtL3oR6YcpNDhW3T. Filed per the 交接收尾清单 item 7 ("换班复盘是交接的固定产物,不是可选项"). Filed unassigned and unlabeled for the triage seat.Three of the four findings are fleet-wide (they hit any PM seat, not just this lane), so they belong in the SKILL rather than only in a seat post. The fourth is lane-local and is already recorded in #6298.
Duplicate search run before filing (
pm-dispatch send_later idempotent timerover open issues) — no existing card.1.⚠️ Deleted
send_latertimers still fire, with stale text — measured TWICEObserved: two timers deleted via
delete_trigger(confirmeddeleted trigger …) nonetheless delivered their payload afterwards. Both carried text that was two rounds behind reality.Why it is dangerous, not merely noisy — one of the two instructed, verbatim:
By the time it arrived, #5783 had delivered PR #6389, which was already reviewed and accepted. Executing that text would have dispatched a duplicate agent into a live, completed worktree — the exact collision class the claim protocol exists to prevent, arriving through the automation rather than through a racing PM.
What saved it: every timer this seat armed opened with "idempotent — re-read state first", and the re-read was actually performed each time.
Proposed SKILL change — promote that from habit to rule, in the 座位 Routine /
send_laterguidance:This composes with the existing rule that a blocked action's full pending state goes into the timer text — that rule makes the text complete, this one makes it safe when stale.
2.⚠️ GitHub's sanitizer swallows
<…>even inside backticks — and it ate a load-bearing markerOperational note 12 covers sanitizer truncation (a bare
<x>swallowing the rest of a body) and correctly warns against misdiagnosing reader-side truncation as issue-side. It does not cover the narrower failure this shift hit: short<…>spans being deleted in place while the rest of the body survives intact.Measured, on the seat post's handover ledger (write, then read back):
`<!-- os-dev-report -->`expected <N> to be 19expected to be 19git log -- `<path>`git log --Backticks did not protect them. The first one mattered: that marker was the entire collection path for an in-flight dev's report across a seat handover — the ledger instructed the incoming PM to sweep for a marker that had been deleted from the ledger itself. Caught only by write-then-read-back.
Proposed SKILL change — extend Operational note 12 with the write-side case:
3. Probe threshold ≠ death threshold — the SKILL currently supplies only the first
Step 6 gives 45 minutes with no remote output as the probe threshold, and the stall rules give "third stall ⇒ unreliable ⇒ hand off". Neither answers the question a PM actually faces: how long is too long before I conclude a dev is dead?
Measured this shift — four devs on comparable text-surface cards, end to end:
At the 92-minute mark I had written that #5783 was heading for an unreliable verdict. It was inside the normal band and pushed its branch minutes later. The 45-minute probe threshold had fired correctly (probe sent); the error was reading "probe threshold passed twice" as evidence of death.
Proposed SKILL change — separate the two thresholds explicitly in step 6:
This is the same failure mode Operational note 11 warns about (inferring maintainer abort from symptoms) applied to duration instead of intent: the symptom of "working normally, slowly" and "dead" are identical until you know the baseline.
4. Lane-local, recorded in #6298 rather than here
JSDoc/TSDoc changes do NOT regenerate
content/docs/references/**; only Zod.describe()strings do. Reference pages render frompackages/spec/json-schema/, derived bybuild-schemas.tsfrom.describe()only. Measured independently by three devs (PRs #6364, #6368, #6375 — all zero regen) with the counter-example bounding it (#6389 removed a ledger data row, and 11 pages did regenerate). The seat post's 产物随源走 clause was too broad and has been narrowed in place. Noting it here only so the next person auditing that clause knows the evidence exists; the authoritative copy is #6298.Filed by the outgoing PM as a handover artifact; no claim is implied and the seat is
⏳ vacant.