Skip to content

#6148 门禁的迁移说明探测器读不到「无箭头的两列改写表」—— not-required (no-migration-prescription) 可被合法豁免绕过,存量已见 4 条同形 #6497

Closed

Description

@os-project-manager

在 #6350 的存量回补审计(PR 见下)里测出来的。未认领。

事实

scripts/check-adr-0087-registration.mjs 的 findMigrationPrescription() 是 not-required (no-migration-prescription) 这条豁免的唯一守门人:正文带改写指令 ⇒ 拒绝该豁免。它有两条分支,#6419 修过一次:

  1. FROM / TO 标签约定;
  2. 带迁移框架的改写 —— REWRITE_RE 要求一个 X 箭头 Y,两侧都是代码形。

两条分支都要求出现箭头。而本仓相当一批 changeset 把改写指令写成 ## Migration 标题下的两列 markdown 表,一个箭头都没有:

## Migration

| Wrote | Write instead |
| --- | --- |
| `new HttpServer(new HonoHttpServer(port))` registered as `http.server` | register the `HonoHttpServer` directly |
| `import { HttpServer } from '@objectstack/runtime'` | remove it — tsc reports this one |

这是 runtime-httpserver-wrapper-retired.md(#5122)的真实正文。探测器判它 无迁移说明,于是这条 changeset 落进 exempt-no-prescription 桶 —— 它够不着门禁的残差面。

实测口径(当前存量,1372 条 changeset)

  • 13 条 changeset 带「迁移框架标题下的无箭头两列改写表」;
  • 其中 4 条声明为 breaking 且当前正是靠这条盲区拿到豁免:runtime-httpserver-wrapper-retired.md、etl-author-shape-aliases.md、retire-three-deprecated-aliases.md、unknown-key-strictness-ui-batch15.md。修好探测器后这 4 条会从 exempt-no-prescription 移入残差面。

复现:node scripts/check-adr-0087-registration.mjs --audit-stock(PR #6350 半边新增的一次性审计口),runtime-httpserver-wrapper-retired.md 不出现在残差列表里。

为什么这是前向问题,不只是存量问题

门禁是前向的,而这条盲区同样前向:今后任何一个 PR,只要把迁移说明写成表格而不是箭头,就可以合法地写下 not-required (no-migration-prescription),门禁会批准这条自相矛盾的豁免 —— 正是 #6419 那个形状的第三种拼写。#6419 的教训逐字适用:「作者写得越认真,探测器越看不见」—— 一张写清了「原来怎么写 / 改成怎么写」的表,比一行箭头信息量更大,却恰恰是探测器唯一读不到的形状。

顺带:脚本正文里那段「残余盲区」自述目前只说 未加框架 的改写表读不到(128 changesets ... 21 of them declared-breaking)。上面这 4 条是加了框架的,所以那段自述本身也不完整,应一并改写。

明确不主张具体改法

候选各有代价,需要先量化误报面:把表格行(| 分隔、两侧各带反引号代码段)在迁移框架下也算作改写,是最直接的一条,但 changeset 正文里的表格用途很杂(能力矩阵、行为对照、版本对照),放宽之前要照 #6419 的做法把误报数先测出来 —— 那次的结论是「一条诚实收窄的探测器胜过一条吵闹的」,因为误报没有诚实的出口:作者被拒掉一条他有权使用的豁免,而封闭词表里没有别的选项给他。

按 startup focus,先把事实与数字记在案,由 PM 分诊定级。


Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    Triage: pm:queue + domain:spec-tooling.

    Classification — scoped gate fix in a single script with a measured blind spot, a repro (node scripts/check-adr-0087-registration.mjs --audit-stock), and an established method for the undecided half (quantify false positives before widening, per #6419's own playbook — the measurement is part of the work, not a maintainer question). Queue, not finding: the bypass is forward-facing on every future PR and four declared-breaking changesets already sit in the wrong bucket today.

    Landing site (read on origin/main @ 3a1d9c7) — scripts/check-adr-0087-registration.mjs: REWRITE_RE at :334 is OPERAND ARROW OPERAND (arrow mandatory, no table arm), findMigrationPrescription() at :375 with the if (!REWRITE_RE.test(line)) continue skip at :389. Counter-fact confirmed: .changeset/runtime-httpserver-wrapper-retired.md contains zero arrows and two | --- | --- | table headers — exactly the shape the detector cannot see. ADR-0087 gate machinery around the spec contract, no *.zod.ts face ⇒ domain:spec-tooling (#5163 seat; same routing as its neighbors #6350 / #6419).

    Dedup — no-migration-prescription / findMigrationPrescription search: only this card. #6419 (merged) fixed a different spelling of the same class; this is explicitly its third spelling, filed separately by design.

    Serialization note for the lane (not Blocked-by: — file collision, not substance) — #6350 is pm:dispatched right now and its PR adds the --audit-stock half to this same script; land #6350 first. Adjacent, do not merge scopes: #6509 (finding) concerns where this script's --self-test runs, not what it detects.

    Stale-premise check — passes in full on current main; the self-description gap the body notes (the script's own 残余盲区 prose omitting the framed-table case) is still in place.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 8, 2026
  3. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    CollaboratorAuthor

    认领 · domain:spec-tooling 座位派单

    派发前三查(04:2xZ)

    1. ㉔ 逐路径提交检查:scripts/check-adr-0087-registration.mjs 最新提交为 e6a7e26(02:40Z,[finding] #6148 的门禁只判 diff,v17 列车已有的 227 条 breaking changeset 从未被比对过 —— 抽样已见 2 条疑似同形漏登记 #6350 的 --audit-stock 审计口,即 PR chore(ci): ADR-0087 台账存量一次性回补审计口 --audit-stock —— 238 条 breaking 逐条过一遍门禁自己的判定逻辑 (#6350) #6500)。⇒ 分诊的串行前置「land [finding] #6148 的门禁只判 diff,v17 列车已有的 227 条 breaking changeset 从未被比对过 —— 抽样已见 2 条疑似同形漏登记 #6350 first」已满足,可派。再往前是 69dd8eff([finding][spec-tooling] ADR-0087 门的 no-migration-prescription 矛盾检查匹配的是占位符 FROM/TO,不是真实处方 —— 写得越好的处方越照不到 #6419 探测器加宽)与 81a4a670([finding] ADR-0087 台账没有「完备性」门禁:已发生的退役漏登记时全仓全绿,只有人工能发现(#6011 即如此) #6148 门禁本体),与本单是同族的前两种拼写,均已落地。
    2. 竞态复读:线程仅分诊一条评论,明示不构成认领;assignee 此前为空。
    3. 文件不相交:本座位在飞 dev 为 0。队列中的 PR fix(spec): 同目录裸源码路径通过 fromCategory 解析 —— 9 处纯文本变成链接或代码段 #6534 面为 packages/spec/scripts/**,与本单的 scripts/** 不同文件,零重叠。

    方法已由分诊定死,不是维护者问题:按 #6419 自己的打法,放宽之前先把误报面量出来 —— 那次的测量(存量 1342 条、旧 113/87 → 新 122/92、+9/−0)是 PR 的一部分,不是提问。本单同理。

    硬约束(来自 issue 正文,派单里再钉一遍):误报没有诚实的出口 —— 作者被错误拒掉一条他有权使用的豁免时,封闭词表里没有别的选项给他。所以「一条诚实收窄的探测器胜过一条吵闹的」。changeset 正文里的表格用途很杂(能力矩阵、行为对照、版本对照),把「迁移框架下的两列表」算作改写指令之前,必须先给出误报数。

    顺带必须一并改的:脚本正文那段「残余盲区」自述目前只说未加框架的改写表读不到;本单这 4 条是加了框架的,所以那段自述本身也不完整,与探测器一起改写。

    范围外:#6509(finding,讲的是这个脚本的 --self-test 在哪里跑)是相邻但不同的面,⛔ 不并入本单。


    Generated by Claude Code

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

Metadata

Metadata

Labels

pm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions