Repository navigation
Commit d8785b4
docs(pm-dispatch): the security lane — a security#1 seat owns every security finding; its charter, the Notify: security doorbell and the seat signature (#29695)
domain:skills#2 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj
Part of #29665 — the lane text, the owner section, the triage hand-over,
the `Notify: security` doorbell and the seat signature land here; the
seat post is the seating session's act, so this PR does not close the
card.
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:新增 `security` 车道与 `security#1` 席——章程
`references/lanes/security.md`、`security-findings.md` 第 9
节「归属」、分诊转交两行、信箱新键 `Notify: security · GHSA-ID`、SKILL.md 域车道表一行、席位签名接受
`security#N`。
- 为什么改:维护者裁定「设 security#1 座位」并补「这个应该算一个车道吧」;此前安全发现谁发现谁处理,无台账、无归属。
- 风险与回滚:纯规则文本与 PM 工具脚本,不发布任何包,回滚即 revert 本 PR;风险 hunk 是签名正则多接受一个词
`security`(`check-half-states.mjs` 与 `fleet-roster.mjs` 各一处),自测已钉非车道词仍拒。
- 先看:① `scripts/pm/record-recognisers.mjs`(新键、读法与自测行);②
`scripts/pm/check-half-states.mjs` 的 `SIGNATURE_LANE_SOURCE`;③
`references/lanes/security.md`。
- 两分钟验证:`pnpm check:pm-record-recognisers`,预期四个自测全绿,且 `node
scripts/pm/record-recognisers.mjs --mailbox-keys` 第 32 行起打印 `Notify:
security · GHSA-ID` 与「finder → security#1」行。
- 需要你做的:无,席位落地(Tier S,达档复核 PASS 后由席位入队)。
## What changes
- `references/lanes/security.md` (new, 34 lines): the lane charter — who
sits it, intake, the opaque ledger and its five states, the no-card fix
order at `xhigh`, rule-level review, the §7 take-over, hand-over at
sign-off. Pointers only: every never-public rule stays in
`security-findings.md` (§8 「一处成文」 holds), and the text names no finding,
no advisory, no path, no object and no mechanism.
- `references/security-findings.md`: §9 「归属」 names `security#1` as the
owner from intake to publish, the finder's two acts (a relay
`advisory_create` draft, one opaque-id doorbell) and the relay-refused
fallback; §8's pointer list gains the security lane in place. +6 lines.
- `references/lanes/triage.md`: push ① stays; then triage forwards to
`security#1` and stops, grading nothing past `security` + p1 on a public
card; while the seat is vacant, today's §7 handling. +2 lines.
- `references/project-forms.md` 〈信箱 PR〉: the `Notify: security` row
(finder → `security#1`, the opaque id only); the 不敲 line keeps the
mechanism, paths and object names out. +1 line.
- `SKILL.md`: one 域车道 row for `security` (266 bytes against the 341-byte
row pin), spelled from the amendment's text "security findings (no file
surface; fixes land in the owning package via no-card orders)". Line
count unchanged at 319 — the ratchet note below.
- `scripts/pm/record-recognisers.mjs`: `MAILBOX_KEYS` row
`notify:security`, template `Notify: security · GHSA-ID`; its reader
accepts the GHSA id alone (`ADVISORY_ID_REF`, mirrored from the relay's
`GHSA_ID_SHAPE` in `fleet-write/ops.mjs` and held equal by a self-test
row, the way `SESSION_SHAPE` already is); self-test rows for the
reading, for the refusals (free text, a second field, a path, a card
number, an upper-case or short id, no id at all) and the roster count 14
→ 15. `--mailbox-keys` prints it.
- `scripts/pm/check-half-states.mjs`: `SIGNATURE_LANE_SOURCE` admits
`security`; the banner lists it. `scripts/pm/fleet-roster.mjs`: the
mirrored pattern admits `security` and `security#1` joins the
`signedSeatOf` corpus; the byte-equality pin already holds the two
copies together. Self-test rows in `record-recognisers.mjs`: `security#1
· …` reads, `reviewer#1` / `finder#1` stay refused, `signatureRefusal`
returns no row for the security seat.
- `scripts/pm/mailbox-open.mjs` (patch round, surface extended by the
seat): `SEAT_BARE_LANES` admits `security` — the third copy of the lane
grammar, which the doorbell `To:` line, every `LANE#N` key field and the
mailbox slug read through; the header's closed-set sentence names three
and points at `SIGNATURE_LANE_SOURCE` as the list it must stay in step
with; `seatKey` self-test rows pin `security#1` → key `security#1` /
slug `security-1`; `domain:security` is reserved. The `Notify: security`
self-test row now rings under `To: security#1`.
- `scripts/pm/check-skill-line-ratchet.mjs`: `CEILINGS` rows
`security-findings.md` 56 → 62, `project-forms.md` 55 → 56,
`lanes/triage.md` 15 → 17, new `lanes/security.md` 34 with its
`MAX_TABLE_ROW_BYTES` pin 0; `SKILL.md` unchanged at 319. This file was
not on the claim's file surface: the order's ratchet clause ("raise the
cap by citing the ruling record") lives only in this map, and a new lane
file reds `laneRosterVerdict` without a row, so its data rows were
edited and the addition is declared in the report's `deviations`.
### The ratchet, and the one row paid by deletion
Ruling of record for every raised row: the card body (maintainer,
verbatim 「设 security#1 座位」) and the amendment comment 6592303181
(maintainer, verbatim 「这个应该算一个车道吧?虽然你不需要打标签,应该也有处理的规则需要写入skills」), which
orders one row in SKILL.md's lane table and the lane's rules in skills.
Measured deltas: `security-findings.md` +6, `project-forms.md` +1,
`lanes/triage.md` +2, `lanes/security.md` new at 34, `SKILL.md` +0.
`SKILL.md`'s row was PAID BY DELETION, the PM's preferred route: the 红线
「⛔ 未经人工的发布痕迹按事故立案,不代跑补救性发布;机械通道存在不构成授权。」 restated two sentences of
AGENTS.md Prime Directive #15 (a publish nobody ordered is filed as an
incident, never counter-published; the existence of a path to a release
is not authorization to walk it), which outranks this file (SKILL.md
优先序: AGENTS.md > 红线) and whose preceding 红线 already defers the release
list to AGENTS.md; the landed precedent is the two 红线 paid the same way
for the external-text rule. No re-wrap funded anything; the meaning of
SKILL.md is unchanged because the rule still binds every seat from
AGENTS.md.
## Tests
Round 1 at head 3868301; the patch round at head 4181cc2 re-ran the
same 58 derived families (identical list) and adds `node
scripts/pm/mailbox-open.mjs --self-test` :: exit 0 — `✓ mailbox-open
self-test: 82 cases in 10 batteries pass`. Each exit captured before any
pipe.
- `node scripts/pm/record-recognisers.mjs --self-test` :: exit 0 — `✓
record-recognisers self-test: 355 cases pass` (the new rows: the
`Notify: security` reading, its six refusals, the roster at fifteen,
`security#1` in the signature lanes, the non-lane words refused, the
`GHSA_ID_SHAPE` mirror held equal).
- `node scripts/pm/fleet-roster.mjs --self-test` :: exit 0 — `✓
fleet-roster self-test: 104 cases in 9 batteries pass` (the mirrored
pattern byte-equal to `SEAT_SIGNATURE_LINE`; `security#1` in the
corpus).
- `node scripts/pm/check-half-states.mjs --self-test` :: exit 0 — `✓
check-half-states self-test: 5166 cases pass`.
- `node scripts/pm/record-recognisers.mjs --mailbox-keys` :: exit 0 —
header `ONE of these 15 keys`; lines 32–33: `Notify: security · GHSA-ID`
/ `the finder — any seat, dev or QA runner → security#1; its relay
advisory_create draft landed; the opaque advisory id ALONE — never a
mechanism, a path or an object name`.
- `pnpm check:pm-skill-ratchet` :: exit 0 — `✓ check-skill-line-ratchet
self-test: 164 cases pass`; every file at its ceiling,
`lanes/security.md is 34 lines (ceiling 34; headroom 0)`, `SKILL.md is
319 lines (ceiling 319; headroom 0)`, `SKILL.md: widest table row is 341
bytes (pin 341)`.
- `pnpm check:pm-skill-id-lint` :: exit 0 — `✓ check-skill-id-lint: 109
file(s) clean`.
- No ablation: no tested runtime behaviour changed; the readers' new
branches are pinned by the self-test rows above (a reader that refused
`security` would red the signature row; a `MAILBOX_KEYS` row without its
reader would red the roster row).
Readings behind the change, taken with the modules at the base fc55892
(the PM's reading, confirmed): `signatureRefusal('security#1 · os-justin
· session_…')` returns a refusal row and `domain:security#1 · …` returns
null; `readSignatureLine('security#1 · …')` is null. At this head both
the bare `security#1` line reads and `signatureRefusal` returns null for
it.
## Acceptance notes
- **Three copies of the lane grammar, kept in step by text alone.**
`SEAT_BARE_LANES` (`mailbox-open.mjs`) is held in step with the two
signature patterns (`check-half-states.mjs` `SIGNATURE_LANE_SOURCE`,
`fleet-roster.mjs` `SIGNATURE_LINE`) only by its header sentence; the
`fleet-roster` self-test pins the two patterns byte-equal and nothing
pins the third. Evidence: `coordinator` is in both patterns and absent
from `SEAT_BARE_LANES`, so a coordinator seat can sign but not be
addressed. Out of scope here; the seat judges whether it needs a card.
- `pnpm --filter @objectstack/lint run check:doc-formula-expressions`
from the derived list: exit 3 in the derived loop (PREREQUISITE NOT MET:
`@objectstack/formula` and `@objectstack/lint` unbuilt, nothing
measured), then measured after a locked build of the two
(`os-verify-lock.sh`: `VERDICT command-exit 0 · held the lock 1s ·
waited 465s`): re-run :: exit 0 (its five self-test cases and the sweep
green).
- PR #29656 (`advisory_read` holds its sender to target-write) is merged
at this base; the charter points at the relay read and does not restate
the gate.
- `test:repo` (the vitest `repo` project) is CI's (`Test Core`), not run
locally; this diff touches no package, so step ① (the dependency
closure) is empty.
- Changeset: none — `.claude/**` and `scripts/pm/**` ship in no package
(AGENTS.md fast path), so `skip-changeset` is declared on the create.
## Verification
Patch round, head 4181cc2 (after
merging `origin/main` 2ea6042, no conflict): 58/58 derived families at
exit 0 after the locked build; `--ran` 58 run / 0 NOT-MEASURED. Round 1
follows.
Derived gate families (`node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack`, derived from the tree at fc55892 /
3868301): 58 commands; 57 at exit 0, one at exit 3 before the build
above. Reconciliation `--ran`: `58 derived famil(ies) accounted for — 58
run`. Model tier line from `--tier`: `MANDATORY: claude-fable-5-1`
(clause ①, SKILL.md is the PM dispatch skill main file). Changed lines
122 (+108 / −14) vs the human-merge threshold 3000: under.
`check:pm-governed-prose` exit 0 (SKILL.md still names all 13 governed
surfaces); `check:skill-frame-sync` self-test and gate exit 0.
<details><summary>Derived gate commands and exit codes (58)</summary>
```text
exit 0 · node scripts/check-closing-keyword-parity.mjs
exit 0 · node scripts/check-closing-keyword-parity.mjs --self-test
exit 0 · node scripts/check-comment-mask-corpus.mjs
exit 0 · node scripts/check-declaration-mirrors.mjs
exit 0 · node scripts/check-declaration-mirrors.mjs --self-test
exit 0 · node scripts/check-issue-citations.mjs
exit 0 · node scripts/check-platform-checklist-watchdog.mjs
exit 0 · node scripts/check-platform-checklist-watchdog.mjs --self-test
exit 0 · node scripts/check-release-section-coverage.mjs
exit 0 · node scripts/check-release-section-coverage.mjs --strict
exit 0 · node scripts/check-self-test-wired.mjs
exit 0 · node scripts/check-self-test-wired.mjs --self-test
exit 0 · node scripts/check-self-test-workflow-commands.mjs
exit 0 · node scripts/check-self-test-workflow-commands.mjs --self-test
exit 0 · node scripts/check-whole-set-label-write.mjs
exit 0 · node scripts/check-whole-set-label-write.mjs --self-test
exit 0 · node scripts/ci/plan-test-core-shards.mjs --self-test
exit 0 · node scripts/ci/scheduled-full-run.mjs --self-test
exit 0 · node scripts/pm/bare-root-worklist.mjs --self-test
exit 0 · node scripts/pm/board-snapshot.mjs --self-test
exit 0 · node scripts/pm/check-governed-queue-guard.mjs --self-test
exit 0 · node scripts/pm/check-harness-current.mjs --self-test
exit 0 · node scripts/pm/sweep-closed-cards.mjs --self-test
exit 0 · node scripts/render-release-coverage-anchor.mjs --self-test
exit 3 · pnpm --filter @objectstack/lint run check:doc-formula-expressions
exit 0 · pnpm check:agent-test-spelling
exit 0 · pnpm check:bash32-floor
exit 0 · pnpm check:ci-filter-parity
exit 0 · pnpm check:cli-command-ids
exit 0 · pnpm check:closing-target-claim
exit 0 · pnpm check:commit-card-trailers
exit 0 · pnpm check:cross-package-test-inputs
exit 0 · pnpm check:doc-authoring
exit 0 · pnpm check:driver-memory-census
exit 0 · pnpm check:entry-guard
exit 0 · pnpm check:gitlink-declared
exit 0 · pnpm check:issue-citations
exit 0 · pnpm check:nul-bytes
exit 0 · pnpm check:parse-guard
exit 0 · pnpm check:partof-closing-keyword
exit 0 · pnpm check:platform-checklist
exit 0 · pnpm check:pm-dispatch-gates
exit 0 · pnpm check:pm-expected-skips
exit 0 · pnpm check:pm-governed-merges
exit 0 · pnpm check:pm-governed-prose
exit 0 · pnpm check:pm-half-states
exit 0 · pnpm check:pm-post-stamped
exit 0 · pnpm check:pm-record-recognisers
exit 0 · pnpm check:pm-skill-id-lint
exit 0 · pnpm check:pm-skill-ratchet
exit 0 · pnpm check:pnpm-filter-targets
exit 0 · pnpm check:pnpm-flag-spellings
exit 0 · pnpm check:ratchet-remedy-authority
exit 0 · pnpm check:refd-timer-probe
exit 0 · pnpm check:scripts-symbol-anchors
exit 0 · pnpm check:single-claim-paths
exit 0 · pnpm check:skill-frame-sync
exit 0 · pnpm check:watch-hint-literal
```
</details>
<details><summary>Ratchet verdict lines for the touched files</summary>
```text
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md: widest table row is 341 bytes (pin 341; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 319 lines (ceiling 319; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/security-findings.md is 62 lines (ceiling 62; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/project-forms.md is 56 lines (ceiling 56; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/lanes/triage.md is 17 lines (ceiling 17; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/lanes/security.md: widest table row is 0 bytes (pin 0; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/lanes/security.md is 34 lines (ceiling 34; headroom 0).
```
</details>
Governed surface: `.claude/**` is Tier S — this PR stays draft until a
contract-review-tier review PASS at its final head; no reviewer
requested, not readied.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QSeKYn5CmmdShCJifm6WYj)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0b2b309 commit d8785b4
10 files changed
Lines changed: 125 additions & 28 deletions
File tree
- .claude/skills/pm-dispatch
- references
- lanes
- scripts/pm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
34 | 33 | | |
35 | 34 | | |
36 | 35 | | |
| |||
163 | 162 | | |
164 | 163 | | |
165 | 164 | | |
| 165 | + | |
166 | 166 | | |
167 | 167 | | |
168 | 168 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
48 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1255 | 1255 | | |
1256 | 1256 | | |
1257 | 1257 | | |
1258 | | - | |
| 1258 | + | |
1259 | 1259 | | |
1260 | 1260 | | |
1261 | 1261 | | |
| |||
1279 | 1279 | | |
1280 | 1280 | | |
1281 | 1281 | | |
1282 | | - | |
| 1282 | + | |
1283 | 1283 | | |
1284 | 1284 | | |
1285 | 1285 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
403 | 403 | | |
404 | 404 | | |
405 | 405 | | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
406 | 413 | | |
407 | 414 | | |
408 | 415 | | |
| |||
1308 | 1315 | | |
1309 | 1316 | | |
1310 | 1317 | | |
1311 | | - | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
1312 | 1324 | | |
1313 | 1325 | | |
1314 | 1326 | | |
| |||
1425 | 1437 | | |
1426 | 1438 | | |
1427 | 1439 | | |
1428 | | - | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
1429 | 1447 | | |
1430 | 1448 | | |
1431 | 1449 | | |
| |||
1490 | 1508 | | |
1491 | 1509 | | |
1492 | 1510 | | |
| 1511 | + | |
| 1512 | + | |
| 1513 | + | |
| 1514 | + | |
| 1515 | + | |
| 1516 | + | |
| 1517 | + | |
| 1518 | + | |
1493 | 1519 | | |
1494 | 1520 | | |
1495 | 1521 | | |
| |||
1547 | 1573 | | |
1548 | 1574 | | |
1549 | 1575 | | |
1550 | | - | |
| 1576 | + | |
| 1577 | + | |
| 1578 | + | |
| 1579 | + | |
| 1580 | + | |
| 1581 | + | |
| 1582 | + | |
1551 | 1583 | | |
1552 | 1584 | | |
1553 | 1585 | | |
| |||
2334 | 2366 | | |
2335 | 2367 | | |
2336 | 2368 | | |
| 2369 | + | |
2337 | 2370 | | |
2338 | 2371 | | |
2339 | 2372 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
297 | 297 | | |
298 | 298 | | |
299 | 299 | | |
300 | | - | |
| 300 | + | |
301 | 301 | | |
302 | 302 | | |
303 | 303 | | |
| |||
735 | 735 | | |
736 | 736 | | |
737 | 737 | | |
738 | | - | |
| 738 | + | |
739 | 739 | | |
740 | 740 | | |
741 | 741 | | |
| |||
826 | 826 | | |
827 | 827 | | |
828 | 828 | | |
829 | | - | |
| 829 | + | |
830 | 830 | | |
831 | 831 | | |
832 | 832 | | |
| |||
0 commit comments