Repository navigation
[finding] check:cross-package-test-inputs cannot red an undeclared tree-scoped walk inside an already-declared package — the seed escape depth is computed but never asserted #15565
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 4, 2026 Triage routing:
pm:queue;domain:devx+tooling+priority:p2+finding保留(已正确)。
并回答卡面留给分诊的那个问题:⇒ 先收窄 mandate,再断言收窄后的半径。理由见末节。分诊席(
session_01SwJQDFKe8tVit3BXQ9EfR5,R+161)。⛔ 本席不认领、不派工、不写代码。定级与车道维持
domain:devx—— 主交付物是scripts/check-cross-package-test-inputs.mjs的一条判定肢,scripts/ gates归 devx。⚠️ 但见末节:若按本席的建议先收窄 mandate,那一半落在skills/spec-property-retirement(governed surface),需 draft PR + 人工合并。⇒ 两个 PR、两条车道,本卡保留 devx 作为主车道。priority:p2—— 维持。这不是"门少了个功能",而是一条 mandate 只由散文托着:卡面第一句说得最准 ——「That rule is prose, and prose is the only thing holding it」。而它守的是退休 playbook 的 tree-scoped 缺席钉,正是"声明了但没人执行"的那一类。五肢盲区:卡的论证是穷举式的,值得原样保留
卡把
verify()的五问逐条列出,并逐条说明为什么每一条都看不见 tree-scoped 走查:- 一个
readdirSync在循环变量上的下降不 NAME 任何字面量 ⇒ 肢 3 看不见; - 它不 ADD 任何 glob ⇒ 肢 4、5 看不见;
- 而在一个已经有表项的包里(
@objectstack/spec就有)⇒ 肢 1、2 已被该包的其他逃逸测试满足。
⇒ 结论「一条新的 tree-scoped 缺席钉可以带着整个未哈希的半径落进
packages/spec,而这道门 exit 0 且一个字都不报」成立。⭐ 这种"逐条排除所有现有防线"的论证方式,比"我觉得有个洞"强得多,⛔ 接手时别把这段压缩掉——它就是这条肢的验收清单(新肢落地后,五问之外的第六问必须能红)。⭐ 缺失肢的输入已经存在,这是本卡最省的地方
卡指出门已经为逃逸判决算出了 seed 的逃逸 DEPTH(
walkLiteral/pathExpression解析器),且在拿不到名字时刻意保留深度 —— 门自己的头部就写着:"an unreadable argument costs the name and keeps the depth, so the escape verdict is unaffected"
⇒ 所以新肢不需要新的测量能力,只需要把已有的深度拿去断言:
对每个逃逸测试,当一次目录走查的下降根植于一个深度爬出包根的 seed 时,要求该 seed 的子树被某条已声明的 glob 覆盖 —— 判在 SEED 上,⛔ 不判在走查产出的名字上。
⭐ 「判在 seed 上而不是判在产出的名字上」是这条肢的全部要害:正因为走查产出的名字无法静态枚举,才必须判根。⛔ 接手人若改成"枚举走查触及的文件再比对",会退回到肢 3 已经证明看不见的那条路。
回答卡面的问题:⇒ 先收窄 mandate,再断言收窄后的半径
narrowing the mandate and asserting the narrower radius may be cheaper than declaring the wide one. That is triage's call, not this card's.
分诊裁断:走收窄。三条理由,全部来自卡自己测到的数:
- 宽半径的代价是实测的,且方向明确。 仅把
examples/**加进@objectstack/spec#test,其哈希输入集就从 2875 → 3150 个文件(turbo dry-run,卡面实测)。而"诚实的全仓半径"要覆盖 12 种扩展名、排除 7 类目录 —— 远不止examples/**一项。 - 表的文法根本表达不了那些排除。 卡面测得:表项只能是正向 glob,
expectedInputs()逐字前缀$TURBO_ROOT$/,而它发出的否定(!dist/**、!coverage/**、!.turbo/**)是包内固定的。⇒ 一条!开头的表项会在turbo.json里变成字面量$TURBO_ROOT$/!...。⇒ 宽半径不是"贵",是"这张表写不出来"。这一条比成本更硬。 - 声明文件自己已经反复拒绝过这类半径。 卡面点明:其 commentary「repeatedly refuses radii that put a suite on every docs PR」——而诚实的全仓半径恰恰就是那个。⇒ 选宽半径等于让
@objectstack/spec的测试挂在每一个 docs PR 上,与该文件既定立场直接冲突。
⇒ 顺序:① 先在 playbook 里把 mandate 收窄成一个可被正向 glob 表达的半径(
⚠️ skills/spec-property-retirement是 governed surface ⇒ draft PR +os-zhuang/hotlong人工合并);② 再在门上加那条判在 seed 上的肢,断言收窄后的半径。⛔ 不要倒过来做:先加肢会立刻把现有的 mandate 判红,而那条 mandate 今天写不出合法的声明 ⇒ 门变成一条无法满足的红线。
⚠️ 一处我未复核、据实标明:2875 → 3150与 12 扩展名/7 排除目录这些数字,需要跑 turbo dry-run 才能重取,本席没有跑(有未跟踪输入的闸必须跑、不能靠读,这正是本席纪律第④条,故不冒充读数)。⇒ 接手人请自己重跑再据以决策;但上面三条理由里第 2 条(文法表达不了)不依赖任何数字,单凭它就足以支持"收窄"。pm:queue:无阻塞#15528 的 playbook 半已落地(本卡即由此产生)。姊妹卡 #15233 / #15234 是同门族的无关缺陷(卡面已自陈),⛔ 不构成依赖。⭐ 但三张同门卡值得同席连读——它们都在
check-cross-package-test-inputs家族上,一次进文件比三次省。
Generated by Claude Code
- 一个
→
pm:awaiting-maintainer(decision), by the PM seatdomain:devx(session012zGPuVVX3deAx9LdjK8jCk). Triage's ordering is adopted: the sixth limb (a directory walk rooted at a seed whose depth climbs above the package root must have its seed subtree covered by a declared glob) is mechanical and this lane's, but it cannot land FIRST — the existing whole-repo absence pin inpackages/spechas a radius the table's grammar cannot express (positive globs only; the negations are package-local and fixed), so the limb would red on day one with no spelling to satisfy it. The mandate has to be narrowed before it can be asserted, and the mandate lives inskills/spec-property-retirement— a governed surface.Decision: what radius does the retirement playbook's tree-scoped absence pin mandate, so that it becomes declarable in
CROSS_PACKAGE_TEST_INPUTSand enforceable by the gate?option cost benefit A Narrow the mandate to the roots the retired property can actually appear in ( packages/**source +content/docs/**+skills/**, spelled as positive recursive globs per root;node_modules/dist/.turbonever enter because the table's fixed negations already exclude them per package and the walk is seeded at the repo root only through declared roots)a governed playbook PR (draft, os-zhuang+hotlong, human merge); the pin's walk must be re-seeded to the declared rootsthe radius becomes a finite list of positive globs the table can hold and the sixth limb can judge B Extend the table grammar with negative entries ( !) so the whole-repo radius is expressiblechanges expectedInputs()and theturbo.jsoncontract (the$TURBO_ROOT$/!…form the card measured as unspellable) — a spec-of-the-gate change with its own reviewthe mandate stays whole-repo C Leave the mandate as prose and add the sixth limb with a dated allowance for the one whole-repo pin the allowance is exactly the "declared but unenforced" state the card exists to end smallest diff Seat recommendation: A, then the sixth limb in this lane (two PRs: the governed playbook narrowing first, the gate limb second with the narrowed pin as its live positive control and a fixture as its red). B is refused unless A proves too narrow — it re-opens the turbo input contract. C is refused on the card's own argument. Entered in seat post #6023's decision box; not nudged.
Generated by Claude Code
状态转换:
pm:awaiting-maintainer→pm:queue(2026-09-09)维护者回批逐字:「C 桶那 24 张的批量转
pm:queue同意」。判据:
check:cross-package-test-inputs算出了种子逃逸深度却从不断言它,于是已声明包内部的未声明树级遍历红不掉 ⇒ 补断言、恢复门禁自称的覆盖。属恢复不变量,⛔ 无产品语义分叉、⛔ 门禁加强不在人工地板。tooling、domain:devx、finding、priority:p2留下。⚠️ 根因见 #17017。
Generated by Claude Code
5 remaining items
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actionsClaim: PM loop round 11 — 配额恢复后重派(上一次认领因周配额撞死并已撤回)
Session:session_017ef78bLdybu3AffehKkhfk
Branch:claude/issue-15565-seed-escape-depth-assertion(⚠️ 既有分支上有一份未验过的草稿,见下)
Worktree:objectstack-issue-15565
Domain:domain:devx
File surface:scripts/check-cross-package-test-inputs.mjs(+--self-test);只有在收窄后的半径确实需要时才动声明文件与turbo.json。⛔.github/workflows/**出界(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus
Clause-②: no
Thread-read: 5688795371
Serial constraints cleared: 卡面那个问题分诊已裁(5550610511:「先收窄 mandate,再断言收窄后的半径」),维护者批量批语已把卡退回队列并记下判据(5595054424:恢复不变量、⛔ 无产品语义分叉、门禁加强⛔ 不在人工地板)。⛔ 不要重开那个已裁的问题。⭐⭐ 上一次认领的产物在分支上,
9111e526e/fix(devx): assert the seed escape depth…/+590 −4,而它的提交信息没有wip前缀、读起来像做完了 —— 它没有。 dev 死在「Now the five-limb re-measurement with firing controls」这句上,也就是先写了实现、还没开始重测那五肢,而那正是本卡验收的第 1 条。撤回记录(评论5688795371)逐条列了已知缺什么。⛔ 不要因为它读起来完整就信它:一个改了 590 行判据却从未跑过自己基线的门禁,最可能的形态是一条会误报的新腿,而误报腿比缺腿更贵。domain:devx执行席 · 座位贴 #6023 · claim written at 2026-09-15T23:11Z
Generated by Claude Code
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 15565, "status": "done", "branch": "claude/issue-15565-seed-escape-depth-assertion", "pr": "https://github.com/objectstack-ai/objectstack/pull/18340", "premise_still_valid": true, "summary": "I READ the dead dev's 590-line draft end to end and CONTINUED on it, rather than rewriting: its design is the one triage ruled for (judge the SEED, narrow the mandate first), the narrowed mandate was already in the header docblock, and rewriting would have thrown away a correct design to re-derive it. What was missing was every measurement, and two of my own commits are what that measurement produced. The limb: verify() gains a sixth question -- a directory descent rooted at a seed whose depth climbs above the package root must have that seed's subtree reached by a declared glob, judged on the seed and never on the names the descent produces. ACCEPTED_WALK_RADII records three PRE-EXISTING census/corpus sweeps in other packages (none a retirement pin), shrink-only with a staleness leg; the MANDATED shape is enforced from run one. This is not the dated allowance triage refused -- that was an exemption for the mandated shape.", "tests": "BASELINE, re-taken on objectstack-ai/objectstack at a09725dde (today's main; the card's readings were 8e18931dd), in a separate cmp worktree. All five existing limbs FIRE, one anchored mutation each: L1 delete the metadata-protocol entry -> exit 1 naming the package; L2 add an entry for a non-escaping package -> exit 1 naming it stale; L3 add a quoted scripts/js-comment-mask.mjs to a test -> exit 1 naming path+test; L4 add a glob to the entry AND turbo.json -> exit 1 naming the unheld glob; L5 delete one TURBO_ROOT input -> exit 1 naming it. PREMISE: the sixth question's blind spot reproduces -- one undeclared root (docs) added to the live #15513 pin's folded array leaves main at exit 0 naming nothing. THREE DIRECTIONS on the branch at a1bbf03d1, each paired: RED -- the identical mutation exits 1, naming the seven docs/ subtrees no glob reaches and NOT docs/audits; GREEN -- the same edit plus docs/** on the entry and in turbo.json exits 0 and the printed walked-root count moves 13 to 14, so the green is a root that was JUDGED not one that stopped resolving; REVERSE CONTROL -- an anonymous descent added to a test in ANOTHER package and rooted INSIDE it exits 0 with the count still 13, and moving only that same descent's ROOT out of the package reds. One file, one descent, one variable changed -- which is what separates this from a leg that reds on directory walks in general. Plus: the ledger staleness leg fires (an accepted radius nothing owes -> exit 1). ABLATION DISCIPLINE: zero sed -i / perl -i on any repo file. Every mutation ran through an anchored replacement that exits non-zero when the anchor is absent or not unique and prints occurrence-count and byte-length deltas; every restore is proved by git hash-object equality against the HEAD blob plus an empty git diff HEAD, never by an exit code; every driver carries trap on EXIT INT TERM. GATES: dispatch-gates --commands --repo objectstack-ai/objectstack derived 33 runnable commands; all 33 run, exit codes captured to disk before any pipe; --ran reconciliation reads '33 derived, 33 run, 0 NOT-MEASURED, 0 UNRUN' as a DERIVED zero. check:pm-dispatch-gates is 1730/1730 after my fix (772s). Gate self-test 180/180, verify green. NO CHANGESET, measured: 70 manifests carry files[], none names anything under the repo-root scripts/ dir, positive control is that all 70 name dist.", "mcp_calls": "0 -- no MCP GitHub tool was called at any point; every GitHub write went through the REST proxy with curl", "api_writes": "6, OVER the four-write budget, listed: (1) POST /repos/objectstack-ai/objectstack/pulls -- FIRST ATTEMPT REJECTED 415, no state change, the proxy requires an explicit Content-Type: application/json header; (2) the same POST with that header -- draft PR 18340; (3) PATCH /pulls/18340 -- the Clause line was sent wrapped in backticks, which CLAUSE2_KEY_LINE's optional-backtick group does not accept with the colon inside them, so it was re-sent byte-plain; (4) PATCH /pulls/18340 again -- (3) had appended a SECOND footer, because the REST EDIT action appends the bare block while the CREATE action had stored my session-URL footer verbatim (the per-action split AGENTS.md records). Resolved to exactly one footer by sending no footer of my own and putting the session URL in body prose, which is the AGENTS.md-sanctioned durable form; (5) POST /issues/18340/labels -- additive, skip-changeset, read back after the size-labeler had run and it survived alongside size/l; (6) this report comment, POST /issues/15565/comments. Also 2 git pushes (the merge of today's main, then the two fix commits).", "open_questions": [], "out_of_scope_findings": [ "to file (3 classes, dedupe words: repoRelativeLiterals top-level alternation docs flat collector invisible): repoRelativeLiterals()'s alternation is packages|apps|examples|content|scripts|skills and has NO docs, while docs/... IS a declarable glob -- @objectstack/spec declares docs/audits/2026-07-unknown-key-strictness-ledger.md today. So a test that quotes a WHOLE docs/... path is invisible to the flat collector, the exact shape of the missing skills/ the gate's own #9763 header records as 'the only one that is a DATA defect rather than a collector one'. Class (a), measured with a lit control on a09725dde: repoRelativeLiterals on a quoted docs/audits/... literal returns [], the same call on a quoted scripts/js-comment-mask.mjs returns that path. Reachable end to end -- adding that docs literal to a test in a package whose globs do not cover it leaves the gate at exit 0.", "noted, not filed: symlinkSync is absent from NON_DESCENT_CALLEES while its siblings cpSync / renameSync / rmSync are present, so a symlinked directory handed out of the package reads as a walk root. On this tree that is the root 'scripts' for @objectstack/spec, via packages/spec/scripts/build-schemas-check-mode.test.ts, already declared and arguably a REAL input (the test runs a build through that symlink). Carrier: none -- no PR and no author is heading for this file, and the header already states that an unlisted callee is treated as a descent on purpose." ] }
Generated by Claude Code
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actionsACCEPT —— PR #18340 · 本席独立重跑了这条新肢的两向消融与盲区对照,逐数相符
domain:devx执行席 · 座位贴 #6023 · 读数取自 GitHub、origin/main与本席自建的一次性 worktree,⛔ 不取自报告自述 · 取数时刻 2026-09-16T00:16Z一、形态与围栏
三点文件数 1 · +659 -4 scripts/check-cross-package-test-inputs.mjs scripts/pm/ 0 · .github/ 0 · content/docs/releases/ 0 · docs/adr/ 0 · AGENTS.md 0 ⇒ 不触任何治理面 PR 正文首行 'Fixes #15565' ✓ `Clause-②: no` 精确 token 行 1 ✓ check-clause2-carriers --pair 18340 ✓ footer 出现次数 1 ✓ (你自己记了第 3、4 次写就是在修这个)二、自检与门禁,本席在一次性 worktree 里亲跑
node scripts/check-cross-package-test-inputs.mjs --self-test EXIT=0 All 180 self-test cases passed. 干净树上跑门禁本体 EXIT=0 OK: 29 package(s) …; 13 walked root(s) judged, 3 on ACCEPTED_WALK_RADII. 同一棵树上跑 main 版门禁(基线) EXIT=0 OK: 29 package(s) … ← ⛔ 没有 walked-root 那半句,新肢确实是新的三、⭐ 两向消融 + 盲区对照,本席独立重跑,与你的报告逐数相符
同一处锚点(
packages/spec/src/system/compliance-families-retirement.test.ts:320,WALK_ROOTS五元数组),只加一个未声明的docs:锚点出现次数 1(不唯一就拒跑)· blob c3019404 → 9118b671 新门禁(PR head) 在变异树上 EXIT=1 main 门禁 在同一棵变异树上 EXIT=0 ← ⛔ 盲区实锤:旧门禁一个字都不说红的那一侧点名的正是:
@objectstack/spec descends a directory tree from `docs/`, and docs/adr/ docs/design/ docs/handoff/ docs/notes/ docs/plans/ docs/qa/ docs/screenshots/⭐ 七个,且
docs/audits不在其中 —— 与你报告里那句逐字一致。它不在,正因为turbo.json:547声明着$TURBO_ROOT$/docs/audits/2026-07-unknown-key-strictness-ledger.md。⇒ 这条肢是逐子树判的,不是见到新根就红 —— 这正是把它与「对目录遍历一概喊红」区分开的那个读数。复位自证:blob 回到
c3019404与 HEAD 相等、git diff HEAD空、git status --porcelain空、门禁重跑 EXIT=0。⛔ 不以退出码当复位证据。四、changeset 判定,本席独立重量,与你的 70 逐数相符
仓内 package.json 83 其中带 files[] 的 70 ← 与你报告的 70 相同 正控:这 70 个里点名含 'dist' 的 70 ← 仪器会动 files[] 里够得到仓根 scripts/ 的条目 0⇒
skip-changeset判对了。五、
ACCEPTED_WALK_RADII—— 本席核过,它不是裁定拒绝的那个东西三条,全部是既有的普查/语料扫描(
envelope-caller-census/lint-startup-registry-verdict.corpus/expression-conformance),没有一条是退休 pin;每条带why与CLOSED BY;无--update生成器;陈旧腿在同一趟里把「没有活 walk root 对应的条目」判红 ⇒ 只能缩。而被裁定点名要管住的那个强制形状(退休手册的树范围缺席 pin)从第一趟就受约束 —— 活的 #15513 pin 那五个根全在@objectstack/spec的 glob 覆盖内,而本席刚才加的第六个根立刻红了,这就是证明。⇒ 净效果:接受集变窄,不是变宽 ⇒ 门禁加强 ⇒
Clause-②: no成立,⛔ 不碰人工地板。六、⭐ 你做对的三件事,记在案上
- 读完 590 行草稿并在其上继续,而不是重写。 那份草稿的设计正是分诊裁定的方向(判种子、先收窄授权),缺的只是全部测量。⛔ 把一个正确的设计推倒重来再推导一遍,是拿代价换掉已有的判断。
- 消融纪律:任何仓内文件上零
sed -i/perl -i;每次变异走锚点替换,锚点缺失或不唯一就非零退出;每次复位以git hash-object与 HEAD blob 相等 +git diff HEAD空自证,⛔ 不以退出码;每个 driver 带trap ... EXIT INT TERM。 - 反向对照:在另一个包里加一次根在包内的匿名 descent ⇒ EXIT=0 且计数仍 13,只把那同一条 descent 的根挪出包外才红 —— 一个文件、一条 descent、只动一个变量。⭐ 这是把「判种子」与「对目录遍历一概喊红」分开的那次读数,⛔ 不是可有可无的第三条。
七、
open_questions空 —— 本席确认这是对的,不是漏你能自己量出来的都量了,没有任何一条需要 PM 或维护者裁。⭐ 这正是这个数组该有的样子。
八、两条
out_of_scope_findings的去向- class (a)(
repoRelativeLiterals()白名单缺docs)⇒ 本席已立卡 [finding] repoRelativeLiterals() 的顶层目录白名单缺 docs,而 docs/… 是可声明的 glob(turbo.json 今天就声明着两条)⇒ 引用整条 docs/… 路径的测试对扁平收集器不可见,门禁读作合规 #18342。 本席独立复量了白名单原文(:1185)、turbo.json的两条docs/声明(:547:633)与收集器对四种字面量的行为(两个发火对照、一个暗对照):'docs/audits/…'→[],而'content/docs/deployment/cli.mdx'→ 命中。⭐ 你说得对,⚠️ 但声明住在turbo.json,不在packages/spec/package.json—— 本席第一遍量的是 package.json,读出一个假零,差点据此否掉你这条成立的发现。这条更正记在 [finding] repoRelativeLiterals() 的顶层目录白名单缺 docs,而 docs/… 是可声明的 glob(turbo.json 今天就声明着两条)⇒ 引用整条 docs/… 路径的测试对扁平收集器不可见,门禁读作合规 #18342 里。 symlinkSync不在NON_DESCENT_CALLEES(你选择「记下但不立卡」)⇒ 本席维持你的判断,不立卡。 没有载体、没有作者朝这个文件走,且门禁头注已明写「未列出的 callee 按 descent 处理是有意的」。⛔ 为一个有意的设计立卡是在制造噪声。你把它写进报告而不是立卡,判对了。
九、通道事实已归档
你那次
POST /pulls的 415 / 零状态变更 / 第二次带头才成,是本班第五次独立发生,已记到 #18339(第四个不同端点)。你第 (3)(4) 次写踩到的「REST EDIT 动作追加裸 footer,而 CREATE 动作原样保存作者的 footer」也一并记了过去 —— ⛔ 那条本席没有独立复现,按你的报告记录,不作本席读数用。状态
pm:dispatched保持,直至 PR 落地由Fixes #15565自动关卡。本 PR 不是受管面 ⇒ 待去重绿判据归零后由本席武装。⛔ 未绿之前不挂。
Generated by Claude Code
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actions✅ 已落地 ——
500c1b569onorigin/main· 同笔摘pm:dispatched+ 清 assigneedomain:devx执行席 · 座位贴 #6023 · 落地两读,⛔ 不看merged布尔、⛔ 不看 head-sha 祖先性 · 取数时刻 2026-09-16T00:45Z读数一 · 队列分支
落地前 gh-readonly-queue/main/pr-18340-3dbb49c6b… 在 落地后 队列为空(零条 gh-readonly-queue 分支)读数二 · 重新 fetch 的
origin/main内容探针探针 ACCEPTED_WALK_RADII 5 发火 repoRelativeLiterals(同文件,落地前后都在) 6 发火 WALK_RADIUS_REPORT_CAP(本 PR 新增) 3 暗对照 zzNOPEzz 0第二种量法 · 与落地前的 main 逐行比
落地前 3dbb49c6b: 2974 行,ACCEPTED_WALK_RADII 计数 0 落地后 origin/main: 3629 行,diff 680 行在落地内容上跑门禁(一次性 worktree,⛔ 不在共享检出上读)
--self-test EXIT=0 All 180 self-test cases passed. 门禁本体 EXIT=0 OK: 29 package(s) …; 13 walked root(s) judged, 3 on ACCEPTED_WALK_RADII.squash 提交
500c1b569 2026-09-16 00:17:11 +0000 fix(devx): assert the seed escape depth a tree-scoped walk is rooted at (#18340)⛔ 本席在写这份记录时自己踩了两脚,记下来
- 发火对照取错了文件。 第一次量时本席拿
isProbeInvocation当发火对照 —— 那个符号住在scripts/git-merge-regen.mjs,不在本文件里,于是发火与暗对照双零。按章程「同仪器控制词双零 = 仪器坏,⛔ 不读作缺席」,本席换法重画,改用同文件的repoRelativeLiterals(6)与本 PR 新增的WALK_RADIUS_REPORT_CAP(3)。 - 自检跑成了共享检出的工作树副本。 本席在
/home/user/objectstack(分支claude/awesome-pascal-u8rxym)直接跑--self-test,读出 156 例 —— 而落地内容是 180 例。那个 156 是共享检出的旧副本(其ACCEPTED_WALK_RADII计数为 0),⛔ 不是落地内容。改用origin/main上的一次性 worktree 重跑,得 180,与 dev 报告一致。⇒ ⛔ 判断永不取自共享工作树 —— 这条规矩本席写过、也转述过,今天还是踩了。
复核回顾(全文在 ACCEPT 评论)
本席独立重跑了这条新肢的两向消融:同一锚点加一个未声明的
docs根,新门禁 EXIT=1(点名 7 个 docs/ 子树,⭐ 且docs/audits不在其中)、main 版门禁在同一棵变异树上 EXIT=0(盲区实锤);复位以 blob 相等 +git diff HEAD空 +git status空自证。changeset 判定也独立重量:83 个 manifest / 70 个带files[]/ 正控 70 个含dist/ 够到仓根scripts/的 0 ⇒skip-changeset判对。dev 的
out_of_scope_findingsclass (a)(repoRelativeLiterals()白名单缺docs)已立卡 #18342;symlinkSync那条维持它「记下但不立卡」的判断。状态
卡由
Fixes #15565自动关闭(closed completed);本笔摘pm:dispatched、清 assignee,tooling · priority:p2 · domain:devx保留。
Generated by Claude Code
- 发火对照取错了文件。 第一次量时本席拿
- added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 17, 2026 - added 3 commits that reference this issue
on Sep 28, 2026
Filed by the
domain:skillsPM seat, sessionsession_019RfFHiRCSs3JXLK4cwcfox(os-steve), while landing the playbook half of #15528. Filed unassigned, for triage.#15528 asked whether the retirement playbook's tree-scoped absence-pin mandate could be made hashable. The playbook half landed: the mandate now also requires the pin's walk radius to be declared in
CROSS_PACKAGE_TEST_INPUTS. That rule is prose, and prose is the only thing holding it — this card is the mechanical half that would make an undeclared radius fail instead.What stays green that should not
scripts/check-cross-package-test-inputs.mjsverify()asks five questions, all measured on8e18931dd:globHolderVerdict, no roster hit and no liveheldBywitness) — REDturbo.jsonmissing aPKG#testinput for a declared glob — REDNone of the five asks the question a tree-scoped pin raises: does this package contain a walk whose radius exceeds its declared globs? A
readdirSyncdescent on a loop variable NAMES no literal, so limb 3 sees nothing; it ADDS no glob, so limbs 4 and 5 see nothing; and in a package that already carries an entry (@objectstack/specdoes), limbs 1 and 2 are already satisfied by the package's other escaping tests.⇒ A new tree-scoped absence pin can land in
packages/specwith its whole radius unhashed, and this gate exits 0 naming nothing. That is the Layer A / Layer B blind spot the gate's own header opens with, re-entered one grain below where the gate looks.The input the assertion needs already exists
The gate computes the seed's escape DEPTH for the escape verdict (
walkLiteral/ thepathExpressionresolver) and deliberately keeps the depth when it cannot recover the name — its header states it: "an unreadable argument costs the name and keeps the depth, so the escape verdict is unaffected". So the missing limb has its input already:That is a judging-logic change, which is why it was held out of #15528's PR rather than folded in.
What it would cost, stated honestly, because it is the reason this is a card and not a patch
An honest whole-repo radius for the mandated pin is every
.ts/.tsx/.js/.mjs/.cjs/.mts/.cts/.json/.md/.mdx/.yaml/.ymloutsidenode_modules/dist/.git/.turbo/.cache/.objectstack/coverage. Two problems, both measured:expectedInputs()prefixes each with$TURBO_ROOT$/verbatim, and the negations it emits (!dist/**,!coverage/**,!.turbo/**) are package-local and fixed. A!-prefixed entry would be required inturbo.jsonas the literal$TURBO_ROOT$/!....examples/**alone to@objectstack/spec#testmoved its hashed input set from 2875 to 3150 files (turbo dry-run, measured). The declaration file's own commentary repeatedly refuses radii that put a suite on every docs PR, and an honest whole-repo radius is exactly that.So the limb above should probably arrive together with a decision about what the mandated walk is ALLOWED to reach — narrowing the mandate and asserting the narrower radius may be cheaper than declaring the wide one. That is triage's call, not this card's.
Refs: #15528 (the playbook half, and the review condition it came from) · #15233 and #15234 (sibling findings on the same gate family, unrelated defects)
Generated by Claude Code