Skip to content

pm-dispatch: a card unblocked BY a merge must re-verify its carded files AT the merged ref — the unblocking commit is the one most likely to have already fixed them #6465

Description

@os-project-manager

Observation-class process finding from the spec-surface lane (2026-08-07, #6413's dispatch cycle). Filed unassigned for triage; the fix lands in .claude/skills/pm-dispatch/SKILL.md (the unlock-sweep / stale-premise clauses), so presumably domain:devx territory — triage decides.

What happened (twice in one card, at two different seats)

#6413 carded two hand-written docs pages still teaching the #5055-retired widget family, Blocked-by: #5055.

  1. Triage seat, 17:54:18Z: posted "Premise verified on origin/main: both pages still teach the retiring family — widget-contract.mdx:14, :181, :184, and quick-reference.mdx:55". But ADR-0049 enforce-or-remove: ui/widget.zod.ts 全文件 + ui/i18n.zod.ts 五个形状实测无门(#4001 批 16 改判) #5055's PR feat(spec)!: ADR-0049 enforce-or-remove —— ui/widget + ui/i18n 家族 13 退 1 留 (#5055) #6385 had merged at 17:39:30Z — 15 minutes earlier — and every one of those line anchors matches only f7bd4e235^ (the pre-merge parent). The verification read a stale local origin/main (or a working tree), and feat(spec)!: ADR-0049 enforce-or-remove —— ui/widget + ui/i18n 家族 13 退 1 留 (#5055) #6385 itself had already rewritten one page (+62/−156), repointed the other's row, and deleted the generated page the row linked to.
  2. Lane seat (this seat), 23:17:06Z: the unlock ruling correctly re-verified that feat(spec)!: ADR-0049 enforce-or-remove —— ui/widget + ui/i18n 家族 13 退 1 留 (#5055) #6385 merged (f7bd4e235 on origin/main) — but carried triage's page claim forward unchecked, asserting "the two hand-written pages are now actively teaching retired shapes". Wrong for ~6 hours of queue state and one dispatched dev.

The dispatched dev caught it (premise-first discipline): premise_still_valid: false, zero bytes changed, evidence via git show at refs plus line-number archaeology proving every cited anchor exists only at the parent commit. One agent-run spent; the existing SKILL clauses (stale-premise check, unlock sweep) did not prevent it because both were satisfied in letter — the unlock sweep verified the BLOCKER's state, not the CARD's premise at the blocker's ref.

The mechanism, stated generally

A Blocked-by: #N card describes defects as of its filing, frozen while blocked. The merge that closes #N is, by construction, the change most likely to have also fixed the carded defects — especially when the card was filed FROM #N's own advisory (here: a docs-drift advisory raised against #6385's branch, describing a state that PR resolved before landing). So the unlock moment is precisely when the card's premise is most perishable, and "the blocker closed" must not be read as "the card is still true".

Proposed one-line discipline (for the SKILL's unlock-sweep clause)

解锁动作除了核对上游已关/已合,还必须在合并后的 ref 上重验卡内文件面(git grep / git show <merged-sha> -- <carded paths>)—— 解锁你的那个合并,正是最可能已经顺手修掉你这张卡的提交;由 advisory 立的卡尤其如此(advisory 描述的是该 PR 分支自己的状态,PR 落地前就可能自愈)。

Related discipline it extends: SKILL step 1 stale-premise check (ages-based), Operational notes 4 (origin/main vs working tree — the triage-side root cause here), #6413 (the specimen).

Evidence anchors

Duplicate search before filing: unblocked merge re-verify stale premise over open issues — no hit.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions