diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index b093b72a8d3..24f9a7a7828 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -125,7 +125,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - `pm:queue` 卡逾三天欠一次显式转换(派发/转箱/停放/撤单/改前提),⛔ 不是排期。 - hold/blocked 的行契约、双通道与 `Restart-touch:` 触发文件细则见 `references/state-machine.md`。 - hold 放行须双查:只放最近一次转换评论的条件,其后卡上有更新的 merged PR 即拒。 -- `Unlock-action: re-check PR #M` 行改写完工卡的解锁动作,只认此一值,别的拼写静默回落。 +- `Unlock-action:` 只认 `re-check PR #M` 与 `re-check #N when label <标签> `,余者静默回落。 - `needs-user-decision` 是决定待做,`pm:on-hold` 是决定已做;`manual — <理由>` ⛔ 不是合法出口。 - 无机制可唤醒的卡 ⛔ 不 hold:关 not planned,理由/出处载关单评论;重开免费,维护者可否决。 - 缺陷卡 ⛔ 不藏进 hold 也不自行关闭:可复现且用户可达 ⇒ 回 `pm:queue`。 diff --git a/.claude/skills/pm-dispatch/references/core-rules.md b/.claude/skills/pm-dispatch/references/core-rules.md index 05c035b72b7..908ab013844 100644 --- a/.claude/skills/pm-dispatch/references/core-rules.md +++ b/.claude/skills/pm-dispatch/references/core-rules.md @@ -30,7 +30,7 @@ - hold 放行须双查:只放最近一次转换评论的条件,其后有更新的 merged PR 即拒。 - 没有可点火出口的卡 ⛔ 不 hold,直接关 not planned 并把理由与出处写进关单评论。 - 缺陷卡 ⛔ 不可自行关闭或藏进 hold:可复现回队列、未兑现走 enforce-or-remove、余下进箱。 -- `pm:blocked` 配正文行 `Blocked-by:`,工已完而卡在门禁的同用此态并写 `Unlock-action:` 行。 +- `pm:blocked` 配正文行 `Blocked-by:`,完工卡遇门禁或等换标的同用此态并写 `Unlock-action:` 行。 - `pm:awaiting-maintainer` 只剩站外人工动作,恒带 `Maintainer-action:` 行;`pm:blocking` ⛔ 不手工挂。 - `pm:retriage` 并存 ⛔ 不摘原标且跳过派发;`finding` 恒等于待首次定级、定级即离标。 - 插队标签可超 `batch` 立即派发,⛔ 不豁免同文件串行、深度等待与认领协议。 diff --git a/.claude/skills/pm-dispatch/references/state-machine.md b/.claude/skills/pm-dispatch/references/state-machine.md index 70ac176366d..db7ddf6a4d0 100644 --- a/.claude/skills/pm-dispatch/references/state-machine.md +++ b/.claude/skills/pm-dispatch/references/state-machine.md @@ -26,8 +26,8 @@ - 句中提及刻意拒收;等 PR 合并或等发布且 pin 覆盖的卡同理,指一张在该刻关闭的卡。 - ⛔ 不扩词表;等发布的目标 = pin-bump 杂事卡,`Part of` 型 PR 的跟踪卡 ⛔ 不可用作目标。 - 工已完、PR 被外部门禁缺陷卡住者同用本态,⛔ 不设新标签;`Blocked-by:` 指向那张门禁卡。 -- 正文加机器可读行 `Unlock-action: re-check PR #M`,把解锁出口改为重查该 PR 落地。 -- 只认此一值,别的拼写静默回落重派,散文另起行;停放的 PR 正文须点名那张门禁卡。 +- 正文行 `Unlock-action: re-check PR #M`(重查落地)或 `re-check #N when label <标签> `。 +- 只认此二值,别的拼写静默回落重派,散文另起行;停放的 PR 正文须点名那张门禁卡。 - ⛔ 永不给完工卡重派 dev。 - 上游已关 ⇒ 先重新推导是否有新阻塞并改写该行,⛔ 不反射式放行。 - 正文是正典家:新 blocker 停在评论、正文留已关旧目标 ⇒ 巡查报 stale 并要求迁回正文。 diff --git a/scripts/pm/check-half-states.mjs b/scripts/pm/check-half-states.mjs index f49d566ed27..2b93576c1e8 100644 --- a/scripts/pm/check-half-states.mjs +++ b/scripts/pm/check-half-states.mjs @@ -1880,7 +1880,7 @@ function stripMatchingDecoration(value, opener) { * cause with. * * @param {string} text - * @param {'Blocked-by'|'Restart-when'|'Maintainer-action'} key + * @param {'Blocked-by'|'Restart-when'|'Maintainer-action'|'Unlock-action'} key * @returns {string[]} */ export function directiveValues(text, key) { @@ -6836,6 +6836,49 @@ export function h31ContractReviewCarrierSplit(issue, openPrs) { ); } +// --------------------------------------------------------------------------- +// The label-transition exit — the second `Unlock-action:` value (#19255). +// +// The unlock predicate is "the `Blocked-by:` target CLOSED", and the one rewrite the state model admitted +// (`re-check PR #M`) is read by seats and by no script — so a block on a `needs-user-decision` / `pm:on-hold` +// target had no exit a machine could fire (H26), and any other spelling fell back to the closed predicate in +// SILENCE. This value names the CARD, the LABEL and the STATE tested on it (a state, not an event: a sweep +// observes labels, never transitions; `absent` is the live case — the ruling lands, `needs-user-decision` leaves +// the target). ⛔ Every other spelling still falls back silently, by ruling: the closed set IS the contract. +// --------------------------------------------------------------------------- + +const UNLOCK_LABEL_EXIT_RE = + /^re-check[ \t]+(?:([A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*))?#([1-9]\d{0,5})[ \t]+when[ \t]+label[ \t]+`?([^\s`]+?)`?[ \t]+(absent|present)\b/; +/** Every `re-check #N when label