From 76ffcc70b39be2581d4aaee20bdcb69ec9d0ba6c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 25 Oct 2026 09:51:10 +0000 Subject: [PATCH] chore(pm-dispatch): ADR cards dispatch at the contract-review tier, effort floor xhigh MANDATORY_TIER_GLOB_ROWS gains a docs/adr/** row (CONTRACT_REVIEW_TIER, oneLineExit: false) quoting the 2026-10-25 order; the tiering clause in execution-duties.md names docs/adr/** beside the protocol-semantic surface, with an xhigh effort floor, and closes its one-line exemption. tierLines no longer hard-codes the published catalog's ruling as the reason for every oneLineExit: false glob; the self-test pins the new row. Claude-Session: https://claude.ai/code/session_01X6Y7QshYEp9SD3ruEazFRS Co-authored-by: Claude --- .../references/execution-duties.md | 4 ++-- scripts/pm/dispatch-gates.data.mjs | 19 +++++++++++++++---- scripts/pm/dispatch-gates.mjs | 10 ++++++---- scripts/pm/dispatch-gates.self-test.mjs | 11 ++++++++++- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.claude/skills/pm-dispatch/references/execution-duties.md b/.claude/skills/pm-dispatch/references/execution-duties.md index d53098685c7..402038c978e 100644 --- a/.claude/skills/pm-dispatch/references/execution-duties.md +++ b/.claude/skills/pm-dispatch/references/execution-duties.md @@ -93,10 +93,10 @@ - 下限档给机械卡(正确性由门禁农场机械判定)。 - 默认判断档给 M/L、裁决实施与任何带设计判断的卡;拿不准就升一档。 - 上限 = 契约复审档(`CONTRACT_REVIEW_TIER`),给最重协议/流程/编排卡,按卡取用非新默认。 -- 强制条款①:凡改协议语义面的卡一律契约复审档。 +- 强制条款①:凡改协议语义面或 `docs/adr/**` 的卡一律契约复审档;后者 effort 下限 `xhigh`。 - 协议语义面 = 本 `SKILL.md`、决策框架拷贝所在文件、`.claude/agents/os-dev.md` 与 `skills/**`。 - 仅 `references/**` 面、或治理面上一行级机械文本改动的卡,降为默认判断档施工。 -- 发布的 `skills/**` 整根随 `npx skills add` 发运,⛔ 无一行级豁免,逐行判机械不作数。 +- `skills/**`(随 `npx skills add` 发运)与 `docs/adr/**` ⛔ 无一行级豁免,逐行判机械不作数。 - 纯机械一行 PM 酌定可至下限档;降档施工的补偿控制 = 复核席跑契约复审档。 - 降档施工只经契约复审档复核到达维护者,⛔ 不新增标签不新增链。 - 强制条款②:放宽接受集或扩大公开面的卡默认判断档施工;命中即 spec 车道的活。 diff --git a/scripts/pm/dispatch-gates.data.mjs b/scripts/pm/dispatch-gates.data.mjs index e5a7596ac96..3a4fb63839f 100644 --- a/scripts/pm/dispatch-gates.data.mjs +++ b/scripts/pm/dispatch-gates.data.mjs @@ -1098,8 +1098,9 @@ export const CHANGE_KIND_ROWS = [ * encoded: the one-line-class downgrade does not exist for a surface under * `skills/**` — the 2026-09-10 ruling's 必须, because a closed enumeration * beats a per-line "is this mechanical" call on a catalog third parties - * install — so that entry carries `oneLineExit: false` and `tierLines` - * refuses to offer the exit for any card whose surface hits it. + * install — nor under `docs/adr/**`, whose 2026-10-25 order says 都需要 — + * so those entries carry `oneLineExit: false` and `tierLines` refuses to + * offer the exit for any card whose surface hits one of them. * * ## Why the globs are matched with `hintCovers`, asymmetry included * @@ -1160,8 +1161,9 @@ export const CHANGE_KIND_ROWS = [ * * The authority for the policy is the maintainer ruling quoted in the PM * dispatch skill (2026-08-10 three-tier ruling, clause ① of its 强制条款, as - * narrowed to protocol semantics by the 2026-08-20 ruling quoted there, and - * widened to the published `skills/**` catalog by the 2026-09-10 ruling). + * narrowed to protocol semantics by the 2026-08-20 ruling quoted there, + * widened to the published `skills/**` catalog by the 2026-09-10 ruling, and + * to ADR text, `docs/adr/**`, by the 2026-10-25 order quoted in its row). * This table is a machine-readable copy of ONE predicate from it, not a second * statement of the policy: when they disagree, the skill wins and this table is * the thing to fix. The frame-copy half of the predicate is DEFINED by another @@ -1189,6 +1191,15 @@ export const MANDATORY_TIER_GLOB_ROWS = [ // beats a per-line call on an installed catalog), so it is data, not prose. oneLineExit: false, }, + { + glob: 'docs/adr/**', + tier: 'CONTRACT_REVIEW_TIER', + why: 'the 2026-10-25 order (marchtian, verbatim 「adr 这种任务都需要 fable extra,重新处理并立skills 卡片」): an ADR binds every later card cut from it until a superseding ADR says otherwise, and lands only by the maintainer\'s hand, so a drafting error is paid by the maintainer and again by each implementation card — 都需要 leaves no one-line exemption, and the same order fixes the effort floor at xhigh (the PM skill states it beside clause ①)', + // 都需要 closes the one-line-class exit by PATH, the same shape as the + // skills/** row; the effort floor is skill text, since this table carries a + // tier and the dispatch-gates freeze admits no new printed line. + oneLineExit: false, + }, ]; /** diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index d75667dd463..35a8e64b729 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -12115,9 +12115,11 @@ export function tierLines(result) { ]; } // The one-line-class exit is a card-CONTENT judgment for every mandated - // surface but one: a glob declared with `oneLineExit: false` (the published - // catalog, 2026-09-10 ruling) closes it by PATH, and one such hit closes it - // for the WHOLE card — the exit is taken per card, not per file. + // surface except those whose glob is declared with `oneLineExit: false` (the + // published catalog, 2026-09-10 ruling; ADR text, 2026-10-25 order): that + // closes it by PATH, and one such hit closes it for the WHOLE card — the exit + // is taken per card, not per file. The reason printed is the row's own `why`, + // already on the hit lines above, so this line names no ruling of its own. const oneLineBarred = [...new Set(hits.filter((h) => h.oneLineExit === false).map((h) => h.glob))]; const oneLineExit = oneLineBarred.length === 0 @@ -12125,7 +12127,7 @@ export function tierLines(result) { ` discretion, compensated by the skill-face review at ${CONTRACT_REVIEW_TIER}) — judged from the card CONTENT,` + ' never from paths' : `the one-line-class mechanical-edit downgrade is ⛔ NOT available for this surface — ${oneLineBarred.map((g) => `'${g}'`).join(', ')}` + - ' carries no one-line exemption (the published catalog, 2026-09-10 ruling), and one such path closes the exit for the whole card'; + ' carries no one-line exemption (its row declares `oneLineExit: false`; the reason is on its hit line above), and one such path closes the exit for the whole card'; return [ `Model tier — MANDATORY: ${tier} (derived from the file surface, not recalled).`, ...hits.map((h) => ` - ${h.path} ⇢ '${h.glob}' — ${h.why}`), diff --git a/scripts/pm/dispatch-gates.self-test.mjs b/scripts/pm/dispatch-gates.self-test.mjs index ae0a5a0d45f..a70b32e388f 100644 --- a/scripts/pm/dispatch-gates.self-test.mjs +++ b/scripts/pm/dispatch-gates.self-test.mjs @@ -9999,7 +9999,16 @@ export function selfTest({ tier = 'full' } = {}) { t('no per-file entry for the deleted published PM skill survives it, and its old path carries the root mandate only', !MANDATORY_TIER_GLOBS.some((g) => g.glob.includes('objectstack-pm-dispatch')) && fableOf(['skills/objectstack-pm-dispatch/SKILL.md']).hits.every((h) => h.glob === 'skills/**')); t('skills/** does NOT reach the internal .claude/skills tree — a pm-dispatch references file still carries no mandate', fableOf(['.claude/skills/pm-dispatch/references/state-machine.md']).mandatory === false); t('the skills/** entry is declared with its one-line exit switched off, as data', MANDATORY_TIER_GLOBS.some((g) => g.glob === 'skills/**' && g.oneLineExit === false && g.tier === CONTRACT_REVIEW_TIER)); - t('every other mandatory entry keeps the one-line exit open (the flag is an opt-out, absent by default)', MANDATORY_TIER_GLOBS.filter((g) => g.glob !== 'skills/**').every((g) => g.oneLineExit === undefined) && catalogHit.hits.every((h) => h.glob !== 'skills/**' || h.oneLineExit === false)); + // The ADR order (2026-10-25, 「都需要」): ADR text is the second surface whose + // one-line exit is closed by path; the rest keep the opt-out absent. + const ONE_LINE_BARRED = ['skills/**', 'docs/adr/**']; + t('the docs/adr/** entry is declared at the contract-review tier with its one-line exit switched off, as data', MANDATORY_TIER_GLOBS.some((g) => g.glob === 'docs/adr/**' && g.oneLineExit === false && g.tier === CONTRACT_REVIEW_TIER)); + t('every other mandatory entry keeps the one-line exit open (the flag is an opt-out, absent by default)', MANDATORY_TIER_GLOBS.filter((g) => !ONE_LINE_BARRED.includes(g.glob)).every((g) => g.oneLineExit === undefined) && catalogHit.hits.every((h) => h.glob !== 'skills/**' || h.oneLineExit === false)); + const adrHit = fableOf(['docs/adr/0028-metadata-naming-and-namespace-isolation.md']); + t('an ADR file is mandated, by the docs/adr/** entry alone', adrHit.tier === CONTRACT_REVIEW_TIER && adrHit.hits.length === 1 && adrHit.hits[0].glob === 'docs/adr/**'); + t('docs/adr/** does NOT reach the rest of docs/ — a sibling docs file carries no mandate', fableOf(['docs/NORTH-STAR.md']).mandatory === false && fableOf(['docs/adr-notes.md']).mandatory === false); + const adrLines = tierLines(adrHit).join('\n'); + t("the ADR rendering refuses the one-line-class exit, naming the glob, and does not borrow the catalog's reason", adrLines.includes("NOT available for this surface — 'docs/adr/**'") && !adrLines.includes('drops to opus execution') && !adrLines.includes('(the published catalog')); const catalogLines = tierLines(catalogHit).join('\n'); t('the published-catalog rendering refuses the one-line-class exit, in those words', catalogLines.includes('one-line-class') && catalogLines.includes('NOT available') && catalogLines.includes('no one-line exemption')); t('and does not offer the opus-execution drop the other mandated surfaces get', !catalogLines.includes('drops to opus execution'));