Skip to content

Commit 03e898c

Browse files
qa(checklist-test): writes through the pm-dispatch doors, every defect filed in the run, auth/authz fixes dispatched at once (#26567)
Refs #25807 ## 维护者速读 - **改了什么:** checklist-test 技能和它的协议孪生 RUNNER.md 写进了你在 18.2.0 第二轮测试里定的四条:QA 运行不走车道认领;GitHub 写入只走 pm-dispatch 写入门;测试中遇到的每个产品问题同一轮立 issue;认证/授权类问题立不含细节的卡并立即派 os-dev 修复、不等维护者。另外把清单项 records-forms.record-discussion-mentions 补成 #26497 修复后的口径(被 @ 的人要能读评论本身)。 - **为什么改:** 这一轮 5 个云卡跑完后写入被拦、安全问题等裁决,规则不写进技能下一轮还会重演;清单项不改,下一轮跑这一项会按旧口径误判。 - **风险与回滚:** 只改内部技能文本、QA 协议文档和一条清单项,不改任何产品代码或发布包;回滚即 revert 本 PR。 - **先看:** `.claude/skills/checklist-test/SKILL.md` 的 §2 新 bullet、§4 写入门段、Guardrails 两条;`RUNNER.md` 规则 2 的 carve-out 段。 - **两分钟验证:** `node scripts/check-platform-checklist.mjs` 绿;`node scripts/check-doc-authoring.mjs`、`node scripts/pm/check-skill-id-lint.mjs` 绿。 - **需要你做的:** `.claude/**` 是受管面(Tier S),这是 PM 自己的工具 PR,按约定留给你审阅合并。 ## What changes - `.claude/skills/checklist-test/SKILL.md` - §2: a QA run is not a lane card; runners (subagents, or one cloud session per card) are dispatched directly by the session that starts the round. - §4: every GitHub write of a run goes through the `scripts/pm/` doors (`issue-create`, `post-stamped`, `close-cards`, behind `write-pace`; the fleet relay in a cloud container); a refused write is not worked around — the texts go to files and are posted in order once cleared. - Guardrails: every product defect a run meets is filed in the same run; an auth/authz finding gets a withheld-detail card and its fix is dispatched at once through pm-dispatch (in-seat `os-dev`, reproduction only in the dispatch prompt). - `docs/qa/platform-checklist/RUNNER.md`: rule 2's carve-out and the extraction clause carry the same rule (one rule, both places). - `docs/qa/platform-checklist/areas/records-forms.json`: `records-forms.record-discussion-mentions` rev 7 → 8 — the mention target must read `sys_comment` as well as the record (the gate fixed in #26497); acceptance[9] and negative[6] name both reads. ## Why Maintainer rulings in the 18.2.0 wave-2 session, recorded verbatim on #25807 (comment 6433562861): 「你是跑测试啊,和车道有什么关系」, 「你应该使用 pm-dispatch 技能写入」, 「测试结果怎样,测试中遇到的问题应该创建 issue」, 「如果有安全问题不能写issue的,直接派卡修复」, 「以上应该写入你的 checklist skills」. The ledger edit to `records-forms.record-discussion-mentions` needs no ruling (checklist-test §3: a run's checklist edit is an ordinary edit; #26453's Landed comment 6435471336 names it as the follow-up owed after #26497); the maintainer agreed to it in this session (「同意」), which is not recorded on the card. ## Verification - `node scripts/check-platform-checklist.mjs` → OK (16 areas, 329 items). - `node scripts/check-doc-authoring.mjs` → exit 0. - `node scripts/check-skill-identifier-liveness.mjs` → OK; `node scripts/pm/check-skill-id-lint.mjs` → clean. ## Line ratchet `.claude/skills/checklist-test/SKILL.md` grows 238 → 246 lines (+8, measured), and its `CEILINGS` row in `scripts/pm/check-skill-line-ratchet.mjs` moves by exactly that delta. Ruling of record that orders the text: comment 6433562861 on #25807 (the maintainer's 「以上应该写入你的 checklist skills」, with the four rulings it orders quoted verbatim). Every new line is under the 120-byte budget. Clause-②: no Metadata-protocol: none No package publishes from this diff (internal skill, QA docs, ledger), so it carries `skip-changeset`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012YjcDon6BvR9MN93ZsFq3U --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent c739de7 commit 03e898c

4 files changed

Lines changed: 42 additions & 16 deletions

File tree

‎.claude/skills/checklist-test/SKILL.md‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ Tier 1 批量清掉,剩下的预算才对得起 Tier 2。
102102
`node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --tier <paths>` 的输出、
103103
⛔ 不凭记忆(floor sonnet · default opus · ceiling fable);每个给:该项 JSON、RUNNER.md、dogfood 技
104104
能、自己的端口/DB、结果不进仓规则(§4)。
105+
- **QA 运行不是车道卡。** runner(子代理或云卡)由发起本轮的会话直接派,⛔ 不走车道认领
106+
与座位贴;pm-dispatch 只管写入门(§4)与安全修复派卡(Guardrails)。
105107
- **没有子代理工具时,顺序跑 —— 并在运行记录里声明这一轮是顺序执行的。** 规则与它
106108
的论证住在 `checklist-author` 技能(维护者所定,一处成文);⛔ 不留第二份拷贝。
107109
- 忠实执行每项的 `steps`,按各自声明的 `oracle` 判定每条 `acceptance` 与 `negative`
@@ -124,7 +126,10 @@ expected-fail 探针 —— 永不在真实缺陷上把条款打成绿。
124126
**issue 是纯文本 —— 永不放图。** 截图只为让你和子代理**现场**得出判定;它们是判断辅
125127
助,随运行环境一起丢弃。持久报告需要的是**复现规则,不是图片**。
126128

127-
经 REST 代理 `POST .../issues` 立单(`Content-Type: application/json`;⛔ 永不 MCP `issue_write`,锁 1 已拒):
129+
GitHub 写入只走 pm-dispatch 写入门:仓根直调 `scripts/pm/issue-create.mjs`、`post-stamped.mjs`、
130+
`close-cards.mjs`,批量先 `write-pace.mjs --announce-batch N`,云容器内自走 fleet relay;⛔ 永不 MCP
131+
`issue_write`(锁 1 已拒)或裸 `curl`。写入被会话权限拦下 ⛔ 不绕行:待发文本落文件、终报给
132+
出路径与正文,放行后照序补发 —— 写入未落地即未收口。记录这样写:
128133

129134
- **标题** —— `QA run · <selector> (<已判定>/<总数>) · <sha8> · <date> · <counts>`:唯一
130135
形状、严格解析、分数**强制**;语法与退役写法见 RUNNER.md「The record title」。
@@ -229,10 +234,13 @@ QA-source: #运行记录号 · area.item · 条款
229234
- **不伪造覆盖。** 缺 fixture → `blocked(fixture)` 带理由;console 没构建 → 构建它
230235
或记 `blocked(environment)`;证到一半的项是 `partial`,不是 `pass`。带证据的
231236
blocked 判定是一次成功运行;伪造的 pass 不是。
237+
- **每个产品问题同一轮经 §4 立 issue。** `fail` 条款与条款外探测同样,⛔ 不只留在运行记
238+
录或聊天;认证 / 授权类按下一条。
232239
- **认证 / 授权漏洞的复现,永不发布到 GitHub 的任何地方** —— 不进运行 issue,不进跟踪
233-
卡,不进评论。记下项 id、条款与 `detail withheld pending maintainer`,复现留在会话里,本轮以该报
234-
告终局,⛔ 不等维护者。⚠ 这与 RUNNER 规则 2 是**同一条规则写在两处**,⛔ 两边都不是对
235-
另一边的优先级主张;完整论证与它的维护者裁定在 RUNNER。
240+
卡,不进评论。卡只载项 id、条款与 `detail withheld pending maintainer`,复现留在会话里;修复直
241+
接经 pm-dispatch 派卡:席内 `mode:subagent` 派 `os-dev`,复现只进派发令,⛔ 不等维护者;runner 无
242+
派发通道时由派它的会话接手。⚠ 这与 RUNNER 规则 2 是**同一条规则写在两处**,⛔ 两边
243+
都不是对另一边的优先级主张;完整论证与它的维护者裁定在 RUNNER。
236244
- **不把 blocked 项当可运行的跑** —— 解析器隐藏它们正为此。
237245
- **一个选择器、一次运行、一张 issue;验证重测不立 issue,证据进 PR 正文(§5)。** release
238246
sweep 把 `since:vN` 与 `priority:P0` 作为分开的两轮跑 → 两张 issue,不要糊在一起。

‎docs/qa/platform-checklist/RUNNER.md‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,17 @@ selector handed you has a verdict; planned ids are listed, not chased.
8383
the run issue, not a tracking or extracted card, not a comment. Relocating it is not a
8484
mitigation — a tracking card is a public issue in a public repo just the same. Such a
8585
`fail` **is a completed verdict** when it records the item id, the clause, and `detail
86-
withheld pending maintainer`; the reproduction stays in the runner session, and the run
87-
ends there with that report — a one-shot runner has no channel to wait on. Existence
88-
published, recipe withheld, is a complete and actionable report — getting a defect
89-
fixed never requires handing anyone a working exploit. (Maintainer disclosure ruling,
90-
2026-08-18, recorded on #9387; the `checklist-test` skill states the same guardrail in
91-
the same terms — one rule written in both places, not a precedence claim by either.)
86+
withheld pending maintainer`; the reproduction stays in the runner session. The fix is
87+
**dispatched directly through `pm-dispatch`**, never waiting on the maintainer: a card
88+
carrying only the item id, the clause and `detail withheld pending maintainer`, then an
89+
in-seat `mode:subagent` `os-dev` dispatch (a disclosure-discipline card) whose prompt
90+
alone carries the reproduction. A one-shot runner with no dispatch channel hands that to
91+
the session that dispatched it. Existence published, recipe withheld, is a complete and
92+
actionable report — getting a defect fixed never requires handing anyone a working
93+
exploit. (Maintainer disclosure ruling, 2026-08-18, recorded on #9387; fix-dispatch
94+
ruling, 2026-10-27, recorded on #25807; the `checklist-test` skill states the same
95+
guardrail in the same terms — one rule written in both places, not a precedence claim
96+
by either.)
9297
**No other failure class is softened by this**: everything else owes its reproduction
9398
rule in full.
9499
3. **Classify blockers honestly.** Missing seed/persona/fixture → `blocked(fixture)`,
@@ -831,7 +836,10 @@ closing out the report includes the extraction, owed by the runner:
831836
card, a pointer back to the run record for the full evidence chain. A defect card does
832837
not carry `qa-run`; it enters triage first-touch normally. ⛔ An authentication or
833838
authorization defect is extracted under rule 2's carve-out — item, clause, `detail
834-
withheld pending maintainer`, no recipe. The extracted card is public too.
839+
withheld pending maintainer`, no recipe — and its fix is dispatched at once (rule 2). The
840+
extracted card is public too. Every product defect the run meets, a clause `fail` or an
841+
off-clause probe finding alike, is extracted in the same run — ⛔ never left only in the
842+
run record or the chat.
835843
- **Checklist-accuracy findings and fixture gaps** close out through the wave's anchor
836844
card (the sweep's tracking issue) — ⛔ not extracted.
837845
- **Environment blockers**: recorded in the run record is enough.

‎docs/qa/platform-checklist/areas/records-forms.json‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2814,12 +2814,12 @@
28142814
"title": "Record discussion: an @mention comment reconciles optimistically, persists to sys_comment, interleaves with activity, pings the mentioned user's bell — and the feed filter shows exactly each mode's subset without dropping author-extended activity",
28152815
"since": "v16",
28162816
"status": "active",
2817-
"revision": 7,
2817+
"revision": 8,
28182818
"priority": "P1",
28192819
"surface": "browser",
28202820
"personas": [
28212821
"seeded admin (admin@objectos.ai / admin123) — the comment author",
2822-
"a second user, minted by the admin with POST /api/v1/auth/admin/create-user — the @mention TARGET. A stock showcase boot is invite_only, so a fresh POST /api/v1/auth/sign-up/email answers 403 SELF_REGISTRATION_CLOSED (steps[13]; RUNNER.md, 'A stock showcase boot refuses self-registration')"
2822+
"a second user, minted by the admin with POST /api/v1/auth/admin/create-user — the @mention TARGET. The target must hold a permission set that grants read on `sys_comment` as well as being able to read the record: the producer gate admits a mentioned user only when both reads succeed, so a target with no comment read is withheld (`cannot_read_thread`) and every bell clause scores against the wrong persona. A stock showcase boot is invite_only, so a fresh POST /api/v1/auth/sign-up/email answers 403 SELF_REGISTRATION_CLOSED (steps[13]; RUNNER.md, 'A stock showcase boot refuses self-registration')"
28232823
],
28242824
"fixtures": {
28252825
"app": "showcase",
@@ -2910,7 +2910,7 @@
29102910
"evidence": "the 'all' feed screenshot showing the custom-type row (or the pin output + the substitution note)"
29112911
},
29122912
{
2913-
"clause": "an @mention notification reaches a mentioned user only when that user can READ the comment's record — whether the mention names them by user id or by email — and the author is never notified: the collab.mention notification carries the comment's preview and a deep link to the record, so it reaches exactly the readers the thread itself reaches. The gate sits at the producer (plugin-audit's mention writer), judged in each mentioned user's own envelope by the same grant resolver, organization-claim vetting and parent-read evaluator a request uses, so the tenant wall, sharing, RLS and object CRUD decide (#24785, fixed by #24794)",
2913+
"clause": "an @mention notification reaches a mentioned user only when that user can READ both the comment's record and the comment itself — whether the mention names them by user id or by email — and the author is never notified: the collab.mention notification carries the comment's preview and a deep link to the record, so it reaches exactly the readers the thread itself reaches. The gate sits at the producer (plugin-audit's mention writer), judged in each mentioned user's own envelope by the same grant resolver, organization-claim vetting and parent-read evaluator a request uses, so the tenant wall, sharing, RLS and object CRUD decide (#24785, fixed by #24794)",
29142914
"oracle": "api",
29152915
"verify": "step-14 inbox reads: the member gains NO collab.mention for either comment on the private note (by id, by email), gains exactly one for the account comment (data.notifications[] row of type collab.mention, actionUrl '/showcase_account/ID'), unreadCount up by one, with that deep link naming the account record and that record readable by the member (200); the admin's inbox gains none for any of the three, though the account comment named the admin. Each recipient reads only their own inbox, so the count is taken per user over GET /api/v1/notifications, never from sys_notification as admin alone. Each mentioned user withheld for want of read access is logged once at warn — '[audit] mention notification withheld' with reason cannot_read_source, the user id (the email mention resolved to it) and the comment id, never the comment text — record both lines; the author is dropped without a line. On a walled boot the cross-organization user's inbox is unchanged. Score the presence or absence of a collab.mention row per recipient and comment, not the notification's wording",
29162916
"evidence": "both users' inbox reads before and after, the member's two access reads, the three comment create responses, and the withheld-recipient log lines"
@@ -2923,7 +2923,7 @@
29232923
"a re-thread that is refused but LEAVES the row moved (or is accepted outright) is a FAIL — #10170 registered the gate on beforeUpdate precisely because a caller barred from creating a comment on a feeds-disabled object could otherwise re-point an existing one into it",
29242924
"scoring either FEEDS_DISABLED clause from the ENABLED control alone is a FAIL — the control exists to prove the refusal is attributable to the capability gate rather than to record access (RECORD_NOT_ACCESSIBLE, comment-access-hooks.ts), so a run that reports the 403 without the 2xx control has not measured the gate",
29252925
"a filter mode showing a row of another mode's type — or dropping one of its own — is a FAIL; and an unknown activity type absent from the 'all' feed is a FAIL (the objectui#5840 shape: stored, queryable, invisible), while its absence from the three NARROWING modes is correct behavior a run must not file as the drop",
2926-
"a collab.mention notification reaching a mentioned user who cannot read the comment's record is a FAIL in either spelling of the mention (user id or email): the notification is a copy of what the thread shows, preview and deep link included (#24785). A notification withheld from a mentioned user who CAN read the record is a FAIL the other way: the gate is read access, not organization membership or the author's own view"
2926+
"a collab.mention notification reaching a mentioned user who cannot read the comment's record, or cannot read the comment itself, is a FAIL in either spelling of the mention (user id or email): the notification is a copy of what the thread shows, preview and deep link included (#24785). A notification withheld from a mentioned user who CAN read the record is a FAIL the other way: the gate is read access, not organization membership or the author's own view"
29272927
],
29282928
"variants": [
29292929
"all — the full merged comment + activity feed",
@@ -2999,6 +2999,12 @@
29992999
"date": "2026-10-26",
30003000
"change": "automated.ref, from Tier 1 run #25815 (6679644a, pin b41ed7f68956), re-read on main cc378e93. (1) acceptance[5]: the comments-permission-matrix FEEDS_DISABLED case asserts 403 + code only and never reads the thread's zero rows; the ref says so. (2) acceptance[8] names recordActivityFeed.test.ts as its fallback oracle, but the ref did not, so a ref-driven run never ran it; it is added, at ui/packages/plugin-detail/src/renderers/__tests__/. The run's notes on acceptance[6] / negative[3] and acceptance[9] confirm the clause and ref text as written (engine-level pins, partial at most). No clause changed",
30013001
"ref": "#25846"
3002+
},
3003+
{
3004+
"revision": 8,
3005+
"date": "2026-10-27",
3006+
"change": "The mention recipient gate now also asks each mentioned user's own read of the comment (fix landed in #26497 for #26453). personas[1] states that the @mention target must hold read on sys_comment as well as the record; acceptance[9] and negative[6] name both reads. No pin changed.",
3007+
"ref": "#26497"
30023008
}
30033009
]
30043010
},

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,11 @@ export const CEILINGS = new Map([
15471547
// that use them too — the erosion mechanism the ratchet exists to stop
15481548
// isn't specific to the pm-dispatch surface. Set at current counts on
15491549
// `origin/main` (headroom 0, same convention as the entries above).
1550-
['.claude/skills/checklist-test/SKILL.md', 238],
1550+
// 238 → 246: the ruling of record that orders text into the file — the
1551+
// maintainer's 「以上应该写入你的 checklist skills」, recorded verbatim with the
1552+
// rulings it orders in comment 6433562861 — +8 measured lines (write doors,
1553+
// file-every-defect, auth/authz fix dispatch, QA run is not a lane card).
1554+
['.claude/skills/checklist-test/SKILL.md', 246],
15511555
['.claude/skills/checklist-author/SKILL.md', 62],
15521556
['.claude/skills/dogfood-verification/SKILL.md', 157],
15531557
// 328 → 334 (#10848): maintainer-ruled (2026-08-22, Option A) — convention 5

0 commit comments

Comments
 (0)