Skip to content

Commit bb4aa09

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-14310-log-every-5xx
2 parents b318683 + 20b8839 commit bb4aa09

2 files changed

Lines changed: 37 additions & 31 deletions

File tree

.claude/skills/pm-dispatch/SKILL.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ issue 任何人不得认领** —— 那意味着分诊还没走到,不是「可
357357
跑到清空排空稳态,阈值吸收突发(实测 40 分钟到 13 张 ≈ 稳态四倍,审计式倾倒形态)——
358358
没有阈值,倾倒只能按到达顺序摊进常规轮,失掉同族同上下文一次读完的批次红利,
359359
队尾同期继续增长;⛔ 二者不可互相替代。
360-
**紧急卡直接分诊** (维护者 2026-08-13):维护者点名或 p0 嫌疑 ⇒ 立即起
361-
`claude-fable-5` 分诊子代理,不等定时轮次;授权面 = 分诊本身(定级/路由/标签/既有评论格式),
360+
**紧急卡直接分诊** (维护者 2026-08-13):维护者点名或 p0 嫌疑 ⇒ 立即起 `CONTRACT_REVIEW_TIER`
361+
分诊子代理,不等定时轮次;授权面 = 分诊本身(定级/路由/标签/既有评论格式),
362362
⛔ 不写码不认领;产出落卡,与定时轮分诊同格式同效力(细则见 `references/dispatch-runbook.md`)。
363363
**跨仓 pin 链的窗口级兜底也在本 sweep**(联动单第一产者仍是接受座位;
364364
⛔ 只立单不执行 bump): objectui pin 落后且其队列已空 ⇒ 在本仓立/刷新 console bump 单;
@@ -587,16 +587,16 @@ closes-list:部分交付 PR 特意写 Refs 而非 Fixes 时它恰为空,正是
587587
**派发模型是 PM 的逐卡显式决定** —— 下限 `sonnet`(机械卡:
588588
正确性由门禁农场机械判定,失败在漏跑门不在判断);默认判断档 `opus`(M/L、
589589
裁决实施、任何带设计判断的卡;拿不准就升一档 —— 错派低档的返工贵过省下的额度);
590-
上限 `fable`(最重协议/流程/编排卡,按卡取用非新默认)。**⛔ 强制条款两条**:
591-
① 凡改**协议语义面**的卡一律 `model: "claude-fable-5"` —— 面 = 本 `SKILL.md` 主文件、
590+
上限 `fable`(最重协议/流程/编排卡,按卡取用非新默认)。**⛔ 强制条款两条**:① 凡改
591+
**协议语义面**的卡一律 `CONTRACT_REVIEW_TIER` 档(`--tier` 输出)—— 面 = 本 `SKILL.md` 主文件、
592592
决策框架拷贝所在文件(以 `check:skill-frame-sync` 强制处为准)与 `.claude/agents/os-dev.md`(2026-08-20
593593
收窄,维护者原话:「接受你的建议」—— fable 当审计师用,不当施工队用);
594594
`references/**` 面、或任一 pm-dispatch 治理面上一行级机械文本改动的卡降为 **opus 施工**
595595
(纯机械一行 PM 酌定可至 sonnet 地板),**补偿控制即既有技能面复核档要求**(ACCEPT 路径分叉
596596
①:复核席跑契约复审档位)—— opus 施工的治理面改动只经 fable 档复核到达维护者,
597597
⛔ 不新增标签不新增链;② 凡**改变契约接受/拒绝行为或扩大公开面**的卡(`domain:spec`
598598
语义面;判据即分诊代裁的机械边界测试与 spec 席内分派判据 —— `references/lanes/spec.md`,
599-
⛔ 不另抄第二份)一律 `claude-fable-5`(维护者 2026-08-12 裁定,
599+
⛔ 不另抄第二份)一律 `CONTRACT_REVIEW_TIER`(维护者 2026-08-12 裁定,
600600
原话:「同意,就按语义面收窄,立卡并通知 spec 席」)—— 契约错毒化一切下游,
601601
全仓最贵(条款②闸门见「入队与落地」)。**负边界(维护者 2026-08-28 裁定)**:
602602
运行时权限/安全**行为**变更不是条款② —— 归人工地板「安全/权限边界」

scripts/pm/dispatch-gates.mjs

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7934,6 +7934,26 @@ export function residueLines(
79347934
// Model-tier derivation — the half of the tier decision that IS a path question
79357935
// ---------------------------------------------------------------------------
79367936

7937+
/**
7938+
* The single source of truth for the model tier the PM lane's governance
7939+
* reads — clause ②'s CONTRACT-REVIEW tier: the tier a card that changes
7940+
* contract accept/reject behaviour or widens the public surface must be
7941+
* dispatched at, and the tier the `needs:contract-review` re-review sub-round
7942+
* must itself be running at (its opening self-check reads this). Declared HERE
7943+
* and only here, as a constant, so a model upgrade is a one-line change in one
7944+
* file — the clause-① mandate rows below read it, the self-test compares
7945+
* against it, and the PM skill's prose names it, so the model id is spelled as
7946+
* a VALUE on this one line and nowhere else across `scripts/pm/**` and
7947+
* `.claude/skills/pm-dispatch/**` (a second value site is what let this
7948+
* constant drift from the served tier unnoticed). The comparison against the
7949+
* served tier is EXACT, never a family or prefix floor — widening a governance
7950+
* gate's accept set is the maintainer's decision, not a refresh-time
7951+
* convenience. The review label deliberately names WHAT is reviewed, never a
7952+
* model (maintainer, 2026-08-16: 「needs:fable-review 这个标签不好,下次模型升级怎么办」).
7953+
* Rulebook: `.claude/skills/pm-dispatch/SKILL.md` 「入队与落地」 — the clause-② gate and the `needs:contract-review` review-chain bullets.
7954+
*/
7955+
export const CONTRACT_REVIEW_TIER = 'claude-fable-5-1';
7956+
79377957
/**
79387958
* The globs that MANDATE a model tier for any card whose file surface touches
79397959
* them, as DATA. This is the one list in this file besides CHANGE_KIND_GATES,
@@ -7967,7 +7987,7 @@ export function residueLines(
79677987
* about paths:
79687988
*
79697989
* - clause ①, encoded below: a card editing the PM lane's PROTOCOL-SEMANTIC
7970-
* surfaces is `claude-fable-5` — the pm-dispatch SKILL.md main file, every
7990+
* surfaces is `CONTRACT_REVIEW_TIER` — the pm-dispatch SKILL.md main file, every
79717991
* file carrying an enforced copy of the decision frame (the COPIES table
79727992
* of check:skill-frame-sync), and the dev-agent definition. Narrowed from
79737993
* "the whole skill tree, references included" by the maintainer's
@@ -7977,7 +7997,7 @@ export function residueLines(
79777997
* file-surface predicate, and exactly what this script takes as argv;
79787998
* - clause ②, NOT encoded and deliberately not: a card that changes contract
79797999
* accept/reject behaviour or widens the public surface is also
7980-
* `claude-fable-5`. That is judged from the card's CONTENT — what the change
8000+
* `CONTRACT_REVIEW_TIER`. That is judged from the card's CONTENT — what the change
79818001
* does to the contract — and a path cannot answer it. An ordinary-looking
79828002
* surface (one package's source file) is the NORMAL shape of a clause-②
79838003
* card. The closest a path can honestly get is SUSPICION:
@@ -8061,35 +8081,21 @@ export function residueLines(
80618081
export const MANDATORY_TIER_GLOBS = [
80628082
{
80638083
glob: '.claude/skills/pm-dispatch/SKILL.md',
8064-
tier: 'claude-fable-5',
8084+
tier: CONTRACT_REVIEW_TIER,
80658085
why: 'clause ① of the model-tiering ruling (narrowed to protocol semantics, 2026-08-20): the PM dispatch skill MAIN file is the lane\'s own operating protocol and a wrong edit propagates to every later dispatch — references/** dropped out of the path mandate that day',
80668086
},
80678087
{
80688088
glob: '.claude/agents/os-dev.md',
8069-
tier: 'claude-fable-5',
8089+
tier: CONTRACT_REVIEW_TIER,
80708090
why: 'clause ① (2026-08-20 narrowing): the dev-agent definition is protocol semantics — every dispatched dev runs under it, and it carries an enforced copy of the decision frame',
80718091
},
80728092
{
80738093
glob: 'skills/objectstack-pm-dispatch/SKILL.md',
8074-
tier: 'claude-fable-5',
8094+
tier: CONTRACT_REVIEW_TIER,
80758095
why: 'clause ① (2026-08-20 narrowing): the published PM skill carries two enforced copies of the decision frame (check:skill-frame-sync COPIES) and ships verbatim to third-party projects',
80768096
},
80778097
];
80788098

8079-
/**
8080-
* Clause ②'s single source of truth for the CONTRACT-REVIEW tier: the tier a
8081-
* card that changes contract accept/reject behaviour or widens the public
8082-
* surface must be dispatched at, and the tier the `needs:contract-review`
8083-
* re-review sub-round must itself be running at (its opening self-check reads
8084-
* this). Declared HERE and only here, as a constant, so a model upgrade is a
8085-
* one-line change in one file. The review label deliberately names WHAT is
8086-
* reviewed, never a model (maintainer, 2026-08-16: 「needs:fable-review 这个标
8087-
* 签不好,下次模型升级怎么办」), and the PM skill's prose points at this
8088-
* constant instead of spelling a model name.
8089-
* Rulebook: `.claude/skills/pm-dispatch/SKILL.md` 「入队与落地」 — the clause-② gate and the `needs:contract-review` review-chain bullets.
8090-
*/
8091-
export const CONTRACT_REVIEW_TIER = 'claude-fable-5';
8092-
80938099
/**
80948100
* The globs that make a surface a clause-② SUSPECT — a HINT, never a verdict.
80958101
*
@@ -15298,12 +15304,12 @@ function selfTest() {
1529815304
// mandate, and the ordinary surface that must NOT be mandated (a tool that
1529915305
// mandates everything is ignored, which loses the guardrail by the other road).
1530015306
const fableOf = (paths) => deriveTier(paths);
15301-
t('the pm-dispatch SKILL.md MAIN file is fable-mandatory', fableOf(['.claude/skills/pm-dispatch/SKILL.md']).tier === 'claude-fable-5');
15302-
t('the dev-agent definition is fable-mandatory', fableOf(['.claude/agents/os-dev.md']).tier === 'claude-fable-5');
15303-
t('the published PM skill (two enforced frame copies) is fable-mandatory', fableOf(['skills/objectstack-pm-dispatch/SKILL.md']).tier === 'claude-fable-5');
15307+
t('the pm-dispatch SKILL.md MAIN file is fable-mandatory', fableOf(['.claude/skills/pm-dispatch/SKILL.md']).tier === CONTRACT_REVIEW_TIER);
15308+
t('the dev-agent definition is fable-mandatory', fableOf(['.claude/agents/os-dev.md']).tier === CONTRACT_REVIEW_TIER);
15309+
t('the published PM skill (two enforced frame copies) is fable-mandatory', fableOf(['skills/objectstack-pm-dispatch/SKILL.md']).tier === CONTRACT_REVIEW_TIER);
1530415310
t('a pm-dispatch REFERENCES path carries NO path mandate — the 2026-08-20 narrowing, inverted from the pre-narrowing pin', fableOf(['.claude/skills/pm-dispatch/references/review-checklist.md']).mandatory === false);
1530515311
const mixed = fableOf(['packages/spec/src/data/filter.zod.ts', '.claude/agents/os-dev.md']);
15306-
t('a MIXED surface is mandatory — one mandatory path decides, ordinary paths do not dilute it', mixed.mandatory && mixed.tier === 'claude-fable-5');
15312+
t('a MIXED surface is mandatory — one mandatory path decides, ordinary paths do not dilute it', mixed.mandatory && mixed.tier === CONTRACT_REVIEW_TIER);
1530715313
t('the mixed verdict reports the offending path, not just the verdict', mixed.hits.length === 1 && mixed.hits[0].path.endsWith('.claude/agents/os-dev.md'));
1530815314
t('an ordinary surface carries no path-derived mandate', fableOf(['packages/spec/src/data/filter.zod.ts']).mandatory === false);
1530915315
t("this tool's own file is not mandatory — the card that added this section reads itself correctly", fableOf(['scripts/pm/dispatch-gates.mjs']).mandatory === false);
@@ -15316,7 +15322,7 @@ function selfTest() {
1531615322
// The rendering is where the invariant is actually delivered: the claim
1531715323
// comment quotes THESE lines.
1531815324
const mandLines = tierLines(mixed).join('\n');
15319-
t('the mandatory rendering names the tier', mandLines.includes('claude-fable-5'));
15325+
t('the mandatory rendering names the tier', mandLines.includes(CONTRACT_REVIEW_TIER));
1532015326
t('the mandatory rendering says MANDATORY in a word a reader cannot skim past', mandLines.includes('MANDATORY'));
1532115327
t('the mandatory rendering shows its provenance — the path and the glob that covered it', mandLines.includes("- .claude/agents/os-dev.md ⇢ '.claude/agents/os-dev.md'"));
1532215328
t('the mandatory rendering names every sanctioned exit, so a downgrade needs a stated reason', mandLines.includes('quota exemption') && mandLines.includes('opus, never lower') && mandLines.includes('one-line-class') && mandLines.includes('proactive low-headroom'));
@@ -15337,7 +15343,7 @@ function selfTest() {
1533715343
let ambiguityRefused = false;
1533815344
try {
1533915345
deriveTier(['.claude/skills/pm-dispatch/SKILL.md'], [
15340-
{ glob: '.claude/skills/pm-dispatch/**', tier: 'claude-fable-5', why: 'a' },
15346+
{ glob: '.claude/skills/pm-dispatch/**', tier: CONTRACT_REVIEW_TIER, why: 'a' },
1534115347
{ glob: '.claude/skills/**', tier: 'opus', why: 'b' },
1534215348
]);
1534315349
} catch {
@@ -15375,7 +15381,7 @@ function selfTest() {
1537515381
/* frameFiles stays empty and the cases below fail loudly */
1537615382
}
1537715383
t('the frame-sync COPIES table is readable and non-empty, so the pin below is not vacuous', frameProbe.status === 0 && Array.isArray(frameFiles) && frameFiles.length > 0);
15378-
t(`every frame-sync-enforced copy is fable-mandated (unmandated: ${frameFiles.filter((f) => !deriveTier([f]).mandatory).join(', ') || 'none'})`, frameFiles.length > 0 && frameFiles.every((f) => deriveTier([f]).tier === 'claude-fable-5'));
15384+
t(`every frame-sync-enforced copy is fable-mandated (unmandated: ${frameFiles.filter((f) => !deriveTier([f]).mandatory).join(', ') || 'none'})`, frameFiles.length > 0 && frameFiles.every((f) => deriveTier([f]).tier === CONTRACT_REVIEW_TIER));
1537915385
t('the SKILL.md main file and the dev-agent definition are declared in their own right, not only via the frame table', MANDATORY_TIER_GLOBS.some((g) => g.glob === '.claude/skills/pm-dispatch/SKILL.md') && MANDATORY_TIER_GLOBS.some((g) => g.glob === '.claude/agents/os-dev.md'));
1538015386

1538115387
// ── Clause-② suspicion (the enqueue-gate card): hit / no hit / wording ────

0 commit comments

Comments
 (0)