Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .claude/skills/pm-dispatch/references/contract-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
- 已发布面以包的 `exports` 映射为准:从入口类型图不可达、且 `exports` 不可寻址的 `.d.ts` 是
出货字节,⛔ 不是已发布接受集,改它不触发 `Clause-②: yes`;legacy node10 深引用在契约之外。
- 四面皆不碰 ⇒ CI 加席位自读 ⛔ 不起第二个 agent;谁跑 = 派发席,档经子代理或卡线程取。
- 取档被配额拒(HTTP 429)⇒ ⛔ 不降档,留标记落交接行,点复核席,无则兄弟席:
- 送审路由只住此处:车道能取 `CONTRACT_REVIEW_TIER` 才自审;取不到(账号够不到、配额拒 429、
维护者限配)⇒ ⛔ 不降档 ⛔ 非分诊,落交接行并同笔敲在座复核席 `Request: contract-review`;
无复核席在座改点能取该档的兄弟席,皆无则挂等复核标记留欠审表待 (a)(b)(c)。交接行:
- `Contract-review-handoff: <review#N|domain:<lane>#N> — CONTRACT_REVIEW_TIER unavailable (<HTTP status / error>, <UTC time>) · head <sha>`
- 「立 skills 卡,把契约复审的路由直接改成 review 座位」「没有 fable 时,找 review 座位」(卡33157)
- 欠审 PR(含 draft)现 head 无记录无活认领且 (a)(b)(c) 之一 ⇒ 复核席先接,车道次之,⛔ 非分诊
- (a) 交接行点名现 head 或带等复核标记,同轮由所点席接;(b) 现 head 已等满一轮(约 60 分钟);
- (c) 车道收班或离总表:欠审入交班简报待下席或复核席;清单 `scripts/pm/check-owed-reviews.mjs`。
Expand Down
1 change: 1 addition & 0 deletions .claude/skills/pm-dispatch/references/dispatch-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
- 例:`screen-input-contract.ts` 的 grep 命中「ruling A′」,裁决区写 `A′ · 5651909056` 与原句:
「a non-number for a numeric field is refused, never silently passed」;路线随之为拒收(A′)。
- 原令「有限数字串转数字」与之相左,应派发前送复核;栅栏点名 A′ 的 spec 散文在范围。
- 派发令带送审路由:dev 交回点名欠审不自敲;席照 contract-review.md 自审或送复核席,⛔ 非分诊
- 新 changeset 文件名用 `<issue>-<slug>.md`,⛔ 不用随机词对名。
- same-day churn 行:派发时 `git log origin/main --oneline -20 -- <paths>` 见当天合并即加一行。
- 该行原文:基于合并后的代码工作,issue 引用的片段可能已变,先核对当前 main。
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/pm-dispatch/references/lanes/review.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

## 路由

- 车道 `Request: contract-review` 敲任一复核席信箱,空闲者接;无复核席在座敲兄弟席,⛔ 非分诊
- 车道何时送审、敲谁只住 contract-review.md 送审路由行;敲任一复核席信箱,空闲者接
- 互斥 = 既有 `Contract-review-claim:` 行:同 head 先贴者持有,复核席之间同此;后者撤回弃产出。
- 欠审表 `check-owed-reviews.mjs` 先给复核席;车道只在无复核席在座或 (b) 后再一轮无认领才接
- delta 复审归原复核者;复核席下班留下旧记录 ⇒ 下一复核席接 delta,交接行点名它。
Expand Down
20 changes: 18 additions & 2 deletions scripts/pm/check-skill-line-ratchet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,14 @@ export const CEILINGS = new Map([
// may not change, and the `Premise:` claim line. Measured delta +4; the section
// heading was renamed in place. Not a CROSS_FILE_MOVES destination, so no
// `ruledRaises` record applies. Landed count, headroom 0, same convention.
['.claude/skills/pm-dispatch/references/dispatch-runbook.md', 245],
// Raised 245 → 246 by the contract-review route (maintainer, 2026-11-13, in the
// triage seat's session, verbatim: 「立 skills 卡,把契约复审的路由直接改成 review 座位」
// and 「没有 fable 时,找 review 座位」; quoted in the body of card #33157, claim
// comment 6879512661): one line in the dispatch-prompt section — the order
// carries the route, the dev names the owed review in its hand-back and never
// knocks, the seat sends it to a review seat, never triage. Measured delta +1.
// Landed count, headroom 0, same convention.
['.claude/skills/pm-dispatch/references/dispatch-runbook.md', 246],
// Whole-text restructuring round (maintainer ruling 2026-08-23, Q1 = A):
// mechanism detail extracted from SKILL.md — the four long state-table rows
// (state-machine.md) and the clause-② review-chain operational detail
Expand Down Expand Up @@ -575,7 +582,16 @@ export const CEILINGS = new Map([
// tails leave the corpus; one rule per ≤120-byte line, no rule already stated in
// SKILL.md). Landed count, headroom 0, same convention (lowering is always
// legitimate).
['.claude/skills/pm-dispatch/references/contract-review.md', 60],
// Raised 60 → 63 by the contract-review route (maintainer, 2026-11-13, in the
// triage seat's session, verbatim: 「立 skills 卡,把契约复审的路由直接改成 review 座位」
// and 「没有 fable 时,找 review 座位」; quoted in the body of card #33157, claim
// comment 6879512661): the one routing rule — a lane self-reviews only when it
// reaches the tier; otherwise (unreachable, 429, rationed) it knocks a seated
// review seat, never triage, then a sibling seat with the tier, else the
// owed-review list — replaces the 429-only line (+2), and its one-line verbatim
// provenance carrying those two operative quotes (+1). Measured delta +3.
// Landed count, headroom 0, same convention.
['.claude/skills/pm-dispatch/references/contract-review.md', 63],
// Business-perspective decision-analysis writing guide (maintainer ruling
// 2026-08-20: the four-facet analysis must argue from the business
// standpoint). Set at landed line count (headroom 0, same convention).
Expand Down
60 changes: 59 additions & 1 deletion scripts/pm/post-stamped.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,8 @@ import { readClause2Line } from './clause2-line.mjs';
import { CONTRACT_REVIEW_TIER, CONTRACT_REVIEW_TIER_NAME, TIER_DEFAULT, TIER_FLOOR, ceilingTierSpellings, containerModelRefusal } from './dispatch-gates.mjs';
// The record's `Local-runs:` line is read by the file that owns the record's
// every other line — judged when present, an absent line not re-judged.
import { localRunsStand, readLocalRuns } from './record-recognisers.mjs';
// The mailbox doorbell is read by the same file: a knock's `To:` seat and its key come from `readMailboxLine`.
import { localRunsStand, readLocalRuns, readMailboxLine } from './record-recognisers.mjs';
// The fleet's repository roster — the one place a repository joins the fleet —
// is what a read-back may collapse a reference expansion against (header).
import { GOVERNED_REPOS } from './check-governed-merges.mjs';
Expand Down Expand Up @@ -2510,6 +2511,36 @@ export function decisionFacetRefusalText(rows) {
);
}

/**
* A contract-review knock addressed to triage — the route the rule text closes (`references/contract-review.md`
* 〈复核归属与资格〉): a lane that cannot take `CONTRACT_REVIEW_TIER` sends `Request: contract-review` to a seated
* review seat, then to a sibling seat that can take the tier, else leaves the PR on the owed-review list — ⛔ never
* to triage. This is the write tool's input check on its own act, the same class as the signature and the keyed
* lines above it: no landing, check, workflow or queue reads it, and a knock it refuses was never on the board.
* The doorbell is read by its owner (`readMailboxLine`), never restated here. A knock it reads AND one it finds
* unreadable (no reason, a bare PR number, a second line) are both judged: an unreadable reading still carries the
* `id` and `to` parsed before the template failed, and a malformed knock to triage is still a knock to triage. A
* comment the reader refuses outright (no `To:` seat, a key outside the table) names no contract-review knock at
* all and passes, as it does today. Comments only. Answers the reading, or null. Pure.
*/
export function triageContractReviewKnock(body) {
const knock = readMailboxLine(String(body ?? ''));
if ((knock.state !== 'read' && knock.state !== 'unreadable') || knock.id !== 'request:contract-review') return null;
return /^triage#/u.test(knock.to) ? knock : null;
}

/** The refusal a caller reads, from `triageContractReviewKnock`'s reading. */
export function triageContractReviewKnockText(knock) {
return (
`post-stamped: REFUSED — a \`Request: contract-review\` knock addressed to triage (\`To: ${knock.to}\`). Nothing was written.\n` +
' A lane that cannot take CONTRACT_REVIEW_TIER (the account cannot reach it, a 429 refusal, or the maintainer\n' +
' rationed it) knocks a seated review seat\'s mailbox — `To: review#N`, the PR its seat post\'s `Mailbox:` line\n' +
' names — and, while no review seat is seated, a sibling lane seat that can take the tier; with neither, the PR\n' +
' waits on the owed-review list (`scripts/pm/check-owed-reviews.mjs`). ⛔ Never triage. The route is\n' +
' `references/contract-review.md` 〈复核归属与资格〉. ⛔ No flag turns it off.'
);
}

/**
* The block the platform appends to an artefact whose sent body does not
* already carry one: a blank line, a rule, the bare attribution line — 58
Expand Down Expand Up @@ -3844,6 +3875,9 @@ export function judgeBody(input, options = {}, nowMs = Date.now(), tool = 'post-
// ⛔ Comments only: a decision analysis is anchored on its card AS A COMMENT, and the handover check reads comments.
const facets = options.mode === 'comment' ? decisionFacetRefusals(rendered.body) : [];
if (facets.length > 0) return { ok: false, rendered, text: decisionFacetRefusalText(facets) };
// ⛔ Comments only: a mailbox knock IS a comment on the seat's mailbox PR.
const triageKnock = options.mode === 'comment' ? triageContractReviewKnock(rendered.body) : null;
if (triageKnock !== null) return { ok: false, rendered, text: triageContractReviewKnockText(triageKnock) };
// ⛔ Bodies only: a VACANT seat post's ledger holds pointers, never obligations (#23396).
const vacant = options.mode === 'body' ? vacantLedgerRefusals(rendered.body) : [];
if (vacant.length > 0) return { ok: false, rendered, text: vacantLedgerRefusalText(vacant) };
Expand Down Expand Up @@ -3886,6 +3920,9 @@ const USAGE = [
' A comment that is a decision analysis — a decision frame, an options table or lettered options, and a',
` recommendation naming one — is REFUSED when it carries no \`${DECISION_FACET_MARKER}\` marker outside code; the`,
' refusal prints the four-facet block it owes. Card bodies and every other route are untouched.',
' A mailbox comment whose `To:` is a triage seat and whose key is `Request: contract-review` is REFUSED, whether',
' or not the key line spells its template: a lane without the review tier knocks a review seat, then a sibling',
' seat with the tier — never triage.',
' The attribution footer is the caller\'s: its form differs by channel and act, so this tool adds none.',
'',
` Exit: 0 written and stored · ${EXIT_USAGE} usage · ${EXIT_REFUSED} refused, nothing written ·`,
Expand Down Expand Up @@ -4117,6 +4154,7 @@ const SELF_TEST_BATTERIES = Object.freeze({
"the size route: over the relay's body cap under auto THIS write goes direct with one line naming bytes, cap and identity; at or under it the relay; explicit dispatch refuses naming the bytes; nothing else re-routes": 13,
'the signature: every body opens with LANE#N · ACCOUNT · SESSION or is refused, beside the stamp contract; one leading signature changes no reading': 11,
'the one judge: every body refusal on ONE path — `main` and `label-write.mjs --comment-file` call `judgeBody`, never a copy': 8,
'the review route: a `Request: contract-review` knock addressed to triage is refused; to a review or sibling seat, and every other key to triage, it passes': 10,
});
const SELF_TEST_BATTERY_FLOOR = 18;
const UNATTRIBUTED_BATTERY = '(unattributed)';
Expand Down Expand Up @@ -5656,6 +5694,26 @@ export function selfTest() {
t('↔ structural: label-write imports judgeBody and judges its folded comment with it, ⛔ no reader of its own', /\bjudgeBody\b[^;]*from '\.\/post-stamped\.mjs'/u.test(lw) && /judgeBody\(text, \{ mode: 'comment' \}/u.test(lw) && !/function\s+(signatureRefusal|claimKeyedLineRefusals|decisionFacetRefusals)\b/u.test(lw));
}

battery('the review route: a `Request: contract-review` knock addressed to triage is refused; to a review or sibling seat, and every other key to triage, it passes');
{
const SIG = 'domain:server#3 · os-bill · session_01QSeKYmhU5KEj1nukYhp1Tg';
const HEAD = '1b03a9c3d4e5f60718293a4b5c6d7e8f90a1b2c3';
const KNOCK = (to, key = `Request: contract-review · PR #26766 · head ${HEAD} · CONTRACT_REVIEW_TIER rationed`) => `${SIG}\nTo: ${to}\n${key}`;
const judged = (to, key) => judgeBody(KNOCK(to, key), { mode: 'comment' }, NOW_MS);
const refused = judged('triage#1');
t('⭐ a contract-review knock addressed to `triage#1` is refused, and the refusal names the seat it was addressed to', !refused.ok && refused.text.startsWith('post-stamped: REFUSED') && refused.text.includes('`To: triage#1`'));
t('⭐ …and the refusal names the review seat\'s mailbox, the sibling fallback, the owed-review list and the rule\'s home', refused.text.includes('`To: review#N`') && refused.text.includes('`Mailbox:`') && refused.text.includes('sibling lane seat') && refused.text.includes('check-owed-reviews.mjs') && refused.text.includes('references/contract-review.md') && refused.text.includes('Nothing was written'));
t('⭐ a MALFORMED knock to triage is refused too — no reason, a bare PR number, a second line: the reader\'s unreadable reading still names the key and the seat', [`Request: contract-review · PR #26766 · head ${HEAD}`, 'Request: contract-review · 26766 · rationed', `Request: contract-review · PR #26766 · head ${HEAD} · rationed\nbecause fable is short today`].every((key) => { const r = judged('triage#1', key); return !r.ok && r.text.includes('`To: triage#1`'); }) && judged('review#1', `Request: contract-review · PR #26766 · head ${HEAD}`).ok);
t('a bare `To: triage` reads as `triage#1` (the doorbell reader\'s seat spelling) and is refused the same way', !judged('triage').ok && !judged('Triage#2').ok);
t('⭐ the same knock addressed to a review seat passes', judged('review#1').ok && judged('review#2').ok);
t('…and to a sibling lane seat, the fallback while no review seat is seated', judged('domain:server#2').ok);
t('⛔ every other key to triage is untouched: `Request: urgent-triage` and `Request: triage` pass', judged('triage#1', 'Request: urgent-triage · #26766 · main red on Test Core').ok && judged('triage#1', 'Request: triage · #26766 · which lane takes it').ok);
t('⛔ a card BODY is untouched — the check is a comment\'s, as a knock is a comment on a mailbox PR', judgeBody(KNOCK('triage#1'), { mode: 'body' }, NOW_MS).ok);
t('⛔ the refusal\'s own words (the seat it echoes aside) carry no tracker number and no HTML comment — a runtime string an author is shown', /#\d/u.test(triageContractReviewKnockText({ to: 'SEAT' })) === false && triageContractReviewKnockText({ to: 'SEAT' }).includes('<!--') === false);
const own = readFileSync(SELF_PATH, 'utf8');
t('structural: the doorbell reader is imported from the file that owns it, ⛔ never restated, and the check runs inside judgeBody on comments only', /import \{[^}]*\breadMailboxLine\b[^}]*\} from '\.\/record-recognisers\.mjs';/u.test(own) && !/function\s+readMailboxLine\b/u.test(own) && /const triageKnock = options\.mode === 'comment' \? triageContractReviewKnock\(rendered\.body\) : null;/u.test(own));
}

// The floor, evaluated last: a battery that stops running names itself here.
const failed = cases.filter((c) => !c.ok);
for (const c of cases) console.log(` ${c.ok ? '✓' : '✗'} ${c.name}`);
Expand Down
Loading
Loading