Repository navigation
Description
发现于 #6494 / PR #6556 实施期间(devx 车道执行座位)。按 Prime Directive #10 只记录不修,未认领,不自评级别(定级是分诊座位的单一通道)。
事实
scripts/check-adr-0087-registration.mjs 的 CLI 派发写在模块顶层,没有 import.meta.url === process.argv[1] 这类入口守卫(同仓 scripts/objectui-changeset-digest.mjs 末尾就有一个)。文件尾部形如:
const argv = process.argv.slice(2);
if (argv.includes('--self-test')) { selfTest(); }
else if (argv.includes('--list')) { list(REPO_ROOT, 'HEAD'); }
else if (argv.includes('--audit-stock')) { auditStock(REPO_ROOT, ...); }
else { /* 真正的门:解析 base、assertInputs、scan、打印判决 */ }四个分支没有一个是 no-op。因此 import 它 = 运行它(对导入方进程的 REPO_ROOT 与 process.argv)。
实测(不是从代码形状推断的)
临时仓 + 从 origin/main 取出的门脚本副本,写一个只想借一个纯函数的消费方:
// probe.mjs
import { readDisposition } from './scripts/check-adr-0087-registration.mjs';
console.log('PROBE OWN OUTPUT: readDisposition ->', JSON.stringify(readDisposition('nothing here')));第一次(门无可判) —— 门的判决先于消费方自己的那行打出来:
=== everything below this line came from a bare `import` of the gate module ===
✓ check-adr-0087-registration: this PR adds no declared-breaking changeset (0 non-breaking changeset(s) seen).
PROBE OWN OUTPUT: readDisposition -> {"ok":false,"reason":"no `adr-0087:` disposition marker"}
PROBE_EXIT=0
第二次(同一个 import,但仓里有一份声明破坏、没带标记的 changeset,默认 base 落在 HEAD 之前) —— 门判红并 process.exit(1),消费方自己的代码一行都没执行到:
✗ check-adr-0087-registration: 1 problem(s).
• .changeset/new-breaking.md
declares a breaking change (major, BREAKING) but no `adr-0087:` disposition marker.
…
PROBE_EXIT=1
--- did the importer's own line ever run? ---
NO — the gate called process.exit(1); the importer never reached its own code
即:导入方拿不到函数、拿不到控制权、还会被按门的判决决定退出码,而门判的是导入方的 REPO_ROOT,与导入方想问的问题无关。
这正是 PR #6556 绕开它的原因
#6494 要让 objectui-changeset-digest.mjs 生成的 changeset 携带一份「门仍会判红」的 ADR-0087 处置脚手架。想证明「门确实把这份占位认成 present-but-unanswered」,最直接的写法是 import 门的 parseChangeset / breakingDeclaration / readDisposition —— 一个判据、两个消费方、不会漂移,正是本仓一贯偏好的形状(objectui-range.mjs 与 digest 共用 classifyRange() 就是先例)。
这条堵死了这个写法。PR #6556 改为子进程 + 临时仓驱动门的二进制来钉一致性。附带一条也值得记:即便可以 import,也要权衡「给发布关键路径(bump-objectui.sh 调用链)加一个『门被改名/移动就崩』的耦合点」;两条理由叠加,子进程是对的,但第一条本不该存在。
代价
一个不能被安全 import 的门,等于强迫每一个想与它保持一致的调用方自己起进程。 具体开销:
- 每个消费方都要自建临时仓 + 复制门脚本 + 造够
assertInputs的输入(两份 ledger 源、spec-changes.json、一份存量 breaking changeset),只为问一句「这段正文算不算带了处置标记」。PR fix(scripts): objectui digest 声明破坏性时写入门仍判红的 ADR-0087 处置脚手架 (#6494) #6556 为此写了约 40 行 fixture。 - 这些 fixture 复制了门的输入契约:门以后改输入要求,邻居脚本的自测会跟着红。子进程把耦合从「模块路径」换成了「输入契约」,没有消灭它。
- 反向作用同样存在:任何工具(未来的门、报表、审计脚本)想复用
extractIds/hasMigrationPrescription/readDisposition这些明显是纯函数的导出,都会踩同一颗雷,而且踩到时的现象是「我的脚本莫名其妙打印了一段 ADR-0087 判决然后退出 1」,第一眼根本不像 import 的锅。
它们全部导出了(export function readDisposition 等),形状上就是给人复用的;只是现在没有一个可以被使用。
相邻(非重复)
- [finding] ADR-0087 台账没有「完备性」门禁:已发生的退役漏登记时全仓全绿,只有人工能发现(#6011 即如此) #6148 —— 门本身。
- objectui-changeset-digest 生成的 console changeset 不带 ADR-0087 处置标记 —— 手工补的会被下次 bump 覆盖,且复发条件是常见情形 #6494 / PR fix(scripts): objectui digest 声明破坏性时写入门仍判红的 ADR-0087 处置脚手架 (#6494) #6556 —— 发现现场;PR 正文写明了「没有 import 门的函数」及其两条理由。
- 观察单:changeset 家族三个 check-*.mjs 的 --self-test 只在可被 skip-changeset 整体豁免的 job 里跑,改这些脚本的 PR 恰好豁免自己的自检 #6509 —— 同族观察:changeset 家族三个
check-*.mjs的--self-test只在可被skip-changeset整体豁免的 job 里跑。方向不同(那条讲谁在跑自检,本条讲能不能被 import 复用),但同一批脚本。 - #6148 门禁的迁移说明探测器读不到「无箭头的两列改写表」——
not-required (no-migration-prescription)可被合法豁免绕过,存量已见 4 条同形 #6497 / #6497 之后:迁移说明探测器仍读不到「只由表头/标签起框」的改写表 —— 存量 11 条声明为 breaking 的 changeset 仍在拿豁免 #6559 / [finding] #6148 的门禁只判 diff,v17 列车已有的 227 条 breaking changeset 从未被比对过 —— 抽样已见 2 条疑似同形漏登记 #6350 —— 门的判据与存量覆盖面,与本条正交。
去重检索:adr-0087 import、import.meta.url top-level CLI dispatch、check-adr-0087-registration 三次 search_issues 均无同形单。
发现会话:session_01BDmDsu2575gDxeMCxXhDE3(devx 车道执行座位)。严重度与路由留分诊座位判定。
Generated by Claude Code
Activity
os-zhuang commentedon Aug 8, 2026
Routing repair:
domain:spec-toolingappended. Routing only — thefindinggrade is untouched and no ownership is taken.origin/main@f549a0d:scripts/check-adr-0087-registration.mjs— the argv dispatch sits at module top level (:1568const argv = process.argv.slice(2);) and the file's onlyimport.meta.urluse is the__dirnamederivation at:153, i.e. no entry guard comparing againstprocess.argv[1]; the pure-function exports the card names really are exported (readDisposition:415,extractIds:459). Sixprocess.exit(1)sites in the file.packages/specsource ⇒domain:spec-tooling(C 包 program card:协议工具链/门禁车道(domain:spec-tooling)—— 整包移交待接收 #5163 boundary; same script as #6148 门禁的迁移说明探测器读不到「无箭头的两列改写表」——not-required (no-migration-prescription)可被合法豁免绕过,存量已见 4 条同形 #6497/#6497 之后:迁移说明探测器仍读不到「只由表头/标签起框」的改写表 —— 存量 11 条声明为 breaking 的 changeset 仍在拿豁免 #6559).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commentedon Aug 8, 2026
认领 ·
domain:spec-tooling座位派单 — 会话session_01AZgRyPVwi1jLb1mNNuUQ9o(座位贴 #6018),分支claude/issue-6566-adr0087-cli-entry-guard,pm:queue→pm:dispatched。三查(12:3xZ):① ㉔
scripts/check-adr-0087-registration.mjs最新提交501c945(#6559 via PR #6588,06:09Z)—— 分诊要求的串行前置(#6558 与 #6559 先落地)已双双满足,且两单均未加入口守卫,前提完好;② 竞态:线程两条分诊评论均非认领;③ 不相交:本批四单四个文件,零交集。实施要点照分诊:入口守卫模式仓内现成(
scripts/objectui-changeset-digest.mjs);PR #6556 已为此付过 ~40 行子进程夹具的代价,是现成的受益方;仅改 import 安全性,⛔ 不碰判定逻辑(#6497/#6559/#6350 的面)、不碰--self-test在哪跑(#6509 的面)。Generated by Claude Code