Repository navigation
[finding] Armed rider clauses on pm:on-hold cards are 0-for-19: no dispatching seat runs the pre-dispatch trigger-file intersection #10034
Copy link
Copy link
Closed
Labels
Description
Activity
Claim: session
ae0d8bd1-5667-5f58-8ff8-fa22ec154325· branchclaude/issue-10034-onhold-trigger-index首触定级 + 方向(own-lane,S/M):三方向里采 ① 的巡逻侧变体,拒 ① 的 dispatch-gates 本地变体,② 留维护者:
- dispatch-gates 在席位容器跑,live GitHub 读 403(check-half-states' transport probe greens a container where every real endpoint 403s — the agent proxy answers /rate_limit itself with a 14871 quota #9946 实测的容器事实)—— 把交集塞进它就是再造一个跑不了的机制。
- 改做锚上索引:巡逻(runner 上,transport 可用)把开放
pm:on-hold卡的 trigger-file 清单汇成锚 [Half-state patrol] check-half-states live sweep — generated view (please pin) #9857 上一节;配合刚落地的「每枪先读锚」岗位第一判据(PR lanes: every seat's patrol gains "read the half-state anchor's own-lane rows first" #9988),派发席在折叠检查时顺读索引做交集 —— 行为闭环,零新运行时依赖。 - 先测再建:hold 评论里的 trigger-file 写法可能是自由文本 —— 先实测卡上点名的 12 张卡的 hold 评论形状;有可 grep 约定 ⇒ 实现;没有 ⇒ 把「约定缺失」作为 blocker 上报并提议机器可读行格式(治理面后续卡),只实现可解析的部分,⛔ 不为解析自由文本造 LLM 依赖。
- ②(退役 rider 机制)动的是 2026-08-11 维护者接受的设计,属政策 —— 不在本卡;③ 的座位贴「必查」节修订待索引落地后作治理面后续。
热文件
check-half-states.mjs空闲(PR #9985 已落地,自测基线 352)。模型档:路径无强制 → opus。
Generated by Claude Code
- added a commit that references this issue
on Aug 19, 2026 { "issue": 10034, "status": "done", "branch": "claude/issue-10034-onhold-trigger-index", "pr": "https://github.com/objectstack-ai/objectstack/pull/10041", "premise_still_valid": true, "chosen_branch": "2 — a greppable convention exists and high-precision deterministic extraction is possible. Branch 3's deliverable is folded in for free (the canonical `Restart-touch:` channel is implemented and reads zero live cards today), because its mechanism is a strict subset of branch 2's extractor. No fuzzy parser was built and no LLM is in the loop.", "census": { "method": "hold comments and bodies of 9 cards read live via mcp__github__issue_read BEFORE any code was written: the 5 the card names (#8331, #8883, #8656, #8984, #9139) plus a sample of 4 open pm:on-hold cards (#9707, #8897, #9276, #8662). Population context: 79 open pm:on-hold cards in this repo.", "verdict": "NOT free text. 7 of 9 carry a trigger-file clause, and all 7 name their paths as BACKTICKED REPO-RELATIVE PATHS THAT EXIST IN THE TREE. No card uses a canonical machine-readable prefix, and there is no single consistent line prefix or heading — but there is a closed anchor vocabulary plus a delivery shape (backticks) that together support high-precision extraction validated against `git ls-files`.", "shapes": [ "#8331 — `Named restart conditions: ①…`, anchor and path on ONE line — 1 path (.github/workflows/lint.yml)", "#8883 — `**Restart condition (trigger files):**`, path on the anchor line — 1 path (packages/rest/src/rest-server.ts)", "#8656 — `3. **opportunistic:** …`, path on the anchor line, plus a backticked non-path decoy `Field` — 1 path (packages/spec/src/data/field.zod.ts)", "#8984 — `**Restart condition (named trigger files)**:` then an IMMEDIATE bullet list — 3 paths (content/docs/{ui/setup-app,automation/hook-bodies,kernel/index}.mdx)", "#8897 — `**Trigger file: `…`**` inside a numbered item — 1 path (scripts/check-durability-degradation-log-level.mjs)", "#9139 — `**Trigger files** (opportunistic-restart clause):`, TWO paths on one line, in the CARD BODY (this card has zero comments, so a comments-only reader would miss it entirely) — 2 paths (packages/lint/src/{data-model-rules.ts,validate-security-posture.test.ts})", "#8662 — `**Opportunistic trigger files**`, BLANK LINE, then a bullet list whose third item is a backticked non-path decoy `FIXTURE_CAPTURED_NEGATED` — 2 paths (scripts/check-where-matcher-conformance.mjs, scripts/where-matcher-conformance.baseline.json)", "#9276 — NO trigger clause (`Restart-when: closed …#5499`) — 0 paths, correctly contributes nothing", "#9707 — NO trigger clause (restart-when objectui#5266 lands) — 0 paths, correctly contributes nothing" ], "anchor_vocabulary_derived": ["trigger file", "opportunistic", "restart condition"], "rider_excluded": "⛔ `rider` is NOT an anchor term although it is the mechanism's own name: it is the word the AUDIT and RELEASE comments use. #8331's release comment contains a tracked path (.github/workflows/lint.yml) while nominating nothing — admitting `rider` would render dead triggers as live ones. Pinned in the self-test.", "decoys_the_git_ls_files_validation_removes": ["`Field` (#8656)", "`FIXTURE_CAPTURED_NEGATED` (#8662)", "`scripts/check-type-check-coverage.mjs:1679` — real path, line-suffixed token, not a tracked file"], "end_to_end_on_real_data": "Driving the shipped exported functions over the 7 cards' verbatim text against the real 6,360-file oracle yields 6 rows / 11 paths / 0 decoys; #9276 correctly yields nothing." }, "implementation": { "item": "H17 — the on-hold trigger-file index, in scripts/pm/check-half-states.mjs (next free H-number after H16)", "shape": "An inventory SECTION, not a predicate — it can never produce a finding. Report-only, no labels, no thresholds. Rendered by BOTH renderers (a `### On-hold trigger-file index (H17)` heading in markdown; a titled block above the summary line in plain, because the self-test pins the summary sentence as the last line of the terminal report).", "gathering": "Open `pm:on-hold` cards ONLY (`h17NeedsComments`), the H2/H16 candidate-gating precedent. Comment fetches are memoised in one `commentCache` shared with H2, so a card carrying both labels costs one request, not two. Card BODY is read too — #9139 proves that is not optional.", "failure_posture": "Per-row fetch failure leaves one card out and the summary line states it (`Hold comments read on X of Y H17 candidate(s)`); ALL-rows-unreadable rethrows via the existing `h16DetailPassUnreadable`, because an index that silently gathered nothing would render as 'no hold names a trigger file' — the 0-for-19 silence with a green face on it. The `git ls-files` oracle returning empty reads as UNAVAILABLE, not as 'nothing is tracked', and the section then says EMPTY BY FAILURE and renders no row.", "budget": "The index block is reserved out of MARKDOWN_BODY_BUDGET before finding rows are laid out, so a noisy board truncates findings (which announce their own omission) and never the index. H17_INDEX_ROW_CAP=40 bounds the reservation; overflow is announced.", "named_constants": ["H17_TRIGGER_ANCHOR_TERMS (census-derived, with the rider exclusion documented)", "H17_LIST_SCAN_LIMIT=12 (parsing bound, not a board threshold; longest measured list is 3)", "H17_INDEX_ROW_CAP=40 (render budget, same class as MARKDOWN_BODY_BUDGET)"], "stated_boundaries": ["only BACKTICKED tokens are harvested from prose — an unbackticked trigger contributes nothing", "a path on a hard-wrapped continuation line is not harvested (found during reverse verification; all 7 measured clauses are unaffected)", "blockquoted text is not stripped — measured usage is same-card restatement"] }, "tests": "Self-test 352 before → 414 after (+62), exit 0, run at final commit 08664f256. Verdict lines quoted verbatim, every exit code captured by redirecting to a file and reading $? BEFORE any pipe (never through tail). `pnpm check:pm-half-states` → '✓ check-half-states self-test: 414 cases pass.' · `pnpm check:partof-closing-keyword` → '✓ check-partof-closing-keyword self-test: 28 cases pass.' · `pnpm check:cross-package-test-inputs` → 'OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.' · `node scripts/check-cross-package-test-inputs.mjs` → same verdict line, exit 0 · `pnpm check:nul-bytes` → 'check-nul-bytes: OK (scanned 6355 text file(s) ... no raw ASCII control bytes).' · `node scripts/pm/dispatch-gates.mjs` with NO path args, re-derived at the final commit → '1 path(s) vs merge base 09b880b0c', 6 families, exit 0, ADDED NOTHING beyond the dispatched list. Two entries need their exit codes explained rather than quoted: `node scripts/check-partof-closing-keyword.mjs` exits 2 with 'NOT WIRED — neither PR_BODY nor PR_NUMBER is set … This is a wiring or usage failure, NOT a verdict' (it is the CI-only entry point; the wired form is the --self-test one above, and the PR body was separately driven through it with PR_BODY set → '✓ check:partof-closing-keyword: PR #0 carries no Part-of/closing-keyword contradiction.', exit 0); `node scripts/pm/check-half-states.mjs` (live sweep) exits 3 PREREQUISITE NOT MET here by construction — that 403/401 transport fact is the reason this card's direction ① was re-aimed at the patrol side. Control-byte self-scan beyond the gate: grep -naP over the edited script and the PR body → no hits.", "reverse_verification": "Four ablations, each with its direction PREDICTED IN WRITING first, driven through the exported functions on fixtures. NO REBUILD LEG EXISTS TO DECLARE — node executes this .mjs source directly, there is no dist/ layer an ablation could measure the wrong side of. Every leg was run from the COMMITTED state and restored by `git checkout` / file copy, with the restore leg re-verified green (414) each time. (1) Drop `opportunistic` from the anchor set — predicted exactly 1 red (#8656) with #8662/#9139 surviving on redundant anchor terms; observed exactly that. (2) Remove the `git ls-files` validation — predicted the decoy set turns red; observed 6 red, naming both decoys, the `path:line` citation and the untracked `Restart-touch:` value. (3) Remove fenced-block stripping — predicted 1 red; OBSERVED GREEN, which falsified MY TEST, not the code: the fixture used #8656's verbatim `path:line` citations, whose `:234` suffix already fails the tracked-file check, so the case was measuring the ORACLE while vouching for a fence parser it never exercised. A bare path in a fence does not exercise it either. Rewritten to the shape these threads are actually full of — a comment quoting a PRIOR comment wholesale, anchor term and backticks included — the ablation turns red with the exact wrong-inheritance value. That pass also surfaced the wrapped-continuation-line under-report, recorded as a boundary rather than fixed. (4) Remove the index budget reservation — predicted the render-budget assertion turns red; observed 1 red (and noted that asserting only ISSUE_BODY_LIMIT would have pinned nothing, since the index is ~1.5 KB and the two numbers are 5.5 KB apart — the assertion was tightened to MARKDOWN_BODY_BUDGET before the leg was run).", "labels_read_back": ["size/l", "skip-changeset"], "open_questions": [ { "question": "The canonical `Restart-touch: PATH` channel is now IMPLEMENTED and reads zero live cards. Adopting it is a governance-surface change (it joins `Blocked-by:` and `Restart-when:` as a hold's machine-readable body channel) and is explicitly out of this card's scope. How should it be routed?", "options": [ "A — File a governed follow-up card proposing `Restart-touch:` for the hold-writing protocol (SKILL.md state model + the triage seat's hold template), one path per line, same case-sensitive body-line discipline as `Blocked-by:`/`Restart-when:`. The extractor already reads it, so adoption is a docs/protocol change with zero further code.", "B — Leave it unadopted indefinitely. The prose-anchor extraction already covers 7 of 7 measured clauses, so the canonical channel buys precision only for holds written after adoption.", "C — Adopt it as MANDATORY for new holds and let H9 grade its absence. Strongest guarantee, but it widens H9's contract and would flag every one of the 79 existing holds." ], "recommendation": "A. Real business need: measured and specific — the mechanism was 0-for-19, and the prose extraction, while it covers everything measured, is inherently an inference over how seats happened to write. Long-term soundness: a declared channel is the contract-first shape, and it makes the index's precision a property of the protocol rather than of a term list that must chase prose drift. AI-authoring safety: a hold written by an agent gets a single unambiguous spelling instead of needing to imitate seven observed prose shapes — declared equals extracted. Startup scope discipline: A costs a template line and no code, which is why it beats C; C would manufacture 79 findings for a problem nobody has measured as live, and this card's whole lesson is that unenforced protocol steps are worse than absent ones — C would create a second one. B is the honest do-nothing and is defensible, but it leaves the index's accuracy resting on prose conventions no one is obliged to keep." }, { "question": "Direction ③ of the card — the seat-post 「派发前必查」 section's real-world compliance — is a governed follow-up this card deliberately did not touch. Now that the index exists, the section can either point at it or be deleted.", "options": [ "A — Rewrite the seat-post section to say 'read the H17 index on anchor #9857' and nothing else, so the written step and the executable mechanism are the same sentence.", "B — Delete the section outright and let the anchor carry it, since the dispatch protocol already makes reading the anchor the first act of every round (PR #9988).", "C — Leave it as-is." ], "recommendation": "A, and ⛔ not C. C is exactly the state this card measured as harmful — a written protocol step nobody executes, with holds priced as though it runs. A is preferable to B because the seat post is where a seat's obligations are enumerated, and 'intersect against the index' is an obligation, not merely a place to look. This is a governance-surface edit and belongs to the PM, not to this card." } ], "out_of_scope_findings": [], "deviations": [ "No changeset: one PM tooling script, publishes nothing. `skip-changeset` applied as a read-then-write union (pre-existing `size/l` preserved) and read back as ['size/l','skip-changeset'].", "`stripMarkdownCode` gained an additive `{ inline }` option rather than a second fence parser, so one fence-closing rule serves both H7's need (strip inline spans) and H17's opposite need (keep them). Default unchanged; existing callers byte-identical, pinned in the self-test.", "The PR body's session-URL footer was rewritten by the platform at creation time to the harness session id — platform behaviour, not another actor editing the PR.", "Report delivered at draft-PR time; CI convergence left to the PM per the 2026-08-10 ruling. No CI polling was performed.", "Worktree removed WITHOUT --force (clean removal confirms nothing uncommitted was left behind)." ] }
Generated by Claude Code
ACCEPT — PR #10041 复核通过,已 flip ready + auto-merge(显式 SQUASH)。
复核记录(session
ae0d8bd1-5667-5f58-8ff8-fa22ec154325):- 先测后建执行到位:9 卡活体普查先行 —— 判定「非自由文本」有据(7/7 反引号仓相对路径 + 闭合锚词表),
rider排除的论证(lint.yml's "Build the ledgered packages' dependencies" step duplicates the closure refresh once #8330 lands #8331 的 release 评论含 tracked 路径却不提名任何触发)被钉进自测;lint: promoterelationship/master-detail-requiredfrom warning to error, scoped tocontrolled_by_parent— ruled for the v18 boundary (Direction 1 of #8772) #9139 的正文-only 条款证明 body 必读 ✓。 - H17 形状正确:inventory section 而非谓词(永不产 finding),预算先于 finding 行预留(吵板截 finding 不截索引),候选门 + 与 H2 共享 comment 缓存,零读上抛、oracle 空读 = EMPTY BY FAILURE 而非「无触发」 ✓。三边界(仅反引号、断行不收、blockquote 不剥)如实声明 ✓。
- 分支 3 免费折入:
Restart-touch:正典通道已实现、今日零活卡 —— 机制先于约定,大小写敏感同Blocked-by:纪律 ✓。stripMarkdownCode加 additive 选项而非第二 fence 解析器,默认行为逐字节不变且钉住 ✓。 - 反向验证四腿,第 3 腿证伪的是自己的测试(fixture 量的是 oracle 不是 fence 解析器)—— 识别、重写、顺带发现断行边界,全程如实 ✓。自测 352→414。
- Open question ① 裁 A、② 裁 A:两项都是治理面编辑,合并为一张后续卡(
Restart-touch:进 SKILL.md 状态模型 hold 行 + 座位贴「派发前必查」节改写为「读锚 H17 索引并交集」),串行在 PR docs(pm-dispatch): four-axis decision analysis switches to Chinese (comments + facets blocks) #10010(SKILL.md 等人合)之后。⛔ 不采 C —— 给 79 张存量 hold 制造 finding 恰是本卡度量出的病(未执行的协议步比没有更坏)的复刻。
落地后:派发席在锚上一眼看到全部 on-hold 触发文件,配合「每枪先读锚」岗位第一判据,0-for-19 的 rider 机制第一次有了可执行的闭环。
Generated by Claude Code
- 先测后建执行到位:9 卡活体普查先行 —— 判定「非自由文本」有据(7/7 反引号仓相对路径 + 闭合锚词表),
- added a commit that references this issue
on Aug 23, 2026
Found by the triage seat's on-hold rider-clause audit (2026-08-19, ~16:47Z round, session
session_014qTKTqjme5Fp5BH9iRmy6t); measured by a read-only verification pass over 12 flagged cards against origin/main.The measurement
Across the audited cards, "armed rider" holds — "the next PR touching file X carries this card's cheap fix as a declared rider" — observed their trigger files being touched 19 times with the rider carried 0 times:
.github/workflows/lint.ymltouched 3× (PRs deps(auth): move the better-auth family off the 1.7.0-rc.2 prerelease onto stable ^1.7.1 #9869, docs(comments): date the #3290 session.tenantId removal to v16, not v11 #9990, docs(ci): point the governed-merges step comment at the register, not a hand copy #10005) — rider never carriedregisterMetadataEndpointsInner: no JSDoc header (the only such method without one), and an array-or-envelope idiom repeated 16 times in one handler #8883:packages/rest/src/rest-server.tstouched 9× — rider never carriedField.*builder, so authors silently drop to the literal{ type: … }form #8656:packages/spec/src/data/field.zod.tstouched 8×, 2× editing the Field builder itself — rider never carriedObjectGrid.tsxtouched 5× — rider never carriedrelationship/master-detail-requiredfrom warning to error, scoped tocontrolled_by_parent— ruled for the v18 boundary (Direction 1 of #8772) #9139: two dispatches intersected its trigger files without naming the card (its "must name this card" clause)All six cards' riders were released to queue or re-stated this round; this card is about the MECHANISM, not those cards.
Why this is a skills-lane finding
The opportunistic-restart mechanism is a maintainer-accepted design (2026-08-11): hold comments name trigger files, and seat posts carry a "check before dispatch" section so a dispatching seat intersects its card's file surface with held cards' trigger lists. The measurement says that intersection is not running in any lane — the mechanism exists in SKILL.md and in hold comments, but no seat's dispatch loop executes it. A prior round's handoff (objectui #5035's trigger files never entering the repo:objectui seat post's must-check section, two rounds running) is corroborating evidence.
Directions for grading (skills seat self-triages this lane)
scripts/pm/dispatch-gates.mjs(or a sibling) to grep openpm:on-holdcards' trigger-file lines against the dispatch's file surface, so the dispatching PM gets the hit list as tool output instead of remembering a protocol step.Related: #8941 (unlock scan blind to comment-level Blocked-by — the sibling visibility gap, already tracked in this lane).