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

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

- **标题** —— `QA run · <selector> (<已判定>/<总数>) · <sha8> · <date> · <counts>`:唯一
形状、严格解析、分数**强制**;语法与退役写法见 RUNNER.md「The record title」。
Expand Down Expand Up @@ -229,10 +234,13 @@ QA-source: #运行记录号 · area.item · 条款
- **不伪造覆盖。** 缺 fixture → `blocked(fixture)` 带理由;console 没构建 → 构建它
或记 `blocked(environment)`;证到一半的项是 `partial`,不是 `pass`。带证据的
blocked 判定是一次成功运行;伪造的 pass 不是。
- **每个产品问题同一轮经 §4 立 issue。** `fail` 条款与条款外探测同样,⛔ 不只留在运行记
录或聊天;认证 / 授权类按下一条。
- **认证 / 授权漏洞的复现,永不发布到 GitHub 的任何地方** —— 不进运行 issue,不进跟踪
卡,不进评论。记下项 id、条款与 `detail withheld pending maintainer`,复现留在会话里,本轮以该报
告终局,⛔ 不等维护者。⚠ 这与 RUNNER 规则 2 是**同一条规则写在两处**,⛔ 两边都不是对
另一边的优先级主张;完整论证与它的维护者裁定在 RUNNER。
卡,不进评论。卡只载项 id、条款与 `detail withheld pending maintainer`,复现留在会话里;修复直
接经 pm-dispatch 派卡:席内 `mode:subagent` 派 `os-dev`,复现只进派发令,⛔ 不等维护者;runner 无
派发通道时由派它的会话接手。⚠ 这与 RUNNER 规则 2 是**同一条规则写在两处**,⛔ 两边
都不是对另一边的优先级主张;完整论证与它的维护者裁定在 RUNNER。
- **不把 blocked 项当可运行的跑** —— 解析器隐藏它们正为此。
- **一个选择器、一次运行、一张 issue;验证重测不立 issue,证据进 PR 正文(§5)。** release
sweep 把 `since:vN` 与 `priority:P0` 作为分开的两轮跑 → 两张 issue,不要糊在一起。
22 changes: 15 additions & 7 deletions docs/qa/platform-checklist/RUNNER.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,17 @@ selector handed you has a verdict; planned ids are listed, not chased.
the run issue, not a tracking or extracted card, not a comment. Relocating it is not a
mitigation — a tracking card is a public issue in a public repo just the same. Such a
`fail` **is a completed verdict** when it records the item id, the clause, and `detail
withheld pending maintainer`; the reproduction stays in the runner session, and the run
ends there with that report — a one-shot runner has no channel to wait on. Existence
published, recipe withheld, is a complete and actionable report — getting a defect
fixed never requires handing anyone a working exploit. (Maintainer disclosure ruling,
2026-08-18, recorded on #9387; the `checklist-test` skill states the same guardrail in
the same terms — one rule written in both places, not a precedence claim by either.)
withheld pending maintainer`; the reproduction stays in the runner session. The fix is
**dispatched directly through `pm-dispatch`**, never waiting on the maintainer: a card
carrying only the item id, the clause and `detail withheld pending maintainer`, then an
in-seat `mode:subagent` `os-dev` dispatch (a disclosure-discipline card) whose prompt
alone carries the reproduction. A one-shot runner with no dispatch channel hands that to
the session that dispatched it. Existence published, recipe withheld, is a complete and
actionable report — getting a defect fixed never requires handing anyone a working
exploit. (Maintainer disclosure ruling, 2026-08-18, recorded on #9387; fix-dispatch
ruling, 2026-10-27, recorded on #25807; the `checklist-test` skill states the same
guardrail in the same terms — one rule written in both places, not a precedence claim
by either.)
**No other failure class is softened by this**: everything else owes its reproduction
rule in full.
3. **Classify blockers honestly.** Missing seed/persona/fixture → `blocked(fixture)`,
Expand Down Expand Up @@ -831,7 +836,10 @@ closing out the report includes the extraction, owed by the runner:
card, a pointer back to the run record for the full evidence chain. A defect card does
not carry `qa-run`; it enters triage first-touch normally. ⛔ An authentication or
authorization defect is extracted under rule 2's carve-out — item, clause, `detail
withheld pending maintainer`, no recipe. The extracted card is public too.
withheld pending maintainer`, no recipe — and its fix is dispatched at once (rule 2). The
extracted card is public too. Every product defect the run meets, a clause `fail` or an
off-clause probe finding alike, is extracted in the same run — ⛔ never left only in the
run record or the chat.
- **Checklist-accuracy findings and fixture gaps** close out through the wave's anchor
card (the sweep's tracking issue) — ⛔ not extracted.
- **Environment blockers**: recorded in the run record is enough.
14 changes: 10 additions & 4 deletions docs/qa/platform-checklist/areas/records-forms.json
Original file line number Diff line number Diff line change
Expand Up @@ -2814,12 +2814,12 @@
"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",
"since": "v16",
"status": "active",
"revision": 7,
"revision": 8,
"priority": "P1",
"surface": "browser",
"personas": [
"seeded admin (admin@objectos.ai / admin123) — the comment author",
"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')"
"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')"
],
"fixtures": {
"app": "showcase",
Expand Down Expand Up @@ -2910,7 +2910,7 @@
"evidence": "the 'all' feed screenshot showing the custom-type row (or the pin output + the substitution note)"
},
{
"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)",
"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)",
"oracle": "api",
"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",
"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"
Expand All @@ -2923,7 +2923,7 @@
"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",
"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",
"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",
"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"
"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"
],
"variants": [
"all — the full merged comment + activity feed",
Expand Down Expand Up @@ -2999,6 +2999,12 @@
"date": "2026-10-26",
"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",
"ref": "#25846"
},
{
"revision": 8,
"date": "2026-10-27",
"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.",
"ref": "#26497"
}
]
},
Expand Down
6 changes: 5 additions & 1 deletion scripts/pm/check-skill-line-ratchet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1547,7 +1547,11 @@ export const CEILINGS = new Map([
// that use them too — the erosion mechanism the ratchet exists to stop
// isn't specific to the pm-dispatch surface. Set at current counts on
// `origin/main` (headroom 0, same convention as the entries above).
['.claude/skills/checklist-test/SKILL.md', 238],
// 238 → 246: the ruling of record that orders text into the file — the
// maintainer's 「以上应该写入你的 checklist skills」, recorded verbatim with the
// rulings it orders in comment 6433562861 — +8 measured lines (write doors,
// file-every-defect, auth/authz fix dispatch, QA run is not a lane card).
['.claude/skills/checklist-test/SKILL.md', 246],
['.claude/skills/checklist-author/SKILL.md', 62],
['.claude/skills/dogfood-verification/SKILL.md', 157],
// 328 → 334 (#10848): maintainer-ruled (2026-08-22, Option A) — convention 5
Expand Down
Loading