Skip to content

Commit 2ec4f43

Browse files
pm-dispatch(security): a finder reports a security finding through the security channel and never fixes it in place (#29939)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} --> _Requested by **Yibo Wang** · [project thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBQiV7K7TN7pm6wRVsEya1vr)_ Fixes #29731 Clause-②: no Metadata-protocol: none **Rules text only.** Two governed `.claude/**` files and the line-ratchet map; nothing published moves (`skip-changeset`). No finding, no mechanism and no example that encodes one is in this diff. ## 维护者速读 - **改了什么**:安全发现规则加一条「只报不修」:发现者不扩当前 PR 或分支、不自开修复分支、不在同一面顺手加固;dev 只经终报私有字段上报,席位与 QA runner 经中继建草稿公告再敲门;任务绕不开那条代码路径时报 `blocked`,只写一句不透明原因,席位停卡,不绕行;修复只由 `security#1` 席以无卡派发令派出。os-dev.md 只留一行指针。 - **为什么改**:你 2026-11-03 的原话「开发中遇到的问题应该通过安全通道上报而不是直接处理」。原文只写了安全发现写到哪,没写不能在手头任务里顺手修;就地修会把机制经 diff、PR 与 changeset 公开,也绕过了归属席。 - **风险与回滚**:只动规则文字,无代码无发布面;回滚即还原本 PR。`security-findings.md` 上限 62 → 64,按棘轮头部的裁决记录路径抬,配额注释引你的原话。 - **先看**:`security-findings.md` 第 60–64 行(§9,新规则),第 28 行(§3,修复只由该席派);`os-dev.md` 第 49 行(指针);`check-skill-line-ratchet.mjs` 的 CEILINGS 行。 - **两分钟验证**:`pnpm check:pm-skill-ratchet && pnpm check:pm-skill-id-lint`,预期两条都 ✓(文件 64/64 行,每行 ≤120 字节)。 - **需要你做的**:无,席位落地(Tier S,`.claude/**` 内)。 ## What changes **`.claude/skills/pm-dispatch/references/security-findings.md`** (62 → 64 lines, every line ≤ 120 bytes): - **§9 归属, the new rule (Wanted 1).** Line 60 now ends 「发现者只报不修」 in place of the old 「⛔ 不归发现者」 (ownership by `security#1` plus "report, never fix" says the same thing with one word fewer). A new line 61 states what "never fix in place" forbids: no widening of the PR or branch in hand, no own fix branch, no hardening on the same surface; and names the dev's channel, §5's private field. Line 62 is the old finder line narrowed to the seat and QA runner: the relay `advisory_create` draft plus the `Notify: security · GHSA-ID` doorbell carrying the id alone. Line 63 (relay refused ⇒ `security#1` in session, maintainer while vacant) is unchanged. - **§9, the blocked rule (Wanted 2).** New line 64: when the task in hand cannot proceed without that code path, the finder reports `blocked` with the one opaque cause line 「a security item is with the owner seat」 and nothing else; the seat parks the card; ⛔ no workaround. - **§3 line 28, folded.** 「修复经 pm-dispatch 以无卡派发令派 `os-dev`」 becomes 「修复只由 `security#1` 席以无卡派发令派 `os-dev`」 — the "fix comes only from the owner seat's no-card order" clause of Wanted 1, carried by the line that already described the fix dispatch, so §9 does not restate it. **`.claude/agents/os-dev.md`** (405 lines, unchanged count): rule 3's pointer line 49 is rewritten in place, 114 B → 116 B — 「安全发现 ⛔ 不就地修,只经终报私有字段 `security_findings` 上报,照 `security-findings.md`」. The old clause 「不进本字段」 is carried by 「只经 … 上报」 (only via the private field ⇒ not via `out_of_scope_findings`, which §5 and the JSON template also state). One pointer, no second copy (§8). **`scripts/pm/check-skill-line-ratchet.mjs`**: the `security-findings.md` CEILINGS row moves 62 → 64 with its row comment quoting the ruling of record and the measured delta (next section). ### The ceiling raise, and why it is not paid by deletion The order says fold first, pay by deletion second, raise only if the ratchet header admits this card's verbatim maintainer word as the ruling of record. Folding took two of the four sentences (dev's route into the prohibition line; fix-only-by-order into §3 L28). The remaining two rules — the prohibition itself and the blocked rule — are new facts no existing line can carry under the 120-byte cap, and every line of the file is a distinct rule, so there is no stale text to delete without dropping a rule the card did not retire. The header's raise path: "RAISING one is authorized by the RULING OF RECORD that orders text into the file … the raising PR quotes that ruling comment's id and the measured line delta in its body". The two previous raises on this very row (55 → 56 and 56 → 62) cite the card body filed under the maintainer's verbatim as that ruling. This card is filed under gate ③ (a rule the maintainer stated) with the verbatim 「开发中遇到的问题应该通过安全通道上报而不是直接处理」; its body is the ruling of record, and the row comment quotes it. **Raise: `security-findings.md` 62 → 64, measured delta +2.** No other CEILINGS entry moves; not a `CROSS_FILE_MOVES` destination, so no `ruledRaises` record applies. `os-dev.md` stays at 405/405 (one line rewritten in place). ## Why `os-dev.md` L49 and `security-findings.md` §5 said *where* a dev writes a security finding and nothing about not fixing it inside the task in hand. A finder that fixes in place leaks the mechanism through the diff, the PR and the changeset, and bypasses the owner seat that §9 (PR #29695) made responsible from intake to publish. The maintainer's word on 2026-11-03 is quoted above; this PR records it once, where the finders read. ## Tests None owed: prose in two `.claude/**` files and a data row in a gate script's map. The gate script's own `--self-test` ran (Verification). ## Acceptance notes - **Two choices a reviewer may push back on.** (1) 「任务绕不开它 ⇒ 报 `blocked`」 names no actor — the card says "the dev stops", but a seat or QA runner meets the same wall, and 「dev 停下」 did not fit the byte cap beside the fixed cause phrase. (2) The old 「⛔ 不归发现者」 on L60 is gone; ownership by `security#1` plus 「发现者只报不修」 carries it. - **A pre-existing inconsistency left alone (out of scope, carrier: the skills seat).** §3 L25 and §4 L33 still route a relay refusal to the maintainer directly (「机制只在会话里交维护者」), while §9 L63 (PR #29695) routes it to `security#1` first and to the maintainer only while the seat is vacant. Rule-level wording drift from the owner-section PR, not this card's; noted, not filed. Dedupe words: security-findings §4 §9 relay refused maintainer security#1. - **Attribution thread link.** The order file spells the skills-lane thread; this body carries this card thread's link because the session's own attribution rule names it. Same project, same requester. - **Changeset:** none — `scripts/pm/**` and `.claude/**` publish nothing; `skip-changeset` sent on the `pr_create` stroke. - Out-of-scope findings beyond the one above: none. Security findings: none. ## Verification Head: `c3118489` (branch `claude/project-thread-26bz62`, on `origin/main` `21510bba`; the merge is a no-op, main did not move). **Derived set:** `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` → 40 commands (30 by path, 2 by change kind, 8 whole-tree). Every one ran in this worktree; exit codes captured before any pipe into a `CMD :: exit N` file; `--ran` reconciliation: ✓ 40 derived families accounted for — 40 run, 0 NOT-MEASURED. - `pnpm check:pm-skill-ratchet` → exit 0 (security-findings.md 64/64, os-dev.md 405/405; every line ≤ 120 bytes). - `pnpm check:pm-skill-id-lint` → exit 0 (109 files clean). - `pnpm check:skill-frame-sync` → exit 0. - `node scripts/pm/check-skill-line-ratchet.mjs --self-test` → exit 0 (164 cases pass; the touched script's own suite, outside the derived set). - `pnpm --filter @objectstack/lint run check:doc-formula-expressions` → first run exit 3 (PREREQUISITE NOT MET: `@objectstack/formula` and `@objectstack/lint` not built); after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under the verify lock (VERDICT command-exit 0, 110 s) → exit 0. - The other 35 derived commands (`check:pm-dispatch-gates`, `check:pm-governed-merges`, `check:nul-bytes`, `check:doc-authoring`, `check:commit-card-trailers`, the `--self-test` pairs, …) → exit 0 each; the full `CMD :: exit N` list is in the `os-dev-report` comment's `gates` field. Not run locally, CI's own: `pnpm lint` (repo-wide), the type-check lanes, `Test Core` / `Build Core`. No package test is owed: no package source moved. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. (no names added) - [ ] 3. No formatter ran; `pnpm lint` passes. (no formatter ran; the repo-wide `pnpm lint` scan is CI's own run under the os-dev local-scope rule, so it is not claimed here — read the PR's `Lint & Repo Gates` check-run) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (publishes nothing: `skip-changeset`) - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. (not touched) - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the maintainer's ruling is quoted verbatim, untranslated). - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01WGufzfz49TMMdiSJVgkdAf)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent ed0ab75 commit 2ec4f43

3 files changed

Lines changed: 14 additions & 6 deletions

File tree

‎.claude/agents/os-dev.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ model: opus
4646
- (c) 让 AI 写出运行时拒收或静默丢弃的元数据的陷阱;三类内 ⛔ 不因看着小揣着不报。
4747
- 三类同欠 `reach:`:公开入口(HTTP/界面/`os validate`/保存)一次实测错误,或具名真实生产者。
4848
- 例外两种照报,`reach:` 写明哪种:发版即固化的错误文字;维护者直派。
49-
- 安全发现 ⛔ 不进本字段,只进终报私有字段 `security_findings`,照 `security-findings.md`。
49+
- 安全发现 ⛔ 不就地修,只经终报私有字段 `security_findings` 上报,照 `security-findings.md`。
5050
- (c) 元数据 = 他人存储并再作者化的键,须具名生产者:React prop 不是,存储视图配置是。
5151
- 把作者引向运行时会兑现却让事情更糟的元数据的警告不在 (c) 内,记为边界不扩类。
5252
- 其余 ⛔ 不立卡:只读推断、观察、休眠、零拉动、死代码、未演练漂移、抛光、命名。
@@ -67,7 +67,7 @@ model: opus
6767
- 归挂不散落:落在已排队 issue 范围内的发现,报告点名为它的 sub-issue(自动进派发池)。
6868
- 只是依赖它的,报告点名独立单带 `Blocked-by:` 行;立在修复落地的仓,带回链;席位代立。
6969
- 有界就地修豁免,四条全立才就地修:① 与本卡同一缺陷类;② 机械修且形态已被钉死。
70-
- ③ 该文件无其他认领持有;④ 同一批门禁族,不新增验证面。
70+
- ③ 该文件无其他认领持有;④ 同一批门禁族,不新增验证面;安全发现不适用。
7171
- 就地修欠两样:认领申报的文件面同轮增补;PR 正文点名该修复并附证据。
7272
- 优先扩展一个守卫关掉整个类;任一条不成立 ⇒ 回默认:报告列出交席位立单、不碰。
7373
- 本轮改动令其变假或触碰的已发布缺陷必修;其余立卡并记明已发布面,PR 照常落地。

‎.claude/skills/pm-dispatch/references/security-findings.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
- 两操作皆被拒 ⇒ 会话专递(选 A):机制只在会话里交维护者,由其建草稿,⛔ 不换账号重发。
2626
- 私有仓无私密漏洞报告功能,那些操作上线后仍会话专递。
2727
- 回退时座位贴只写不透明编号与状态,⛔ 无细节。
28-
- 修复经 pm-dispatch 以无卡派发令派 `os-dev`,`xhigh`;机制只进派发令与公告。
28+
- 修复只由 `security#1` 席以无卡派发令派 `os-dev`,`xhigh`;机制只进派发令与公告。
2929
- 用到公告的临时私有 fork ⇒ 修复从该 fork 落地。
3030

3131
## 4. 跨仓发现者(应用仓量框架、cloud 席位)
@@ -57,6 +57,8 @@
5757

5858
## 9. 归属:`security#1` 席
5959

60-
- 每份安全发现从接收到发布归 `security#1` 席(章程 `lanes/security.md`),⛔ 不归发现者。
61-
- 发现者只做两件:经中继 `advisory_create` 建草稿;向该席敲 `Notify: security · GHSA-ID`,只带编号。
60+
- 每份安全发现从接收到发布归 `security#1` 席(章程 `lanes/security.md`),发现者只报不修。
61+
- ⛔ 不扩本 PR 或分支,不自开修复分支,不在同一面顺手加固;dev 只走第 5 节上报。
62+
- 席位与 QA runner 两件事:中继 `advisory_create` 建草稿;敲 `Notify: security · GHSA-ID`,只带编号。
6263
- 中继拒(第 3 节)⇒ 机制在会话里交 `security#1` 席;席空缺 ⇒ 交维护者;发布恒归维护者。
64+
- 任务绕不开它 ⇒ 报 `blocked`,只写「a security item is with the owner seat」;席位停卡,⛔ 不绕行。

‎scripts/pm/check-skill-line-ratchet.mjs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,13 @@ export const CEILINGS = new Map([
13321332
// §8's pointer list in place. Ruling of record: that card's body, filed under the maintainer's verbatim
13331333
// 「设 security#1 座位」, and its amendment comment 6592303181 (「这个应该算一个车道吧?…」) naming this file's
13341334
// new section. Measured delta +6 (56 → 62 lines); landed count, headroom 0.
1335-
['.claude/skills/pm-dispatch/references/security-findings.md', 62],
1335+
// 62 → 64 (#29731): the finder reports and never fixes in place — no widening of the PR or branch in hand, no
1336+
// own fix branch, no hardening on the same surface — and the task that cannot proceed without that code path
1337+
// stops as `blocked` with the opaque cause line while the seat parks the card. Ruling of record: that card's
1338+
// body, filed under the maintainer's verbatim 「开发中遇到的问题应该通过安全通道上报而不是直接处理」. The
1339+
// dev's route and the fix-only-by-order sentence folded into existing lines (§9 L60, §3 L28). Measured
1340+
// delta +2 (62 → 64 lines); landed count, headroom 0.
1341+
['.claude/skills/pm-dispatch/references/security-findings.md', 64],
13361342
['.claude/skills/pm-dispatch/references/external-contributions.md', 22],
13371343
['.claude/skills/pm-dispatch/references/reading-discipline.md', 37],
13381344
// Lowered 51 → 47 by #25712 item 4: objectui stopped being a sister repo, so

0 commit comments

Comments
 (0)