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
2 changes: 1 addition & 1 deletion .claude/skills/pm-dispatch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
- governed 面统一定义:`docs/adr/**` + `.claude/**`(全量)+ `skills/**` + `docs/NORTH-STAR.md`。
- governed 面同含 `AGENTS.md` + `CLAUDE.md`;`GOVERNED_REPOS` 各仓同治理待遇,执行席恒随落地仓车道。
- 路径面命中 Tier H ⇒ ACCEPT 换终局四件套,混合 diff ⛔ 不按比例判;要拆让 dev 单独开 PR。
- 改动 >5000 行(含生成物)同换终局四件套,⛔ 无 Tier S 例外;读数 = PR additions+deletions。
- 改动 >3000 行(含生成物)同换终局四件套,⛔ 无 Tier S 例外;读数 = PR additions+deletions。
- ① 复核结论照常写在 issue 上;技能面 hunk 须由契约复审档的席复核,档外席先交 skills 席。
- ② PR 留给维护者看得见地悬着;终局两条:人工直合即审核记录;授权批准 ⇒ 席位落地。
- 看得见 = ACCEPT 同笔挂 `needs-user-decision` + 贴终稿「维护者速读」评论;①仍是审核记录。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
- 确认 MERGED 要两个读数:每轮同时读队列分支与 `origin/main`。
- 契约复核 PASS 落地的 PR 到窗口时已 ready 且 auto-merge 在挂,见 `contract-review.md`。
- 窗口自身权责不变:跟到 MERGED、踢出处置、落地后对账。
- 转 ready/入队前跑 `check-governed-merges.mjs --pr N`:受管面照两层;>5000 行(含生成物)照 Tier H。
- 转 ready/入队前跑 `check-governed-merges.mjs --pr N`:受管面照两层;>3000 行(含生成物)照 Tier H。
- 受管路径全在 `.claude/**` 者 Tier S:席内达档复核过落地前检三条即转正式入队。
- Tier H(其余受管面)者:四件套留 draft 等人批,⛔ 不翻正式不入队;获授权批准后认领席落地。
- ⛔ 两层不由席位批准;清标即落地同受此闸,漏判会被队列守卫在 merge group 里拒收。
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ Even inside your own worktree, operate defensively:
⛔ **Three classes of PR never enter this path on green alone:** (a) a diff touching any **governed surface**
(**Prime Directive #14**, which names them and holds the current list — **this file and `CLAUDE.md` are on it**,
so re-read it rather than recalling it); (b) the **Version Packages** PR, or any PR whose merge performs a
release (**Prime Directive #15**); (c) a PR whose **changed lines exceed 5,000** (`additions + deletions`,
release (**Prime Directive #15**); (c) a PR whose **changed lines exceed 3,000** (`additions + deletions`,
generated files included) — it lands the way a Tier H surface does: an authorized APPROVED review and then
the owning seat, or a human merge. Read the PR's file list (`get_files`), **its author and its size** before
you arm anything.
Expand Down
70 changes: 40 additions & 30 deletions scripts/pm/check-governed-merges.mjs

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions scripts/pm/check-governed-queue-guard.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,12 @@
*
* > 修改代码量超过某个行数(比如5000)就应该人工审核
*
* and on 2026-10-09 lowered the line, verbatim and untranslated:
*
* > 这种大额改动就应该人工审核,我还是建议5000行的人工审核门槛降到 3000,立卡。
*
* PR #19033 landed it seat-side: `testVerdict(paths, { size })` in the sibling
* carries a `size` limb, `HUMAN_MERGE_LINE_THRESHOLD` (5,000) is declared
* carries a `size` limb, `HUMAN_MERGE_LINE_THRESHOLD` (3,000) is declared
* there ONCE, the comparison is `additions + deletions` STRICTLY greater, and
* generated files are INCLUDED — the case that prompted the ruling, PR #18971
* (+238,310 / −119, 237,706 of them regenerated), touched no governed path and
Expand Down Expand Up @@ -1906,6 +1910,7 @@ export function renderSizeVerdict(verdict) {
'',
' 2026-09-18 「修改代码量超过某个行数(比如5000)就应该人工审核」',
' 2026-09-27 「所以阈值写死成 5000 行 , 维护者已经批准了就是可以合并。」 (objectstack#20153)',
' 2026-10-09 「这种大额改动就应该人工审核,我还是建议5000行的人工审核门槛降到 3000,立卡。」',
'',
' landed as `HUMAN_MERGE_LINE_THRESHOLD` and the lift in scripts/pm/check-governed-merges.mjs, which',
' this leg IMPORTS — the number, the comparison, what counts and what lifts are that file\'s, never',
Expand Down Expand Up @@ -3455,9 +3460,10 @@ export async function selfTest() {
text18971,
);
assert(
'and-names-the-TWO-landings-an-authorized-APPROVAL-or-a-HUMAN-MERGE-quoting-both-rulings-untranslated-and-never-advises-shrinking-the-diff',
'and-names-the-TWO-landings-an-authorized-APPROVAL-or-a-HUMAN-MERGE-quoting-all-three-rulings-untranslated-and-never-advises-shrinking-the-diff',
text18971.includes('HUMAN MERGE') && text18971.includes('修改代码量超过某个行数(比如5000)就应该人工审核') &&
text18971.includes('所以阈值写死成 5000 行 , 维护者已经批准了就是可以合并。') && text18971.includes('DRAFT') && !/shrink|split the|smaller/i.test(text18971),
text18971.includes('所以阈值写死成 5000 行 , 维护者已经批准了就是可以合并。') &&
text18971.includes('这种大额改动就应该人工审核,我还是建议5000行的人工审核门槛降到 3000,立卡。') && text18971.includes('DRAFT') && !/shrink|split the|smaller/i.test(text18971),
text18971,
);
assert(
Expand Down
7 changes: 4 additions & 3 deletions scripts/pm/check-skill-line-ratchet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,10 @@ export const CEILINGS = new Map([
// 2026-09-18, live chat beside ruling C on the regenerated-artefact landing,
// verbatim and untranslated: 「还有应该完善skills,修改代码量超过某个行数
// (比如5000)就应该人工审核。」 The content is ONE rule line beside the
// four-piece-terminal trigger: a PR over 5,000 changed lines (additions +
// deletions, generated files included) takes the same terminal, with no
// fact-layer exception; the mechanical face is `check-governed-merges.mjs`.
// four-piece-terminal trigger: a PR over the human-merge line (3,000 changed
// lines since the maintainer's 2026-10-09 word; additions + deletions,
// generated files included) takes the same terminal, with no fact-layer
// exception; the mechanical face is `check-governed-merges.mjs`.
// It could not be paid in place — measured, not assumed: the trigger line it
// belongs beside stands at 118 B against the 120-byte cap and the shortest
// self-contained form of the rule is 111 B; of the file's 598 adjacent bullet
Expand Down
2 changes: 1 addition & 1 deletion scripts/pm/dispatch-gates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26397,7 +26397,7 @@ function selfTest() {
t('exactly at the threshold is under it — strictly greater, as the gate reads it', atLine.includes('under.') && !atLine.includes('HUMAN MERGE'), atLine);
const noneLine = changedLineLines(null).join('\n');
t('an explicit path list is NOT MEASURED, said out loud, never a silent under', noneLine.includes('NOT MEASURED') && !noneLine.includes('under.') && noneLine.includes('--pr'), noneLine);
t('the threshold is read from the gate — no second copy here — and it is the ruled 5000', HUMAN_MERGE_LINE_THRESHOLD === 5000 && changedLineLines({ additions: 5001, deletions: 0 }).join('\n').includes('OVER'));
t('the threshold is read from the gate — no second copy here — and it is the ruled 3000', HUMAN_MERGE_LINE_THRESHOLD === 3000 && changedLineLines({ additions: 3001, deletions: 0 }).join('\n').includes('OVER'));
t('a text buffer counts its lines, an unterminated last line included', lineCountOf(Buffer.from('a\nb\n')) === 2 && lineCountOf(Buffer.from('a\nb')) === 2 && lineCountOf(Buffer.alloc(0)) === 0);
t('a buffer with a NUL in its first 8000 bytes is binary: null, which the caller counts as zero lines', lineCountOf(Buffer.from([0x61, 0, 0x62])) === null);
// Same liveness guards as the mandatory table: dead data reading as
Expand Down
Loading