Skip to content

Commit 88920d1

Browse files
os-steveclaude
andauthored
governed: a fork PR is a proposal, never a delivery — the FORK predicate beside PATH and SIZE, plus the charter's external-contributions section (#19526)
Fixes #19470 Clause-②: no ## The ruling this lands Maintainer, batch #207 item 1, letter 是, verbatim and untranslated: 「fork PR 的处理同意你的意见。」 — recorded by the director on the card (comment 5754996112) as: **a fork PR is a proposal, not a delivery. No agent seat flips it ready, enqueues it, arms auto-merge on it, or approves it — ever.** It enters through the card door (card first; the human decides the problem, not the code; the seat adopts the diff and never lands the fork PR; a fork's CI is never approved to run by a seat, zero check runs read NOT MEASURED, never green), with the minimal mechanism: a second predicate beside the governed one in `scripts/pm/check-governed-merges.mjs`, one sentence in AGENTS.md, one short 〈外部贡献〉 section in the charter, the NOT-MEASURED wording. No new label, no new sweep; the supply-chain clause is deferred until the first such fork PR appears. The live specimen, PR #19342 (head `jinyitao123/objectstack`, `author_association: FIRST_TIME_CONTRIBUTOR`, 0 check runs on `5fa7b6d`, 0 labels), is read here as evidence only. It stays untouched by this PR: its disposal is the director's and triage's act in the same stroke, and this branch writes nothing on it. ## What changed (five files, all on the claim's surface) | file | before → after | net | what | |:--|:--|--:|:--| | `scripts/pm/check-governed-merges.mjs` | 6146 → 6226 lines | **+80** (98 added, 18 replaced; budget ≤ +80, self-tests included) | the FORK predicate beside PATH and SIZE; the check-run reading; a new self-test battery beside the SIZE cases | | `AGENTS.md` | 1109 → 1109 | **0** (ceiling 1109, headroom 0) | one sentence in Prime Directive #14's first paragraph, paid by one retired restatement | | `.claude/skills/pm-dispatch/SKILL.md` | 815 → 816 | **+1** (ceiling 819, headroom 3) | one rule line in 〈入队与落地〉 | | `.claude/skills/pm-dispatch/references/core-rules.md` | 151 → 151 | **0** | the landing-rule line rewritten in place to carry the twin | | `.claude/skills/pm-dispatch/references/external-contributions.md` | new, 16 lines | +16 (budget ≤ 20; widest line 120 B) | the ruled 〈外部贡献〉 section, four points + the deferred supply-chain line | ### 1. `check-governed-merges.mjs` — the FORK limb - `forkVerdict(pull)` (pure, exported, beside `sizeVerdict`): reads `head.repo.full_name` and `base.repo.full_name` off the PR object; NOT MEASURED when there is no `base.repo` to compare against; a fork when the head repo differs — **or is `null`** (the fork was deleted): a deleted fork is still a fork, fail closed. - `testVerdict(paths, { size, fork, checks })` carries `fork` and `checks`; `humanMerge` fires on any of the three limbs; `landsByHumanMerge` reads the fork limb too, so a fork exits on the EXISTING GOVERNED code (3) through the Tier H terminal — every caller that already routes 3 to the human hand routes a fork there without learning a new code. `applyGeneratedExceptions` keeps the fork limb across a generated-artifact lift (a lift moves a PATH, never the head repo). - `renderForkLines(fork, checks)` (pure, exported): the fork sentence under the verdict — a PROPOSAL, never a delivery, whatever its paths; no AI seat flips it ready, enqueues it, arms auto-merge on it or approves it; a seat's review is required INPUT, never the permission; the owning seat adopts the diff onto an internal branch (`Co-authored-by:` the contributor) and lands THAT; requests to the contributor go only as review comments on the fork PR, which is closed with thanks and the landing link. When the PATH limb is clear the head line reads `paths: none on the register — the HEAD REPO decides this PR:` (the SIZE limb's shape); on a governed diff the sentence rides under the tier block, Tier S included (a fork head on a `.claude/**` path is still adopted, never landed). - `--pr N` reads the head's check-run count off `GET /repos/{slug}/commits/{sha}/check-runs` — one more GET, on the channel already chosen for the PR read. `total_count: 0` prints `check runs on head SHA: 0 — NOT MEASURED, never green` in the register the size limb already uses; a count that did not read prints `NOT READ (reason) — read as NOT MEASURED, never green`; a non-zero count prints nothing. - `--test` and `--branch` cannot see a head repo and now say so on stdout (`head repo: NOT MEASURED — this verdict cannot tell a fork PR from an internal one; --pr N reads it`), the same discipline as the size limb: a verdict silent about a leg it did not run reports a clearance it never measured. The `--branch` / `--test` byte-identity pin still holds (both print the same line). - `--json` carries `fork` and `checks` beside `size`. - Self-test: battery `⭐ the FORK predicate: head repo ≠ base repo is a proposal, never a delivery` (6 cases, floor 6, roster 30 → 31), placed between the SIZE battery and the audit-half battery, never at the tail: fork head on ordinary paths ⇒ H route with the fork sentence and no `ordinary queue landing applies`; `head.repo === null` ⇒ the same; same-repo head on ordinary paths ⇒ unchanged (NOT governed, no fork line); same-repo head on `AGENTS.md` / `.claude/agents/os-dev.md` ⇒ Tier H / Tier S word for word, while a fork head on the Tier S path still prints the fork sentence; no PR object ⇒ NOT MEASURED said; zero check runs ⇒ the NOT-MEASURED line, 43 ⇒ absent, unread ⇒ `NOT READ`; and `fetchPullFiles` against an injected fetch reads the head repo off its own GET and the count off the head sha. Header docblock gains a "The FORK predicate" section; the summary line names the battery. ### 2. `AGENTS.md` — one sentence, net 0 Prime Directive #14, first paragraph, :264 before (102 B): ```text paragraph names fewer surfaces than the register — or more. When it reds, name the surface here. ``` :264–:266 after (113 B / 116 B / 106 B): ```text paragraph names fewer surfaces than the register — or more. When it reds, name the surface here. A fork PR (head repo ≠ base repo) is a proposal, never a delivery, whatever its paths: no AI seat readies, queues, arms auto-merge on or approves it; the owning seat adopts the diff onto an internal branch and lands that. ``` "whatever its paths" is the sentence's shape saying the fork rule is a predicate on the PR, not a surface: the paragraph still names exactly the register's six surfaces and no `**`-shaped span was added, so `pnpm check:pm-governed-prose` stays green (quoted below). **Payment (+2 lines bought by one retired restatement, ⛔ not by the ceiling, not by re-wrap):** the three paragraphs of Prime Directive #14 are greedy-packed already (878 / 1789 / 918 characters joined ⇒ 8 / 16 / 8 lines at the 120-column cap, exactly what they occupy), so re-wrap buys nothing. Retired: the Skills section's line (pre-edit :800, 117 B, plus its trailing blank line): ```text ⛔ **Both roots are governed surfaces** — `skills/` is Tier H, `.claude/skills/` Tier S (**Prime Directive #14**). ``` It restated the register and its tiers, whose home is the directive it pointed at. Surviving home and grep proof on this head: `grep -n 'skills/\*\*' AGENTS.md` → :6 (the CLAUDE-conflict clause), :260 (the register names `.claude/**` and `skills/**`), :273 (Tier H names `skills/**`); `grep -n 'Tier S' AGENTS.md` → :258, :276 (Tier S = all of `.claude/**`), :292; `grep -n 'Both roots' AGENTS.md` → no hits. The Skills section keeps its two-root catalog lines; only the restatement left. ### 3. `SKILL.md` — one rule line in 〈入队与落地〉 (+1, 108 B) Inserted at :643, directly under the section's pointer line (`- 细则见 references/landing-operations.md,落地窗口查阅。`): ```text - fork PR = 提案,席位永不放行;采纳 diff 内部落地,见 `references/external-contributions.md`。 ``` Placement (four axes): **业务需求** — the acts the rule forbids (ready / 入队 / auto-merge / 批准) are the acts this section governs, so a seat reading its landing checklist meets the fork rule where it would otherwise act; **长远合理性** — one rule line, one pointer, the detail in a references file, the same shape as the section's first line; **防 AI 犯错** — the line sits before the 条款② gate and the PASS ⇒ ready ⇒ auto-merge line, so the fork stop is read before the enqueue reflex; **创业阶段不扩散** — ≤ +1, no new section. ⛔ Not in the 分诊 / 定级 region (:174–:175, :362, :368–:372, :379 are #19494's) and not on PR #19488's lines (the `area:*` rows, :119–:134, :215, :243, :259, :294, :310, :371–:372, :470–:471). PR #19513 edits :632–:633 and :647 / :653 of the same section; :643 sits between its two hunks with unchanged context on both sides, so the later lander merges `origin/main` once with no conflict expected. ### 4. `references/core-rules.md` — the twin, paid in place (151 → 151) :122 before (118 B) → after (112 B): ```text - 验收后取路径面,命中规则层即分叉 ⛔ 不翻正式不入队;Tier S 席内达档复核 PASS 后入队。 - 验收后取路径面:规则层 ⛔ 不翻正式不入队,Tier S 达档 PASS 后入队;fork PR 永不放行。 ``` Every landing-rule line in the core subset sat at 111–118 B of the 120 B cap, so the twin could only ride a compression: 「命中…即分叉」 and 「席内…复核」 are folded to 「规则层」 and 「达档」 (the SKILL.md lines they summarise are unchanged), and the freed bytes carry the rule. No clause dropped. PR #19513 and PR #19488 touch :55–:69, :102, :106–:113 of this file, not :122. ### 5. `references/external-contributions.md` — new (16 lines, every line ≤ 120 B) Frame as its siblings (title, a 「见 SKILL.md 〈…〉」 pointer line, one rule per line). Bytes per line: 45 · 0 · 117 · 117 · 0 · 113 · 77 · 97 · 92 · 102 · 110 · 113 · 106 · 113 · 116 · 120. Content, the four points of the ruling in substance: ① card first — triage's fire scans open PRs whose head repo ≠ base repo, files a card from the PR body graded like any card, posts the ONE fixed comment (`this repository works card-first; filed as #N; this PR stays a draft until the card is graded`), a fork PR with no card does not exist on the board; ② the human decides the problem, not the code — a plain reproducible defect routes to a seat, floor items (security / permission boundary, contract, feature) go to the decision box as a business question; ③ the seat adopts the diff, never lands the fork PR — internal branch, cherry-pick or re-implementation, `Co-authored-by:` the contributor, full gate derivation + at-tier review + the queue as for internal work, requests to the contributor only as review comments on the fork PR, closed with thanks and the landing link when the internal PR lands; ④ a fork's CI is never approved to run by a seat, zero check runs read NOT MEASURED, never green; the machine face (`check-governed-merges.mjs --pr N` routes head repo ≠ base repo through the H(人合) exit, `head.repo` null the same); and the deferred supply-chain line. `check-skill-line-ratchet.mjs` does **not** require a CEILINGS row for a new references file (it enumerates only `references/lanes/` for uncovered files; the file is simply outside the ratchet's map, as `references/instrument-discipline.md` on PR #19513 is). No row was added: the ratchet script is outside this card's file surface. Noted under Acceptance notes for the seat. ## The two `--pr 19342` readings Before (origin/main 8fc6a5f), `node scripts/pm/check-governed-merges.mjs --pr 19342 :: exit 0`: ```text governed-surface predicate: 0 of 4 path(s) hit the register (6 surfaces, repo-agnostic). ✅ NOT governed — ordinary queue landing applies to a PR with exactly this file list. Derived from GOVERNED_SURFACES, not recalled. Re-run on the FINAL file list: the register has grown several times in two days, and a reading taken earlier in the session is recall. size: 56 changed line(s) (+48 / -8) ≤ 5000 — under the human-merge threshold (generated files included in the count). ``` After (this head 0a50588), `node scripts/pm/check-governed-merges.mjs --pr 19342 :: exit 3`: ```text governed-surface predicate: 0 of 4 path(s) hit the register (6 surfaces, repo-agnostic). paths: none on the register — the HEAD REPO decides this PR: ⛔ FORK PR — head jinyitao123/objectstack ≠ base objectstack-ai/objectstack: a PROPOSAL, never a delivery, whatever its paths. The Tier H terminal, with its own reason: no AI seat flips it ready, enqueues it, arms auto-merge on it or approves it — ever; a seat's review is required INPUT, never the permission. The owning seat adopts the diff onto an internal branch (`Co-authored-by:` the contributor) and lands THAT through the ordinary gates; requests to the contributor go only as review comments here, and this PR closes with thanks and the landing link. ⚠️ check runs on head 5fa7b6d: 0 — NOT MEASURED, never green: a fork's CI does not run until a maintainer approves it, and a head that never ran looks exactly like one that passed. No seat approves it to run. size: 56 changed line(s) (+48 / -8) ≤ 5000 — under the human-merge threshold (generated files included in the count). ``` `--json` on the same run: `governed: false`, `tier: null`, `humanMerge: true`, `fork: { measured: true, isFork: true, headRepo: "jinyitao123/objectstack", baseRepo: "objectstack-ai/objectstack" }`, `checks: { sha: "5fa7b6dc9d76657a57e30fbcd8010277261254f7", total: 0, reason: null }`. ## Design choices, on the four axes **`head.repo === null` reads as a fork (fail closed).** 实际业务需求: the API returns `head.repo: null` exactly when a contributor deleted the fork after opening the PR — a PR nobody can rebuild the head of is the least reviewable shape a fork PR takes, and the population it comes from is the fork population. 项目长远合理性: the predicate is closed (`head ≠ base`, with an unreadable head on the far side of ≠), so no third state grows beside it. 防 AI 犯错: the alternative — treating an unreadable head as "not a fork" — is a `??` fallback in the consumer that turns a missing fact into a clearance; the fail-closed reading is the loud one, and its words name the deleted repo. 创业阶段不扩散: zero extra code — one `headRepo === null ||` in the predicate, one `(deleted fork repo)` in the words, one self-test case. The one case deliberately left NOT MEASURED rather than forked is a PR object with no `base.repo` at all (a fixture shape, never seen from the API): there is nothing to compare against, and NOT MEASURED is never a clearance either. **Where the SKILL.md line sits** — the four axes are given under §3 above; the 分诊 / 定级 region belongs to #19494 and the feature-axis lines to PR #19488, so the landing section was the only region on the claim. ## PM mechanism assumptions — verified 1. ✅ At 8fc6a5f `check-governed-merges.mjs` had 0 hits for `head.repo` / `author_association` / `FIRST_TIME`; the PR object is fetched in `fetchPullFiles` (`fetchJsonOver` on `GET /repos/{slug}/pulls/{n}`, the read that gives `changed_files` and the size pair), and the proxy returns `head.repo` (`jinyitao123/objectstack` on #19342, `base.repo` `objectstack-ai/objectstack`). The fork limb reads that same object; the check-run count is a second GET on the same channel. 2. ✅ The H route's terminal reads `⚖️ landing tier: H(人合) — the maintainer's hand, or an authorized APPROVED review (GOVERNED_APPROVERS) and then the owning seat lands it`; the SIZE limb's terminal reads `The same terminal as a Tier H governed diff: no seat flips it ready, enqueues it, or arms auto-merge`. The fork sentence keeps the three verbs, adds `approves it`, and adds the adoption step instead of the seat-lands-it clause (a fork PR is never landed by the seat). 3. ✅ AGENTS.md 1109 / 1109; on the unchanged tree `pnpm check:pm-skill-ratchet :: exit 0` and `pnpm check:pm-governed-prose :: exit 0`; on this head both exit 0 again (quoted below). 4. ⏳ `node scripts/pm/check-governed-merges.mjs --pr` on this PR's own number is run after the PR exists; the reading (expected: exit 3, GOVERNED, Tier H — `AGENTS.md` and `skills`-free `.claude/**` on the register, one Tier H path making the whole PR Tier H) goes into the `os-dev-report` comment on the card. This PR stays draft for the maintainer's hand. ## Verification (this head 0a50588) - `node scripts/pm/check-governed-merges.mjs --self-test :: exit 0` — 441 assertions, the new battery registered at its floor; the two `--pr 19342` readings above; `--test README.md :: exit 0` (NOT governed, `head repo: NOT MEASURED` on stdout), `--test AGENTS.md :: exit 3`; `npx eslint scripts/pm/check-governed-merges.mjs :: exit 0`. - The four charter gates, exits captured before any pipe: `pnpm check:pm-skill-ratchet :: exit 0` (AGENTS.md 1109 / 1109 headroom 0; SKILL.md 816 / 819; core-rules.md 151 / 151), `pnpm check:pm-skill-id-lint :: exit 0`, `pnpm check:pm-governed-prose :: exit 0` (2 surfaces name all 6 registered surfaces and claim no others), `pnpm check:nul-bytes :: exit 0`; control-character scan of the five files: 0 hits. - Derived union, `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` with no paths on 0a50588: 44 commands. Every command run in the foreground with its exit captured before any pipe (`cmd > log 2>&1; EXIT=$?`), then reconciled: `node scripts/pm/dispatch-gates.mjs --ran ran-union.txt --repo objectstack-ai/objectstack :: exit 0` — **44 derived, 44 run, 0 NOT-MEASURED, 0 UNRUN**, every exit 0. One family needed its inputs built first: `pnpm --filter @objectstack/lint run check:doc-formula-expressions` answered `PREREQUISITE NOT MET` (exit 3, `@objectstack/formula` then `@objectstack/lint` not built in a fresh worktree) until `pnpm --filter '@objectstack/lint...' build` ran under the shared verification lock (`os-verify-lock.sh`, VERDICT command-exit 0, held 176 s); re-run on the built tree it exits 0 (22 record-scoped examples judged clean). Heavy families in the union (`check-governed-queue-guard.mjs --self-test`, `check:pm-dispatch-gates`, `check-skills-token-ratchet.mjs`) all green. - Local scope per the dispatch: no package's `pnpm test` / `typecheck` is owed — the diff touches no `packages/**` source; `pnpm lint` (the repo-level eslint) is CI's run, the edited script was linted directly. ## 维护者速读(草稿) **改了什么** — 三处一致的规则:fork 上来的 PR(head 仓 ≠ base 仓,含 fork 已删的情况)是提案不是交付。① `check-governed-merges.mjs` 在「路径受管」「改动超 5000 行」之外加了第三个判据「head 是 fork」,命中即走既有的「人合」出口,并打印自己的理由句;`--pr` 同时读 head 上的 check run 数,0 条时打印「NOT MEASURED,不是绿」。② `AGENTS.md` 第 14 条基本原则加一句(行数不变,用 Skills 节里一句重复表述抵付)。③ PM 技能的落地条款加一行,核心条款一行原地改写承接,并新增一页 `external-contributions.md` 写清四步:先立卡、人裁问题、席位采纳 diff 内部落地、fork 的 CI 席位不代批。供应链条款按裁决延后。 **为什么改** — 您 2026-09-21 裁了「fork PR 的处理同意你的意见」。之前合并前防线只看改了哪些文件、只约束我们自己的席位,#19342 那样的外部 PR(OAuth 放宽到明文 HTTP,0 条 CI)按机器判定可走普通队列;现在它被机器点名为提案,任何席位都不能放行。 **风险与代价(含回滚)** — 代价:每张外部 PR 都要您(或授权批准账户)拍板,今天 100 张里 1 张;`--pr` 多一次 API 读。行为变化:`--test` / `--branch` 的输出多一行「head 仓未测」提示,不改退出码。回滚:revert 本 PR 一个 commit 即可,无数据、无迁移。 **席位意见** — (留空,席位定稿时填) **你要做的** — 点合并(Tier H:本 PR 改了 `AGENTS.md`,只由您的手落地)。#19342 本身按同一批裁决由总监席 / 分诊席处置,不在本 PR 内。 ## Acceptance notes - `references/external-contributions.md` carries no CEILINGS row in `check-skill-line-ratchet.mjs` (the ratchet does not require one and the script is outside this card's surface), so the new file is invisible to the line ratchet until pinned; a first pin at the landed count (16) is not a raise. carrier: the `domain:skills` seat. - `--pr N` now spends one extra GET per run (`/commits/{sha}/check-runs?per_page=1`) on the chosen channel; a failed read is carried as `NOT READ (reason)` and never a zero. - `--test` / `--branch` stdout gained the `head repo: NOT MEASURED` line under every verdict — deliberate, mirrors the size limb; a grep reader keyed on `NOT MEASURED` alone now matches on every `--test` run without size flags too (it already did for the size line). - The seat's decision analysis left three confidence gaps open (`pull_request_target` in four workflow files, the MCP merge route against a fork head, fork PR history beyond the newest 100); none is on this card's surface and none was measured here. carrier: the `domain:skills` seat. - PR #19342 is not addressed here; it remains open for the director's / triage's disposal. --- _Generated by [Claude Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent ecf56e7 commit 88920d1

5 files changed

Lines changed: 119 additions & 22 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
640640
### 入队与落地
641641

642642
- 细则见 `references/landing-operations.md`,落地窗口查阅。
643+
- fork PR = 提案,席位永不放行;采纳 diff 内部落地,见 `references/external-contributions.md`。
643644
- 条款②入队闸门:翻 ready / 入队前先取 PR 实际 diff;diff 是事实,卡片语义是预测。
644645
- `--tier` 嫌疑行是提示非裁定;双肢命中任一 ⇒ 无达档条款②复核 PASS 在案 ⛔ 禁止入队。
645646
- 路径肢 = diff 触及契约面 `packages/spec/src/**`,含 error-code-ledger 与 `*.zod.ts` 契约 schema。

‎.claude/skills/pm-dispatch/references/core-rules.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
- 停摆永不自愈,按梯度复位、三次即判不可靠重派;报告丢失时按草稿 PR 直接验收。
120120
- 复核对 GitHub 核验 ⛔ 不对自述核验,逐项过清单并亲核形态、范围与整包价值密度。
121121
- CI 收敛读数只属于复核侧;判决三种:验收落卡、返工最多两轮、升级走决策通道。
122-
- 验收后取路径面,命中规则层即分叉 ⛔ 不翻正式不入队;Tier S 席内达档复核 PASS 后入队。
122+
- 验收后取路径面:规则层 ⛔ 不翻正式不入队,Tier S 达档 PASS 后入队;fork PR 永不放行。
123123
- 受管面 PR 留 draft 并向两个授权批准账户请审;契约卡无同形复核记录 PASS ⛔ 禁止入队。
124124
- 入队资格是每一个检查全绿 ⛔ 不是必查子集;碰生成物的 PR 入队前先同步再重生成。
125125
- 唯一例外:源码自述 pushed 上按设计而红、不跑 `merge_group`、评论记明门与因,三条全立。
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# 外部贡献:fork PR 是提案,不是交付
2+
3+
见 SKILL.md 〈入队与落地〉的 fork PR 行;本文是 fork PR(head 仓 ≠ base 仓)进场到落地的四步。
4+
席位永不翻 ready、入队、挂 auto-merge 或批准它;席位复审是必需输入,⛔ 永不是放行许可。
5+
6+
- ① 先立卡:分诊 fire 扫 open PR 中 head 仓 ≠ base 仓者;无卡的按 PR 正文立卡,常规定级。
7+
- 无卡的 fork PR 在板上不存在;PR 上只贴一条固定评论,原文:
8+
`this repository works card-first; filed as #N; this PR stays a draft until the card is graded`
9+
- ② 人裁的是问题不是代码:普通可复现缺陷路由到席位,不经维护者。
10+
- 地板项(安全/权限边界、契约、功能)作业务问题进决策箱,与任何卡同批裁。
11+
- ③ 席位采纳 diff,永不落地 fork PR:内部分支 cherry-pick 或重写,`Co-authored-by:` 贡献者。
12+
- 门禁推导、达档复核与队列同内部工作;对贡献者的要求只作 fork PR 上的 review 评论。
13+
- 内部 PR 落地后关闭 fork PR,附致谢与落地链接;席位在 fork PR 上只写这两种评论。
14+
- ④ fork 的 CI 席位永不代批准运行;head 上 0 条 check run 读作 NOT MEASURED,⛔ 永不读作绿。
15+
- 机器面:`check-governed-merges.mjs --pr <n>` 对 head 仓 ≠ base 仓走 H(人合)出口;head.repo 为空同。
16+
- 供应链条款(fork 带来的依赖、lockfile、workflow、scripts)延后:第一张此类 fork PR 出现时再立。

‎AGENTS.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,9 @@ localStorage / auth gotchas.
261261
`CLAUDE.md` — the file you are reading is one — and a mixed diff is governed whole on a single path hit. The
262262
register is the `GOVERNED_SURFACES` table in `scripts/pm/check-governed-merges.mjs`, each row carrying its tier;
263263
adding a surface is an edit *there*, never here, and `pnpm check:pm-governed-prose` reds per-PR when this
264-
paragraph names fewer surfaces than the register — or more. When it reds, name the surface here.
264+
paragraph names fewer surfaces than the register — or more. When it reds, name the surface here. A fork PR
265+
(head repo ≠ base repo) is a proposal, never a delivery, whatever its paths: no AI seat readies, queues, arms
266+
auto-merge on or approves it; the owning seat adopts the diff onto an internal branch and lands that.
265267

266268
**Authoring stays open to every seat** — drafting, pushing, opening and revising the PR. What is reserved is the
267269
**landing**: on a PR whose diff touches a governed surface ⛔ never merge, ⛔ never queue, ⛔ never arm
@@ -797,8 +799,6 @@ working in its domain — browse the directory, never a hand-written list here:
797799
- `.claude/skills/` — repo-internal agent playbooks; every entry must carry
798800
`metadata.internal: true`.
799801

800-
⛔ **Both roots are governed surfaces** — `skills/` is Tier H, `.claude/skills/` Tier S (**Prime Directive #14**).
801-
802802
---
803803

804804
## Patterns

0 commit comments

Comments
 (0)