Skip to content

skills(pm-dispatch): dedupe at grading by file/mechanism over the open board of both repos — same finding ⇒ duplicate_of, never a second dispatch - #18981

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-18963-dedupe-by-file-at-grading
Sep 18, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-18963-dedupe-by-file-at-grading

Conversation

@os-elon-musk

Copy link
Copy Markdown
Collaborator

Fixes #18963
Clause-②: no

Governed rules layer (.claude/skills/pm-dispatch/SKILL.md) — draft PR, four-piece terminal; the skills seat's contract-tier review, then the maintainer's approval lands it. skip-changeset: nothing published moves (.claude/** is internal agent tooling, in no package's files[]).

What changed — three rows of the 分诊 band, 812 / 812 held, no line added, no re-wrap

The triage band's shadow rows read as a cross-repo keyword search only, and the dedupe step that would have caught two cards on one file and one defect — graded two days apart into two lanes by the same seat, both dispatched, the second PR superseded — did not exist in the rules text: a dedupe by FILE / MECHANISM against the OPEN board, own repo included, before keywords, with the finding (not the card) as the unit. Governing triage reading, verbatim: 「缺的不是勤勉,是一条按『文件/机制』而不是按『关键词』去重的步骤」 · 「去重的单位是『发现』,⛔ 不是『卡』」.

line before (bytes) after (bytes)
:366 「跨仓查重(shadow 检查):跟跨仓引用 + 关键词搜各姊妹仓。」 (75 B) 「查重/shadow 检查先按文件/机制查本仓与姊妹仓 open 卡(含 pm:dispatched),再跟引用与关键词。」 (120 B)
:367 「shadow 命中在飞 ⇒ Blocked-by: 不派;open 未认领 ⇒ 先收敛成一个派发入口。」 (99 B) 「同文件同缺陷 = 同一发现,不分车道:证据搬到先卡,后卡关 duplicate_of,⛔ 不并排派发。」 (115 B)
:368 「shadow 命中已完成 ⇒ 卡可能过期。」 (47 B) 「其余在飞 ⇒ Blocked-by: 不派;open 未认领 ⇒ 先并成一个派发入口;已完成 ⇒ 卡可能过期。」 (119 B)

Band total 221 B → 354 B (+133 B) at +0 lines; every row is at or under the 120-byte cap (120 / 115 / 119). Lines :223 (「分诊座位唯一生产:定级/路由/type/查重/shadow/duplicate_of…」) and every line outside :366–:368 are byte-identical to origin/main — the diff is 3 insertions / 3 deletions on one file. The parallel-draft bands of PR #18903 (:509–:670) and PR #18921 (:162–:183) are untouched.

What the new rows say (measured against the card's requirements)

  • By file / mechanism, before keywords, over the OPEN board of both repos, pm:dispatched included — :366: 「先按文件/机制查本仓与姊妹仓 open 卡(含 pm:dispatched),再跟引用与关键词」. The population is stated once, in the same row (the PM's mechanism assumption 2, confirmed: 「跨仓」 became 「本仓与姊妹仓」 in place).
  • The unit is the finding, not the card — :367: 「同文件同缺陷 = 同一发现,不分车道」; the later card's evidence moves to the earlier card (「证据搬到先卡」), the later card shuts as duplicate_of (「后卡关 duplicate_of」, the state the :136 row already binds to the duplicate reason), and it is never dispatched beside the earlier one (「⛔ 不并排派发」).
  • Every hit that is NOT the same finding keeps the old trichotomy — :368: in flight ⇒ Blocked-by:, not dispatched; open and unclaimed ⇒ fold into ONE dispatch entry first; completed ⇒ the card may be stale. 「其余」 scopes the row to what :367 did not already settle, so a same-finding sibling in flight lands on duplicate_of, not on Blocked-by:.

Retired clauses and their survivors (nothing retired without one)

retired spelling survivor
:366 「跨仓查重(shadow 检查)」 :366 「查重/shadow 检查 … 本仓与姊妹仓」 — same name (the :310 spelling 「查重/shadow 检查」), population widened to both repos
:366 「跟跨仓引用 + 关键词搜各姊妹仓」 :366 「再跟引用与关键词」 — same two methods, now second to file / mechanism; 「各姊妹仓」 is carried by 「本仓与姊妹仓」 earlier in the row
:367 「shadow 命中在飞 ⇒ Blocked-by: 不派」 :368 「其余在飞 ⇒ Blocked-by: 不派」 — same mechanism, scoped to hits that are not the same finding
:367 「open 未认领 ⇒ 先收敛成一个派发入口」 :368 「open 未认领 ⇒ 先并成一个派发入口」 — 「收敛成」 → 「并成」 (3 B) is the only compression; 「先」, 「open 未认领」 and 「一个派发入口」 all kept
:368 「shadow 命中已完成 ⇒ 卡可能过期」 :368 「已完成 ⇒ 卡可能过期」 — folded into the trichotomy row

The 「shadow 命中」 subject of the old :367/:368 is now carried by :366 naming the check and :368's 「其余」 reading against :367; no row outside the band was touched to make that binding.

references/core-rules.md (151 / 151): its only shadow mention is :56 「跨仓查重与 shadow 检查恒归中央 ⛔ 不下放」 — a rule about WHO runs the check (central triage), not about its population or order, and it stays true under the new rows (:55 already makes same-repo dedupe central too). No rule moved there, so no twin is owed (the PM's mechanism assumption 3, confirmed by git grep -i shadow on that file: 1 hit, :56).

Reader test — the second grading, replayed under the new rows

At 2026-09-18T00:06Z the triage seat grades #18844 (check-single-claim-paths.mjs 401s because node fetch ignores HTTPS_PROXY; remedy: the proxy re-exec the sibling scripts already carry). Platform state of #18314 at that instant, from its label events: open, pm:queue + domain:spec + priority:p2 since 2026-09-17T10:10Z, unclaimed (pm:dispatched and the assignee arrived at 05:49Z, five hours later — so at grading it was a queued sibling, not yet an in-flight one; the dispatch text's 「pm:dispatched when #18844 was graded」 describes the later claim-time instant, which is the seat's own half, #18964).

Outcome: one card (#18314, p2, domain:spec), one dispatch, one PR. The old :366 could not reach this: its population was 「各姊妹仓」 only, and its method was keywords.

Gates — all at ea2521bd9 (the final commit; the tree did not move after these runs)

Derived from the worktree's own changeset with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (stderr: 「gate list derived from the tree of 'objectstack-ai/objectstack' at commit ea2521b」; change set: 1 path vs merge base 26c73fb4e): 20 commands, 20 run, every exit code captured by redirect-then-$?, never through a pipe. --ran reconciliation: 「20 derived famil(ies) accounted for — 20 run, 0 NOT-MEASURED, 0 UNRUN」 (exit 0).

command exit verdict line
pnpm check:pm-skill-ratchet 0 .claude/skills/pm-dispatch/SKILL.md is 812 lines (ceiling 812; headroom 0) · ✓ references/core-rules.md is 151 lines (ceiling 151; headroom 0) · widest table row 342 (pin 342)
pnpm check:pm-skill-id-lint 0 ✓ 27 file(s) clean (pattern /#[0-9]{3,}/g)
pnpm check:skill-frame-sync 0 ✓ the one declared copy is internally coherent; 4 axes; 74 markdown files scanned — four-axis block :733–:754 md5 3327d02c56f8a0eca88569dad2270f32 before and after
pnpm check:pm-governed-prose 0 ✓ 2 instruction surface(s) name all 5 registered governed surfaces and claim no others
pnpm check:nul-bytes 0 OK (8891 text files, no raw ASCII control bytes); control-byte grep of the edited file: 0 hits
pnpm --filter @objectstack/lint run check:doc-formula-expressions 0 ✓ self-test 58 cases · 22 record-scoped examples across 438 files / 1378 TS blocks clean · 9 TSDoc examples clean · 14 *When predicates clean — after pnpm --filter "@objectstack/lint..." build under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0, 30 s held; first attempt without the lint build exited 3 PREREQUISITE NOT MET, which is a refusal, not a measurement)
pnpm check:agent-test-spelling 0 ✓ 0 violations — 515 files
pnpm check:cross-package-test-inputs 0 OK: 29 package(s) read outside themselves, all declared; 255 self-test cases
pnpm check:doc-authoring 0 ✓ 821 pinned sites across 231 files hold the baseline
pnpm check:driver-memory-census 0 OK — every declaration ledgered, every entry live
pnpm check:pm-expected-skips 0 ✓ self-test 99 cases
pnpm check:pm-governed-merges 0 ✓ 328 assertions
pnpm check:pm-half-states 0 ✓ self-test 4963 cases
pnpm check:refd-timer-probe 0 ✓ 11 cases, negative controls included
pnpm check:watch-hint-literal 0 ✓ 71 declarations across 4 rostered names
node scripts/check-closing-keyword-parity.mjs 0 OK (3 parsers agree on all 9 keywords; 5 files carrying the grammar, all registered)
node scripts/check-closing-keyword-parity.mjs --self-test 0 ✓ 40 assertions, 5 mutations driven to red
node scripts/check-comment-mask-corpus.mjs 0 ✓ 6857 files, 0 disagree, 0 unparseable
node scripts/pm/check-governed-queue-guard.mjs --self-test 0 ✓ 253 cases
node scripts/pm/check-harness-current.mjs --self-test 0 all 26 cases passed

Builds were run with OS_SKIP_DTS=1 (the formula gate imports compiled JS, not declarations); no gate that reads .d.ts is in this derivation. Repo-wide scans (pnpm lint) are CI's run, not owed here — this diff touches no lintable source.

Line budget

  • SKILL.md: 812 before / 812 after / ceiling 812 — paid in-band by rewriting the three rows (:366 75 → 120 B, :367 99 → 115 B, :368 47 → 119 B); the one compression is 「收敛成」 → 「并成」 in the :368 survivor.
  • references/core-rules.md: 151 / 151 / 151 — untouched, no twin owed.

Acceptance notes

维护者速读(草稿)

改了什么 — 分诊规则里的三行「shadow 检查」被改写为一条真正的去重步骤:定级时先按文件/机制、再按关键词,对本仓与姊妹仓全部 open 卡(含已派发的)查重;同文件同缺陷视为同一个发现,后卡的证据搬到先卡、后卡以 duplicate_of 关闭,不再并排派发。行数 812/812 不变,只在原三行内改写,没有折行凑数。

为什么改 — 同一个文件、同一个缺陷的两张卡,被同一个分诊席在两天里定进两个车道,两边都派了 dev,第二个 PR 作废:浪费了一轮 dev。原规则只说「跨仓 + 关键词」,本仓已有的卡根本不在检查范围里。

风险与代价(含回滚) — 纯规则文本,不碰代码与发布包;风险是分诊多做一次按文件名的板面检索(成本很小)。回滚 = revert 这一个 commit,三行恢复原文。

席位意见 — (留空,席位定稿成评论)

你要做的 — 一个动作:APPROVE(受管面,需你的批准后由席位落地)。


Generated by Claude Code

…n board of both repos before keywords; same finding ⇒ duplicate_of, never a second dispatch

The triage band's shadow rows (:366–:368) read as a cross-repo keyword search
only. Two cards on one file and one defect were graded two days apart into
two lanes by the same seat, both dispatched, and the second PR closed as
superseded — the step that was missing is dedupe by FILE / MECHANISM against
the OPEN board (own repo and sibling repos, `pm:dispatched` included) before
keywords, with the finding — not the card — as the unit: the later card's
evidence moves to the earlier card and the later card closes `duplicate_of`.

Paid in-band at 812 / 812: the three rows are rewritten, no line added, no
re-wrap; every retired clause survives in the same band (see the PR body).

Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Sep 18, 2026
@os-elon-musk os-elon-musk added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ea2521bd92e63f3542333c5f5546084dfa51026b

① Derived judgments

② Semver level

  • skip-changeset is correct: .claude/** ships in no package's files[]. Clause-②: no on the claim (5727820576) and in the body; PM_SWEEP_REPO=objectstack-ai/objectstack node scripts/pm/check-clause2-carriers.mjs --pair 18981 at 2026-09-18T09:36Z: exit 0, one live claim, no widening tell.

③ Boundary flags

Implemented-by: claude/issue-18963-dedupe-by-file-at-grading
Reviewed-by: session_01BTeBejoPUvRHN8WdAJC6oF

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿)— PR #18981 · 席位定稿 2026-09-18T09:36Z(草稿在正文,以本评论为准)

改了什么:分诊规则里的三行「shadow 检查」改写成一条真正的查重步骤:定级时先按文件/机制查本仓与姊妹仓的全部 open 卡(含已派发的),再看引用与关键词;同文件同缺陷视为同一个发现、不分车道——证据搬到先卡,后卡以 duplicate_of 关闭,不再并排派发;其余命中沿用原来的三分法(在飞不派、未认领先并、已完成可能过期)。行数不变(812/812),只在原三行内改写,没有折行凑数。

为什么改:今天早上同一个文件、同一个缺陷的两张卡(#18314#18844)被同一个分诊席隔两天定进两条车道,两边都派了 dev,第二个 PR 作废——浪费一轮 dev。原规则只说「跨仓 + 关键词」,本仓已有的卡根本不在检查范围里。分诊席自己在 #18963 上认了这一步是缺的。

风险与代价(含回滚):纯规则文本,不碰代码与发布物;代价是分诊每张卡多做一次按文件名的板面检索。与在等你批准的 PR #18903#18921 同文件不同行段,谁后落谁先合 main。回滚 = revert 一个提交。

席位意见:建议批准。三行各在 120 B 之内,退掉的每个子句都有去处;「不分车道」四个字是关键——正是它让两条车道各自的分诊看见同一张卡。席位这边的另一半(认领前扫远端分支)是 #18964,另走 runbook。

你要做的:确认这条查重规则该进分诊纪律,是则 APPROVE(GOVERNED_APPROVERS 账户);之后由本席按裁决 C 落地。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 18, 2026 11:25
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Landing record — ruling C, on an authorized APPROVED (skills seat, session_01BTeBejoPUvRHN8WdAJC6oF) · 2026-09-18T11:27Z

os-zhuang (GOVERNED_APPROVERS) approved this PR (review 5247231818 at 2026-09-18T11:25Z), marked it ready and added it to the merge queue in the same minute — the two CCR calls this seat's channel could not make, made by the approver's own hand. The seat's pre-landing reads on head ea2521bd92: the review of record 5728142814 names this head; PM_SWEEP_REPO=objectstack-ai/objectstack node scripts/pm/check-clause2-carriers.mjs --pair 18981 exit 0 (card #18963); checks at 2026-09-18T11:25Z: 18 success · 16 skipped, none red. SKILL.md 812 / 812, hunks :363–:371, disjoint from PR #18903 and PR #18921 (the latter now queued ahead of it) — the queue rebuilds on the current main. needs-user-decision cleared by the seat now (the decision it marked has been made). The merge is the queue's; #18963 closes on it, and the seat clears its pm:dispatched / assignee residue after the merge lands.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants