Skip to content

[finding] Once system-context.mdx carries no line numbers, the os-regen mixed: 'line-anchors' comparator is the IDENTITY — the routing's stated safety argument, and three prose blocks, go stale together #16612

Description

@baozhoutao

维护者速读

system-context.mdx 这一页被配置成「合并时交给我们自己的重算程序处理」。那套配置里有一个字段,声明「这两个版本只差在自动生成的那半,所以可以安全地丢掉一边」——它靠页面里的行号来判断。而 #15921 已经把这一页的行号全部删掉了,所以那个判断现在等于「两个版本必须一模一样」,也就是它永远不会说可以丢。

这本来是往安全方向走的:再也不会有人的手写段落被静默丢掉。问题在分诊当时选的处置(把那个字段删掉)被开发席实测证明会把静默丢弃重新打开——因为那个字段不只是个比较器的答案,它还决定走哪一条驱动代码分支。那条实测之后,上一任 PM 席已经拒绝落地该选项并把卡退回分诊重判,而分诊至今没有再判,卡就这样在「可派」状态里躺了 5 天。

现在要的是一个字:保持字段不动、只把三段过期说明改成今天的事实(A);设计并落地一个新的比较器(B);还是把这一页从驱动里摘出去(C)?

① 项目长远合理性:A 缩小特例(删掉三段已经为假的散文,不新增任何机制);B 扩大(一个新比较器就是一份永久义务);C 缩小机制但把冲突解决成本转给人。
② 实际业务拉动:今天撞上的是任何编辑这一页的人 —— 现状是「每次真实编辑都落到文本合并或响亮冲突」,⛔ 没有人被静默伤害,所以拉动是把三段假话改真,不是恢复便利。
③ 防 AI 犯错:A 是响亮拒绝(冲突)优于静默容忍,且闭合;B 引入一个新的自由结构判断,恰是本卡缺陷的来源形状;C 响亮但把判断交给人。
④ 创业阶段不扩散:A remove(散文)优于 declare-and-maintain;B 是新增一个已声明键,永久义务;分诊原选的「删字段」在这一棱上最省,但③上被实测否决。

Prior rulings read: mixed,line-anchors,system-context,carries,line,numbers,os-regen,comparator,identity,routing,stated,safety (+6 more) → 100 hits; ADR-0076 D11, ADR-0110 D1, ADR-0131 D5, ADR-0006 D3, ADR-0056 D10, ADR-0058 D7, ADR-0076 D10, ADR-0087 D3, ADR-0087 D7; thread: 5

⚠️ 那九条 ADR 裁决本席逐项查过,没有一条管这个问题。 check-prior-rulings.mjs 的告警是术语重叠触发的(它匹配上的是 carries / line / numbers / routing 这类通用词),⛔ 不是命中本卡的问题。判据:docs/adr 共 139 个文件,os-regen / REGEN_ARTIFACTS / merge-driver 意义上的 mixed 三者各 0 命中,而同一次 grep 的必中对照(ADR)命中 139 / 139 ⇒ 这三个 0 是真空,不是坏 grep(2026-09-19T04:21:20Z 现读)。⇒ 本卡不是被既有 ADR 裁决答过的执行卡。

推荐:A(保持 mixed: 'line-anchors' 不动,只改三段说明)。自检「只看①选 A;②③④ 是否翻转:②不翻转(没有人今天被静默伤害,拉动就是改真话)、③不翻转(A 是这三个里唯一既响亮又不引入新自由结构的)、④不翻转(A 净删散文)」。

置信缺口:本席没有独立复现开发席那条「选项 1 会重新打开静默丢弃」的实测(证据在 5620351387,exit 0 且无冲突标记);若该实测不成立,分诊原选的删字段会重回桌面,而 A 的③理由随之变弱。⛔ 本席不代裁:落点是合并驱动的路由,而 #15921 被明确围栏排除在它之外。

Governing text: scripts/regen-artifacts.mjs 该行的注释块(声明 mixed: 'line-anchors' 的用途与其实测依据)· .gitattributes 中该页 merge=os-regen 的路由段与其上方段落 · scripts/doc-line-anchors.mjs 模块头(自述为 docs 散文里行锚点的唯一读者)· #14064(该 mixed 字段存在的原因:防静默丢弃手写散文)


Filed unassigned by the execution seat working #15921. Ungraded and unrouted — domain:*, priority and type are triage's.

Blocked-by: #15921 — nothing here is true on origin/main today. It becomes true the moment #15921's branch lands, so the card exists before the landing rather than after it.

The mechanism

content/docs/permissions/system-context.mdx is routed merge=os-regen in .gitattributes, and it is the ONE row carrying a mixed field (scripts/regen-artifacts.mjs, mixed: 'line-anchors'). The comparator that field names is blankAnchorLineNumbers in scripts/doc-line-anchors.mjs, wired through MIXED_COMPARATORS in scripts/git-merge-regen.mjs. Its job (#14064) is to decide whether two revisions differ ONLY in the half a generator re-derives — if so the driver may defer, and if not it must not, because dropping a side would delete hand-written prose.

That comparator blanks file:line anchors. #15921 removes every one of them.

Measured in the #15921 worktree, on the same two revisions of the page:

base f2f6684cd5   | line anchors: 141 | blankAnchorLineNumbers is the identity: false
issue-15921 head  | line anchors:   0 | blankAnchorLineNumbers is the identity: true

An identity comparator makes "equal modulo the generated half" mean "byte-identical". So after #15921 lands, this row defers essentially never and falls back to a text merge or a loud conflict.

Why this is a finding and not a bug

The behaviour change is in the SAFE direction and is not a regression to repair by reverting anything: silent prose deletion (the whole of #14064) becomes unreachable, because the driver can no longer conclude "lossless" on a page whose two revisions differ at all. What is lost is the #13646 convenience — 24 of the last 25 main commits to this page were pure anchor renumberings the driver absorbed for free, and none of those commits can exist any more either, because there are no numbers left to renumber.

What is left behind is stale text and an inert declaration, and both are the kind that read as current forever:

  1. scripts/regen-artifacts.mjs — the row's comment block argues at length from "the merged tree's correct anchors are on NEITHER side (measured on fix(rest): require the resolved environment to belong to the caller at GET /ui/view/:object/:type #13625 — five conflicted anchors resolve to 4408/5771/6019/6382/6575 …)". That measurement is about line numbers this page no longer has. The mixed: 'line-anchors' value itself is now a comparator that can never say yes.
  2. .gitattributes — the paragraph above the row calls the page "a generated file:line anchor table" and says the census gate "catches the stale anchors a merge leaves behind". There are no stale anchors of that kind to catch.
  3. scripts/doc-line-anchors.mjs — its module header opens on this page ("Measured on content/docs/permissions/system-context.mdx over 19 days, 101 of its 111 anchors rotted") and describes itself as the one reader of line anchors in docs prose. After [finding] system-context.mdx re-conflicts faster than one verification lap — the resolve→land window is measurably smaller than the gate union it requires #15921 the module has exactly one consumer left, scripts/git-merge-regen.mjs, and the page it was built for is not in its population any more.

What the decision actually is

Not for this seat. Stated as options rather than a recommendation, because the routing is the merge driver's territory and #15921 was explicitly fenced out of it:

pnpm check:merge-driver reconciles .gitattributes against regen-artifacts.mjs in both directions and is green on the #15921 branch, so nothing mechanical will raise this.

Re-check

git show origin/main:scripts/regen-artifacts.mjs | grep -n "line-anchors"
git show origin/main:scripts/git-merge-regen.mjs | grep -n "MIXED_COMPARATORS" 
node -e "import('./scripts/doc-line-anchors.mjs').then(m=>{const t=require('fs').readFileSync('content/docs/permissions/system-context.mdx','utf8');console.log(m.extractLineAnchors(t).length, m.blankAnchorLineNumbers(t)===t)})"

What is deliberately NOT claimed

Related: #14064 (the ruling that created the mixed field) · #13646 (the routing) · #13625 (the five-anchor measurement it argues from) · #15921 (the migration that makes the comparator vacuous).


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions