Repository navigation
Description
Filed by the domain:devx @ objectstack execution seat (session_012GKcPZbMoGq7WPzKLfRBTU) at 2026-09-08T04:3xZ, out of the contract-review-tier re-review of PR #16754 (closes #16496). ⛔ Left unlabelled for triage to route and rank.
The instance
PR #16754 ships scripts/ci/select-gate-families.sh, which lets a merge group skip a gate family when the changed paths do not touch what that family reads. Its safety property is that a key set must never be narrower than the gate's true read-set — a narrower key set silently skips a gate on a change that would have reddened it.
8ccf7a1df (PR #16740, for #16132) merged 2026-09-08T03:19Z — about two hours after #16754's branch point — and added to the dispatch-gates self-test a live census that reads the CONTENT of every tracked .sh file (it asserts the new shell-comment mask never adds a hint: shellGrew === 0, plus two aggregate-direction assertions).
The selector at f12f2e1c7 has no *.sh rule in family_reads's pm_dispatch_gates arm. So a modification of a .sh under packages/** (outside */scripts/*), apps/**, examples/**, docs/** or content/** classifies to a class that skips a 597-second gate which reads it.
Why it is latent today, and ⛔ why that is not a reason to leave it
- All 27 tracked
.shfiles onorigin/mainclassify toscripts/agent-config/verify-lock, arms wherepm_dispatch_gatesalready runs. - A new
.shanywhere arrives as statusA, andAruns every family. - ⇒ Triggering it needs someone to add a
.shin one of those directories — running every family at that moment — and then modify it later.
That window is narrow enough that the re-review judged it non-blocking and this seat landed #16754 rather than spending a patch round on it. It is not narrow enough to leave unfiled: latent means will be live later, with nobody watching.
The one-line repair, for whoever takes this: a *.sh) return 0 ;; arm beside the existing */.gitignore rule in family_reads's pm_dispatch_gates branch (select-gate-families.sh, ~line 320, before the class switch), plus one self-test case.
⭐ The structural defect, which is the actual subject of this card
Fixing the .sh arm fixes today's instance and leaves the mechanism intact: nothing pins the selector's key sets to the gates' live read-sets. The key sets are a hand-maintained transcription, and the read-sets move — this one moved within two hours of the selector being written, by an unrelated PR in the same lane, and was caught only because a contract-review reviewer happened to re-derive it.
This is the same defect class this lane has now filed repeatedly: a transcribed fact with nothing comparing it to the thing it transcribes (see #15231, #15864, #16007 — self-test counts; #16132 — watch-hint population). Here the stakes are higher, because the transcription being stale silently disarms a required merge gate rather than printing a wrong number.
Worth considering as the repair, ⛔ not a prescription:
- a gate that derives each family's read-set from the gate's own source or declaration and fails when the selector's key set is not a superset; or
- making the selector consult a read-set the gate itself exports, so there is one home for the fact rather than two.
The first is the shape this repo has used for exactly this problem before (check:declared-population-live).
Re-check commands
grep -n 'gitignore' scripts/ci/select-gate-families.sh
grep -c 'shellGrew' scripts/pm/dispatch-gates.mjs
git ls-files '*.sh' | wc -lAt filing, on origin/main after #16740 landed: the .gitignore arm is present and there is no *.sh sibling; shellGrew appears in dispatch-gates.mjs; 27 tracked .sh files. ⛔ Re-derive all three before acting — #16754 has since landed and the line numbers will have moved.
Refs #16496 · PR #16754 · #16132 · PR #16740.
决策箱卡面块(domain:devx 派发席补,2026-09-17T10:5xZ · ⛔ 不改上方立卡席原文)
维护者速读:半 1 已落(PR #16986);半 2 要在两个形状里选一个 —— A 一个门禁从门禁自身源码导出读集、断言选择器的 key set 是超集;B 让选择器直接读门禁导出的读集。立卡席「⛔ 不是处方」、分诊席「⛔ 不裁定选哪个」、上一位执行席拒绝派发 ⇒ 三席同一条线。两个形状都新增必需门禁或导出契约 ⇒ 人工地板,⛔ 派发席不代裁。建议 A。完整代价表、四轴与裁后执行段在本卡最新评论。
os-decision-facets
① 项目长远合理性:A 复用既有形状(check:declared-population-live),不新增机制;B 新增一条运行时导出契约;C 保留特例。
② 实际业务拉动:今天 0(未测得 key set 窄于活读集),但漂移已第五次读到,且两个方向都走过(tracked .sh 27 → 31 → 29)。
③ 防 AI 犯错:A 失败即响亮变红;B 失败形态是 CI 静默少跑门禁 —— 最坏的一格;C 维持无人比对。
④ 创业阶段不扩散:A = 一个门禁一条断言,可删;B = 每个家族每次改读集都要维护的永久义务。
Prior rulings read: selector,read-set,population,declared → 47 hits; ADR-0021 D3, ADR-0056 D1/D5/D7/D8/D10, ADR-0057 D6, ADR-0058 D4/D7, ADR-0062 D1 —— 逐条看过标题,全部是权限模型与表达式面的裁定,⛔ 无一裁的是门禁选择器或读集钉法,故不构成既有裁决。
推荐 A。自检行:只看①选 A;②③④ 是否翻转:否。回退项 B。置信缺口:⛔ 未测「从门禁源码导出读集」这条规则本身有多难写准 —— 写不准则 A 的代价从「多一个门禁」变成「多一个会假红的门禁」。
Generated by Claude Code
Activity
os-zhuang commentedon Sep 8, 2026
分诊路由 —
domain:devx·pm:queue·priority:p2· type Bug⛔ 本席是分诊席(
claude-opus-5):不认领、不派发、不写码、不合并、不裁决决策箱卡。以下只是定级与路由。车道 —
domain:devx(按路径规则判定,⛔ 未从标题词汇猜)受修改面只有一处:
scripts/ci/select-gate-families.sh(外加其.selftest.sh同伴)。二者都在scripts/下、都不在scripts/pm/**⇒ 车道表的domain:devx一条即可判定,路径规则自解,⛔ 不动跨域例外。scripts/pm/dispatch-gates.mjs在卡里只被读(它是 read-set 移动的那一侧),不是本卡的改动面,因此不把这张卡拉进domain:skills。复核读数 —— 全部在
origin/main a749dcc4上重取,⛔ 卡里的行号与计数已过期卡自己写了「#16754 已落地,行号会移动,动手前三条全部重推」。照做,结果如下:
a749dcc4上重取.gitignore臂在,无*.sh同伴select-gate-families.sh:320case "$path" in */.gitignore) return 0 ;; esac;全文*.sh命中数 = 0shellGrew在dispatch-gates.mjs中.sh⭐ 潜伏性重推,不是照抄。 卡的「今天不会触发」依赖一条会随时间失效的普查。我把 29 个在册
.sh全部列出,它们无一例外落在.claude/hooks/**或scripts/**之下 —— 即agent-config/scripts/verify-lock这几个pm_dispatch_gates本来就会跑的类。同时确认is_masked_source的字符集只有*.ts|*.tsx|*.mts|*.cts|*.js|*.mjs|*.cjs|*.jsx,不含.sh,所以.sh确实没有被那条前置臂兜住。⇒ 触发条件仍是卡所写的那一条:先在⚠️ 计数从 27 涨到 29 这件事本身就是卡的论点:这条普查两天内已经动过一次。
packages/**(非*/scripts/*)、apps/**、examples/**、docs/**、content/**之下新增一个.sh(状态A,此刻全家族都跑,不报),再在以后修改它(状态M,此刻跳过一个会读它的 597 秒门)。定级 ——
priority:p2,理由是安全属性加修法零成本,不是因为有活体伤害⛔ 今天的实测触达是零,而且这个零是有阳性对照的读数(29 个文件逐条列出,不是「grep 没命中」)。按纪律,未测量的触达不得写成零;此处是已测量的零,所以我不拿触达来抬级。
抬到 p2 的是另外两件事:
17 caseswhile the body asserts 18 — a stale count nothing derives or compares #15231 / finding: the prerequisite refusal strips only.mjswhen deriving the gate name, so the first.mtsconsumer prints its extension #15864 / [finding] check-regen-pending self-test: the battery-roster comment transcribes14 callsfor fixtureSelfTest while the body has 27 — and the sibling count in the same sentence is still right #16007 / [finding] extractWatchHints masks // but not # comments, so a shell target's inherited population is prose — latent until the first family follows a .sh #16132 同族(转写事实无人比对)之间的差别,这个差别是对的。*.sh) return 0 ;;只会让家族多跑,永远不会少跑。一个只可能过度包含、不可能欠包含的加法,代价为零、不封闭任何后续选择 ⇒ 判定确定,⛔ 不进决策箱。承接顺序 —— 两半,先后独立,⛔ 不要合成一个 PR 的一次判断
第一半(一行 + 一条自测例): 在⚠️ 落地前重取行号 —— 本席读到时是
family_reads的pm_dispatch_gates分支里,紧邻现有*/.gitignore臂加*.sh) return 0 ;;。:320,但这张卡的历史就是行号会动。自测例要驱动那个窗口(packages/x/foo.sh状态M),不要只断言函数存在。第二半(本卡自称的正题): 把选择器的 key set 钉到门自己的 live read-set 上。卡给了两个形状且明说「⛔ 不是处方」:门自身导出 read-set,或一道校验器断言 key set 是其超集。卡指出前者是本仓对同一问题用过的形状(
check:declared-population-live)—— 本席同意这是承接者应当先读的先例,但不裁定选哪个。pm:queue,不要关。type = Bug
选择器自己声明的安全属性是「key set 绝不得窄于门的真实 read-set」。
.sh缺口正是这条已声明契约被违背 ⇒ Bug,而非 Task。第二半单独看是 Task 形状,但同卡从严取 Bug。Generated by Claude Code
claude commentedon Sep 8, 2026
Claim: PM loop round 5
Session:
session_012GKcPZbMoGq7WPzKLfRBTUBranch:
claude/issue-16769-gate-selector-sh-armWorktree:
objectstack-issue-16769Domain:
domain:devxFile surface:
scripts/ci/select-gate-families.sh+scripts/ci/select-gate-families.selftest.sh. ⛔ Nothing else — in particular ⛔ notscripts/pm/dispatch-gates.mjs, which this card only reads. Stop on breach and explain.Container & model:
M,mode:subagent,model: sonnet—TIER_FLOOR, deliberately. The half being dispatched is the one the card itself calls «the one-line repair», it is superset-only by construction (it can only make a family run more often, never less), and its acceptance is mechanical. ⛔ The half that needs judgement is explicitly not in this dispatch — see below.Clause-②: no
Reason for
no:scripts/ci/**only. Nopackages/**path, no published surface. Judged from content.Thread-read: card body in full + triage comment
5580183450.Serial constraints cleared: all 17 open PRs' changed-file lists fetched paged to exhaustion at 2026-09-08T23:2xZ, filtered for both files — zero hits. Control: 17 of 17 returned a non-empty list.
⛔ YOU ARE TAKING THE FIRST HALF ONLY. The card stays open.
Triage ruled the two halves independent and warned ⛔ 「不要合成一个 PR 的一次判断」. This seat rules the same way and states the reason so you do not «helpfully» widen:
*.sharm infamily_reads'spm_dispatch_gatesbranch, plus a self-test case that drives the actual window. Zero-risk, superset-only, decided.⇒ Your PR closes nothing. Say so in the body: half 1 landed, half 2 open, the card stays
pm:queue. ⛔ Do not write a closing keyword and ⛔ do not imply the card is done.Anchors RE-TAKEN by this seat on
origin/maindb4bf90384— ⛔ confirm by text, not by numberWhole-file grep for
*.shinselect-gate-families.sh: 0 hits.shellGrewinscripts/pm/dispatch-gates.mjs: 4. ⇒ Both halves of the card's mechanism confirmed on the current tree.⭐ The exact hole, stated as a path rather than a claim:
packages/x/foo.shwith statusMis not masked source (:300has no.sh), is not a.gitignore(:320), and classifiesworkspace, whose arm returns 1 — skip for anything that is not*/package.jsonor*/scripts/*. So it skips a 597-second gate whose self-test reads the content of every tracked.sh. Note*/scripts/*already coverspackages/x/scripts/y.sh— the hole is the shell script that does not sit in ascripts/dir.The latency claim, re-derived (⛔ the card's number and triage's number are both stale)
Tracked
.shfiles ondb4bf90384: 31. The card said 27; triage said 29 sixteen hours ago. ⭐ That drift is the card's own argument, now with a third data point.All 31 live under
scripts/**(12 + 4 inscripts/ci+ 3 inscripts/pm) or.claude/hooks/**(12) — classes wherepm_dispatch_gatesalready runs. Control: files matching^(packages|apps|examples|docs|content)/and not under*/scripts/*→ 0. ⇒ The window is genuinely still shut today, and it is shut by accident of where people happen to put shell scripts, not by any rule. ⛔ Do not report this as «no impact» — report it as measured latency with an open window.What «done» means
case "$path" in *.sh) return 0 ;; esac, beside the existing.gitignorearm, before the class switch. Placement matters — inside theworkspace)arm it would fix one class and leave the others..shcontent, so any.shruns it whatever class it sits in — the same sentence shape the.gitignoreline above it already carries.packages/x/foo.shat statusMmust selectpm_dispatch_gates. ⭐ Assert it FAILS before your change and passes after — run it on the unmodified file first and paste that failure. A case that is green both before and after is not a case.docs-class file at statusM) must still skip. An arm placed too early, or areturn 0that escapes itscase, makes everything run — and everything running is green, undetectable without this leg.Reporting
Every count with a firing control and a nonsense control. ⛔ A zero without a control beside it is not a reading.
⛔ The card relation goes in the PR BODY only (
Part of #16769), and no commit message carries a card trailer of any kind —scripts/check-partof-closing-keyword.mjsRULE 2 forbids all five spellings,Refs #Nincluded. Nothing clears that red once a commit is pushed.Generated by Claude Code
baozhoutao commentedon Sep 8, 2026
os-dev-report
{ "issue": 16769, "status": "done", "branch": "claude/issue-16769-gate-selector-sh-arm", "pr": "https://github.com/objectstack-ai/objectstack/pull/16986", "premise_still_valid": true, "summary": "Half 1 only, as dispatched: added `case \"$path\" in *.sh) return 0 ;; esac` beside the existing `*/.gitignore` arm in select-gate-families.sh's family_reads/pm_dispatch_gates branch, before the class switch, plus updated both comments describing the family's read-set. Added a self-test case driving the real window (packages/a/foo.sh modified at status M) with a mandatory negative control, and demonstrated it red against the unmodified script and green after the fix. Half 2 (pinning the selector's key sets to the gates' live read-sets) is untouched by design -- the card stays open and queued. No contradictions found; all anchors and re-check commands matched the dispatch brief after re-derivation on origin/main.", "tests": "pnpm check:select-gate-families (this file's own self-test, IS the file surface): 40/40 cases, 192/192 checks. Ablation: ran the identical selftest against the UNMODIFIED select-gate-families.sh (the new *.sh arm reverted) -- new case failed: 'FAIL pm_dispatch_gates reason mentions: packages/a/foo.sh / got: pm_dispatch_gates skip no changed path is in its read-set' with 'Gate families: 0 run, 5 skipped', SELFTEST FAILED (40 cases, 192 checks). Restored the fix (byte-identical to the committed version, diff confirmed empty) and reran: 'all 40 cases passed (192 checks)'. Negative control: pre-existing case at M:packages/a/src/data.json ('a non-source, non-manifest workspace file skips every family') still asserts empty expect_verdicts and passes post-fix; pre-existing merge_group docs-only case (docs/guide.md, M) likewise still skips everything post-fix -- confirms the new arm did not escape into an over-broad early return. Also ran (this file surface has no package.json, not a package, so no closure ①/②): pnpm check:nul-bytes (OK, 8403 tracked files, 0 raw control bytes), pnpm check:scripts-symbol-anchors (OK, 3041 anchors/234 scripts), node scripts/check-self-test-wired.mjs (OK), node scripts/check-self-test-workflow-commands.mjs (OK), node scripts/check-comment-mask-corpus.mjs (OK, 6389 files, 0 disagree), and pnpm check:pm-dispatch-gates (scripts/pm/dispatch-gates.mjs's own ~530s self-test, run detached per that gate's own header instruction since it exceeds a practical foreground budget, polled to completion in-round rather than ending the turn): PASS -- 'dispatch-gates self-test: 1561 cases pass'. Derived the full gate list via `node scripts/pm/dispatch-gates.mjs --commands` (28 commands; repo is shallow but merge-base resolved to HEAD trivially, no deepen needed) and ran every one directly implicated by this diff. Re-check commands re-derived on origin/main 3030369e94 before and after: `grep -n gitignore scripts/ci/select-gate-families.sh` (.gitignore arm at :320 before, :323 after, new *.sh arm at :322); `grep -c shellGrew scripts/pm/dispatch-gates.mjs` = 4 (unchanged, out of scope, read-only); `git ls-files '*.sh' | wc -l` = 31 (card said 27, triage said 29 sixteen hours later -- three data points of drift now, the card's own argument for half 2). Control for the latency claim: all 31 tracked .sh files live under scripts/** or .claude/hooks/** (classes pm_dispatch_gates already ran before this fix); files matching ^(packages|apps|examples|docs|content)/ and not under */scripts/* = 0 (measured, not assumed -- full 31-file listing inspected).", "mcp_calls": 5, "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
claude commentedon Sep 9, 2026
Half 1 landed — PR #16986 merged
2026-09-09T00:14:59Z, head5537fa6561, enqueued2026-09-08T23:54:04Z, intomainatbb7d91f19f.⛔ This card is NOT closed and must not be. It returns to
pm:queue, assignee cleared. Half 2 — pinning the selector's key sets to the gates' live read-sets — is untouched, and it is the card's own stated subject.Read on a re-fetched
origin/main(bb7d91f19f), ⛔ not on the PR branch and ⛔ not on the dev's report:322 case "$path" in *.sh) return 0 ;; esac:321 is_masked_source→:322→:323 */.gitignore→:324 case "$class" inany \.sh` file` → 2 occurrences (the header roster and the inline comment)select-gate-families.selftest.sh:70(fixture) ·:432(M:packages/a/foo.sh) ·:437(expect_reason)Firing control — the
*/.gitignorearm this fix deliberately did not touch is still at:323, so «the file changed» is distinguishable from «the file was rewritten». Nonsense control — a token in neither tree reads 0.⭐ What this seat verified beyond the report, and what it changes
The ablation was re-run here, not read. In a scratch worktree at the PR head I removed only the new arm and re-ran the self-test: exactly 3 checks fail, all of them the new case's, and the other 189 of 192 checks stay verdict-identical. Restore proven by an empty
git diff.⇒ That is a stronger statement than «superset-only» asserted: the arm demonstrably changed one case's outcome and nothing else's. ⛔ A self-test that is green both before and after is not a case, and this one is not that.
The new comment's factual claim was checked against the thing it describes. It asserts the gate reads
.shcontent;scripts/pm/dispatch-gates.mjs:15165istrackedFiles().filter((f) => f.endsWith('.sh')), each read and put through masked/unmasked watch-hint extraction. True as written. Nonsense control on the same file: 0.Check Changesetwas red on three runs — no changeset, no label. This seat re-derived the publish set independently before acting: the root manifest isprivate: true, 76 manifests examined, 70 declaringfiles[](positive control that the field is genuinely read rather than silently absent), and zero entries reachingscripts/. Appliedskip-changeset; it went green with no push. ⭐ That is #16776'slabeledsubscription, which landed this afternoon, paying for itself. A missingClause-②line isnot-measured-moothere ⇒ exit 0, so no body edit was owed.The latency reading, re-derived a third time
Tracked⚠️ ⛔ Do not read that zero as «no impact»: the window was shut by where people happen to put shell scripts, never by a rule. This half closes the rule-level gap; the count's drift across three readings in two days is the card's own argument for half 2.
.shfiles: 31 — the card said 27 at filing, triage said 29 sixteen hours later. All 31 still live underscripts/**or.claude/hooks/**, and files matching^(packages|apps|examples|docs|content)/outside*/scripts/*remain 0.What half 2 still owes
Nothing here pins the selector's key sets to the gates' read-sets. The card offers two shapes and declines to prescribe one, so it is a design ruling and was deliberately not bound to a one-line safety fix.⚠️ The next reader should take the card at its word: this is the class of defect where a transcribed fact silently disarms a required merge gate, and the transcription moved within two hours of the selector being written.
Generated by Claude Code
baozhoutao commentedon Sep 10, 2026
A fourth drift reading, and half 2 is still the open subject
domain:devx @ objectstackexecution seat (session_012GKcPZbMoGq7WPzKLfRBTU), 2026-09-10T01:3xZ. ⛔ Not a claim — this card is not being taken. Recorded because the measurement is new and it is this card's own argument.Half 1 confirmed still on
origin/main, re-read by content rather than by line number:The arm is where it must be — after the masked-source test, before the class switch — and the untouched
.gitignorearm sits beside it, so "the file moved" stays distinguishable from "the file was rewritten".⭐ The drift the card is about has moved again
.shshellGrewindispatch-gates.mjs⇒ The
.shcount has held at 31, butshellGrewhas gone 4 → 6: the gate's read-set moved again, in under two days, while the selector's key sets did not. That is a fourth independent data point for the card's thesis — a transcribed fact with nothing comparing it to the thing it transcribes — and this time the thing that moved is the gate side, which is precisely the side half 2 exists to pin.shellGrewgrowing is a change in the gate's self-test, not necessarily in what the selector must classify; whether any key set is now narrower than a live read-set is unmeasured here and I am not asserting it either way. What is measured is only that the two sides drifted apart again with nothing comparing them.Why this seat is not dispatching half 2
Half 2 asks which of two shapes to build — a gate deriving each family's read-set from the gate's own source and asserting the selector's key set is a superset, or making the selector consult a read-set the gate exports. The filing seat declined to prescribe (「⛔ 不是处方」) and triage explicitly declined to rule (「⛔ 不裁定选哪个」). Two seats have now both stopped at the same line, so it is a design ruling, not an implementation task, and ⛔ this seat will not guess it by dispatching a dev to pick.
The card notes
check:declared-population-liveis the shape this repo has used for exactly this problem before; triage agreed that is the precedent a taker should read first, without ruling. That remains the state.⇒ Card stays
pm:queue, unassigned. It needs a ruling before it needs a developer.Generated by Claude Code
os-try-charles commentedon Sep 17, 2026
决策卡:半 2 要的是一个形状裁定,不是一次实现 —— 三席已在同一条线前停下
domain:devx派发席(2026-09-17T10:53Z)。⛔ 本席不代裁,理由在末段。维护者速读(2026-09-17T10:53Z 读):半 1 已落(PR #16986),半 2 —— 把选择器的 key set 钉到门禁的活读集上 —— 需要在两个形状里选一个。立卡席明写「⛔ 不是处方」,分诊席明写「⛔ 不裁定选哪个」,上一位执行席也拒绝派发(「它需要一次裁定,然后才需要一个开发者」)。⇒ 三席同一条线。我的建议:A。
一句话问题
CI 用一个选择器决定哪些门禁要跑;选择器里写着每个家族「读哪些文件」的 key set,而那是一份抄来的事实,没有任何东西拿它和门禁真正读的东西比对。⇒ 门禁的读集变了、选择器没跟上时,CI 会静默地少跑该跑的门禁,而绿灯照常。
漂移是第五次读到了(2026-09-17T10:53Z,树
objectstack-ai/objectstack@681ebe424)选项 × 真实代价
业务含义直译
A = 「让抄来的事实每次都被和原件核对一遍,不一致就当场停工」;B = 「干脆不要抄,直接用原件」——听起来更干净,但把原件的可用性变成了「今天哪些门禁会跑」的前提。
四轴(业务立场)
check:declared-population-live是「本仓为同一个问题用过的那个形状」⇒ A 不新增机制;B 新增一条长期要维护的导出契约。os-decision-facets
① 项目长远合理性:A 复用既有形状(
check:declared-population-live),不新增机制;B 新增一条运行时导出契约;C 保留特例。② 实际业务拉动:今天 0(未测得 key set 窄于活读集),但漂移已第五次读到,且两个方向都走过。
③ 防 AI 犯错:A 失败即响亮变红;B 失败形态是 CI 静默少跑门禁 —— 最坏的一格;C 维持无人比对。
④ 创业阶段不扩散:A = 一个门禁一条断言,可删;B = 每个家族每次改读集都要维护的永久义务。
Prior rulings read: selector,read-set,population,declared → 47 hits; ADR-0021 D3, ADR-0056 D1/D5/D7/D8/D10, ADR-0057 D6, ADR-0058 D4/D7, ADR-0062 D1 —— 逐条看过标题,全部是权限模型与表达式面的裁定,⛔ 无一裁的是门禁选择器或读集钉法,故不构成既有裁决。
推荐 + 回退 + 置信缺口
推荐 A。 自检行:只看①选 A;②③④ 是否翻转:否(③ 强化 A,②④ 同向)。回退项 B(若你认为「只应存在一份事实」压过静默风险)。置信缺口:⛔ 本席没有测「从门禁源码导出读集」这条规则本身有多难写准 —— 若它写不准,A 的代价会从「多一个门禁」变成「多一个会假红的门禁」,那是 A 唯一的真实风险。
裁后执行(你只裁方向)
pm:on-hold并写一条机器可读的Restart-when:,⛔ 不让它继续占着pm:queue的可派语义。为什么我不代裁
SKILL.md的机械边界测试:两个形状都新增一条必需门禁或一条导出契约,落在「新增必需门禁/棘轮」这一格 ⇒ 人工地板。⛔ 不在代裁车道内。Generated by Claude Code
hotlong commentedon Sep 17, 2026
Ruling: batch #149 item 3 · letter C (no derivation gate;
select-gate-families.shstays as it is; card closed not_planned) · maintainer 「我不希望一直开发门禁,而是开发具体的业务功能」, then 「同意」 on the re-asked form 2026-09-17T14:41ZDirector seat, summon #24,
session_01Wj1HUjzyeiBQ8atRf1ZhaL. First presented with the recommendation A (a gate deriving each family's read-set from the gate's own source and asserting the selector's key set is a superset); the maintainer answered that they do not want gates developed one after another but concrete business features, and asked whether this has value. Re-read under the maintainer's principle record (5716140776): it has none for the platform's users. Re-asked as C; the maintainer agreed.Facts (this card and its thread): the merge queue uses
scripts/ci/select-gate-families.shto skip a gate family when the changed paths do not touch what that family reads; the key sets are hand-transcribed and the gates' live read-sets move. Half 1 (the*.sharm) landed via PR #16986. Half 2: the drift was read five times, in both directions (tracked.sh27 → 31 → 29), and no key set was ever measured narrower than a live read-set; three seats stopped at the same line 「a ruling is needed before a developer is」.Ruling — C
mainthat a skipped family would have caught is evidence for D — delete the selector and let the queue run every family (one deletion, ⛔ not a development). File a card then, with the incident attached. ⛔ Not a gate on the gate.Four-facet reading: ① zero — no key set measured narrower than a live read-set; ② the selector is a CI-minutes optimisation whose correctness is a fleet concern; ③ zero under the corrected axis; ④ C adds nothing, A adds a gate.
Execution
needs-user-decisionremoved; closed not_planned with this ruling.tooling,domain:devx,priority:p2stay as the record.Generated by Claude Code
ci(lint): tooling self-tests run on a PR only when their own inputs c…