Repository navigation
docs(pm): add docs/qa/** to the domain:devx row of the lane table - #17526
Conversation
The 域车道 table named docs/qa/** in no row, so a card landing in docs/qa/platform-checklist/** was routed by judgment call. The maintainer settled it by acting: on the card that raised it, domain:services was replaced with domain:devx for a fix in that tree. This writes the answer into the domain:devx row beside content/docs/** and apps/docs. The row is metered by the file's max-table-row-bytes pin (342, headroom 0) and the file sits at its 812-line ceiling, so the 15-byte clause is paid inside the same row: the back-reference 按锚定规则例外 (21 bytes) is dropped from the packages/lint / scripts/ / .github/workflows/ clause, whose rule is stated verbatim six lines above the table. Row width 341 -> 335 bytes; the file's widest row (342) and line count (812) are unchanged. Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK Co-authored-by: Claude <noreply@anthropic.com>
… the anchoring pointer Review round 1: the byte payment in the domain:devx row must keep the pointer 按锚定规则例外 and drop the restated condition 与 spec 相交面 instead. The pointer is what makes the routing of packages/lint, scripts/ and .github/workflows/ conditional on the anchoring rule's qualifier (围着 spec 契约转的归 domain:spec,余留 devx); without it the row read as an unconditional routing of every spec-intersecting face to domain:spec, a widening under the name of a byte payment. The condition is carried by the pointer, so dropping the restatement loses nothing. Row 247: 335 -> 338 bytes (pin 342); file stays 812/812; widest row 342. Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK Co-authored-by: Claude <noreply@anthropic.com>
维护者速读改了什么 —— 为什么改 —— #17453 落在 风险与代价(含回滚) —— 纯指令文本,一行;只影响分诊查表,无运行时面。第一版补丁反过来删了回指、留下重述条件,会把这条例外读成「相交面无条件归 spec」,本席复核第一轮退回,第二个 commit 改正;本席在 head 席位意见 —— 通过。受管面( 你要做的 —— 一个动作:人工合并本 draft PR(若您更想要 skills 席,session Generated by Claude Code |
Fixes #17459
What changed
One row of the
域车道table in.claude/skills/pm-dispatch/SKILL.md— line 247, thedomain:devxrow. Nothing else in the file or the repo moves (git diff --stat f8e57905..HEAD: 1 file, 1 insertion, 1 deletion).Before (
origin/mainatf8e57905) — 341 bytes:| domain:devx | sdui-parser、content/docs/**、apps/docs、.githooks/、docker/README.md、examples/** 仅测试基建面;packages/lint、scripts/(门禁类)、.github/workflows/(接线)三者与 spec 相交面按锚定规则例外归 domain:spec,门禁按 SUBJECT:governed 面归 skills,代码/文档质量归本域 |After (this PR's head) — 338 bytes:
| domain:devx | sdui-parser、content/docs/**、apps/docs、docs/qa/**、.githooks/、docker/README.md、examples/** 仅测试基建面;packages/lint、scripts/(门禁类)、.github/workflows/(接线)三者按锚定规则例外归 domain:spec,门禁按 SUBJECT:governed 面归 skills,代码/文档质量归本域 |(Code spans inside the row are flattened above for readability; the diff carries the exact bytes.)
Two deltas inside the one row:
、docs/qa/**(15 bytes) afterapps/docs— the checklist tree now has a lookup, beside the other two docs trees the row already carries.与 spec 相交面(18 bytes) from thepackages/lint/scripts//.github/workflows/clause — the payment. It restated a condition that the retained pointer按锚定规则例外already carries: the anchoring rule six lines above the table (line 241, 「唯一例外packages/lint等与 spec 相交的 devx 面:围着 spec 契约转的归domain:spec,余留 devx」) is what makes the routing of those three paths conditional, and the pointer is what binds the row to it. The three paths, the pointer and thedomain:specdestination all stay in the row; no fact leaves the table.Review round 1 corrected the payment: the first cut (commit
5d834e00) paid with the pointer instead and kept the restated condition, which left the row reading as an unconditional routing of every spec-intersecting face of the three todomain:spec— a widening of the anchoring exception under the name of a byte payment. Commit42521c38restores the pointer and drops the restatement.Authority for the routing
The maintainer answered the card's question by acting, not by writing. On #17453 — whose change lands in
docs/qa/platform-checklist/areas/approvals.json— the issue events endpoint (/repos/objectstack-ai/objectstack/issues/17453/events, read in this session on 2026-09-10) records:labeled domain:servicesbyos-litantat 2026-09-10T15:27:36Z (the triage seat's judgment call, recorded on the card as such)unlabeled domain:servicesbyhotlongat 2026-09-10T15:28:53Zlabeled domain:devxbyhotlongat 2026-09-10T15:28:53Z⇒
docs/qa/**routes on the tree, todomain:devx. The triage seat's comment on the card records the same reading and settles the question: 「⛔ Do not re-open the routing question in the PR — it is answered. The PR writes down the answer.」 This PR writes it down; it does not re-argue the four readers the card enumerated.Why the row names
docs/qa/**and notdocs/**The triage comment suggested phrasing the clause to generalise (all
docs/**trees ⇒domain:devx). Written that way the row would contradict two routings the table already carries:docs/audits/**sits on the catch-all row (无固定归属,按落点分诊), anddocs/adr/**is a governed surface (domain:skillsvia the governed-face definition). The maintainer's act evidences exactly one tree, so the row names that tree; the next docs tree gets its own act and its own clause. If the maintainer wants the general rule instead, that is a one-word edit on this same row plus two edits elsewhere in the table, and a separate decision.Four-axis note — the one judgement: where the clause sits, and what pays for it
docs/qa/platform-checklist/**card arrives with the next checklist sweep (checklist-authorruns are scheduled work), so the lookup is exercised, not speculative. Measured:docs/qaappeared in no row of the table (grep -n 'docs/qa' SKILL.md= 0 hits onf8e57905).lanes/*.mdor CODEOWNERS, so the table stays the one routing authority.docs/qa/**), so no seat can read it as licence to routedocs/adr/**ordocs/audits/**by tree. The bytes paid are a restated condition the retained pointer already carries, so the row's routing of the three devx tooling paths stays conditional on the anchoring rule — a payment that had instead removed the pointer would have widened that rule, which is why round 1 swapped it.Verification
Tree:
42521c38(this PR's head; every gate below ran on it with a clean working tree — round 1 ran the same 16 families green on5d834e00, and the whole set was re-run in full on the new head). Every exit code captured by redirect before any pipe; each verdict line is the gate's own.Ratchet (
node scripts/pm/check-skill-line-ratchet.mjs), SKILL.md verdict lines byte-identical to theorigin/mainbaseline (diffof the two greps printed IDENTICAL):✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md: widest table row is 342 bytes (pin 342; headroom 0).✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 812 lines (ceiling 812; headroom 0).Row 247 measured with
awk 'NR==247' SKILL.md | tr -d '\n' | wc -c: 341 onorigin/main, 338 at head (335 at the round-1 head). The pin's headroom was 1 byte (the widest row is line 245 at 342), so the 15-byte clause could not ride on it; paid by −18 inside the same row. Line count 812 → 812. The committed row is byte-identical to the row the reviewing seat specified (cmpof the two = equal, 338 B).Derived families (
node scripts/pm/dispatch-gates.mjs --commands, derived at42521c38from the branch changeset — identical list to round 1; reconciled with--ran:✓ dispatch-gates --ran: 16 derived famil(ies) accounted for — 16 run, 0 NOT-MEASURED (a DERIVED zero — all 16 recorded an exit code and none of them is 3).):node scripts/check-closing-keyword-parity.mjscheck-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators …)node scripts/check-closing-keyword-parity.mjs --self-test✓ check-closing-keyword-parity --self-test: 24 assertions, 5 mutations of the shipped parsers each driven to red.node scripts/check-comment-mask-corpus.mjs✓ comment-mask corpus sweep: 6582 files, 0 disagree, 0 unparseablenode scripts/pm/check-governed-queue-guard.mjs --self-test✓ check-governed-queue-guard self-test: 183 cases passpnpm --filter @objectstack/lint run check:doc-formula-expressions✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 438 files / 1375 TS blocks judged clean by @objectstack/formula.— its prerequisite (@objectstack/formula+@objectstack/lintbuilt) was met under the verify lock (turbo run build --filter=@objectstack/formula --filter=@objectstack/lint,VERDICT command-exit 0); the very first run in round 1 had been exit 3PREREQUISITE NOT MET(NOT MEASURED, not a finding)pnpm check:agent-test-spelling✓ check-agent-test-spelling: 0 violations — 499 file(s) · 7980 bare -- token(s) · 1674 launcher-rooted run(s) · 12 separator(s) JUDGEDpnpm check:doc-authoring✓ doc authoring guard: sibling-package prose ids hold the baseline — 821 pinned site(s) across 231 file(s) … no growth, no burn-down unrecorded.pnpm check:driver-memory-censuscheck-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live …pnpm check:nul-bytescheck-nul-bytes: OK (scanned 8312 text file(s) … no raw ASCII control bytes).— plus a direct control-byte grep over SKILL.md: 0 hitspnpm check:pm-governed-merges✓ check-governed-merges --self-test: 274 assertions …pnpm check:pm-governed-prose✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.pnpm check:pm-skill-id-lint✓ check-skill-id-lint: 27 file(s) cleanpnpm check:pm-skill-ratchet✓ check-skill-line-ratchet self-test: 157 cases pass.plus the two SKILL.md verdict lines abovepnpm check:refd-timer-probeOK check-refd-timer-probe: 6577 source file(s) swept; the process-global timer probe is read in packages/qa/refd-timer-testkit/src/index.ts and nowhere else.pnpm check:skill-frame-sync✓ check-skill-frame-sync: the one declared copy of the decision frame is internally coherent (.claude/skills/pm-dispatch/SKILL.md …)pnpm check:watch-hint-literal✓ check-watch-hint-literal: 69 declaration(s) across 4 rostered name(s) …Path face:
node scripts/pm/check-governed-merges.mjs --test .claude/skills/pm-dispatch/SKILL.md→ exit 3,⛔ GOVERNED — a human merge is the review record for this PR (#9495 regime).The dispatch named a--branchmode of this script; it is not onf8e57905(a grep for the literal--branchin the script returns 0 hits), so the dispatch's own fallback — the--testpredicate with the path list — is what ran.Not owed: no package is touched, so there is no ① build closure and no ② package test/typecheck; the formula + lint build above was a gate prerequisite, not a package under test.
Acceptance notes
references/lanes/devx.mddoes not mentiondocs/qa/**. The table is the routing authority and the lane file is read after the table resolves, so nothing is wrong; out of this PR's declared file surface. 承接者: the devx seat, on its next lane-file edit..github/CODEOWNERScarries nodocs/qarule (already recorded on the card). The maintainer's act routes on the tree, and CODEOWNERS routes onlydocs/adr/; nothing to add. Out of the declared file surface. 承接者: none.check-governed-merges.mjs --branchmode is not landed onf8e57905; the prompt's own fallback was used. Prompt drift, no repo file to change. 承接者: the skills seat's dispatch template.docs/**was not taken, for the reason in the section above; if the maintainer prefers the general rule, that is a follow-up decision, not a defect. 承接者: the maintainer, at review.Clause-②: no — instruction text; no accept set or public surface moves.
Changeset: none —
.claude/**publishes nothing from any released package;skip-changesetapplied.维护者速读(草稿)
改了什么:pm-dispatch SKILL.md 的域车道表
domain:devx行加了一个词docs/qa/**(平台测试清单树),并删掉同一行里一句重复陈述的条件(与 spec 相交面)来付字节账;指向锚定规则的回指按锚定规则例外保留,因为那个条件正由它承载。整个文件行数(812)、最宽表行(342 字节)都没有动。为什么改:#17453 那张卡落在
docs/qa/platform-checklist/**,表里查不到该树,分诊席按「文档跟随它记录的子系统」打了domain:services,您在 8 分钟后把它改成了domain:devx。本次改动把您的这个动作写进表里,下一个席位不再重新推导。风险与代价(含回滚):零运行时影响,只影响分诊席查表;回滚就是 revert 这两个 commit。删掉的只是一句重复陈述的条件,保留的回指
按锚定规则例外已经承载同一条件(第 241 行「围着 spec 契约转的归 domain:spec,余留 devx」),三个路径的归属和它们的条件都还在表里;第一版曾反过来删掉回指、保留重复条件,那会把这条例外读成无条件归 spec,评审第一轮已纠正。席位意见:(席位定稿)
你要做的:确认
docs/qa/**⇒domain:devx是您的本意 —— 表里现在写的是这一棵树,没有泛化成docs/**,因为docs/audits/**(按落点分诊)和docs/adr/**(governed 面)各有已定归属。认可即人工合并;想要泛化规则的话请在评审里说一句,那是另一个决定。Generated by Claude Code