Skip to content

[finding] ADR-0006 is linked under two filenames — ADR-0007 and ADR-0008 point at the Superseded v3, everyone else at the Accepted v4, and the link checker is green either way #12748

Description

@os-litant

Filed unassigned and ungraded by the domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12473 dev — that seat gets 403 on the dedup channel, so the mandatory pre-file search was impossible from there. ⭐ It reported rather than filing blind. ⛔ Not graded, not routed. Re-measured independently by this seat before filing.

⚠️ Nothing is broken today, and that is the point: the redirect works, so nothing ever reds.

Measured on origin/main

Two files under docs/adr/ link ADR-0006 to the bare filename, which holds the Superseded v3:

  • 0007-settings-manifest-and-kv-store.md:5 — in its Builds on line
  • 0008-metadata-repository-and-change-log.md:8 — in its Builds on line

Five link to the .v4 filename, which holds the Accepted revision: 0005:9, 0016:5, 0016:449, 0027:5, 0086:5 (plus the v3 record's own Superseded-by line pointing forward, which is correct).

The v3 file's own header reads "Superseded by v4" and names the successor, so a reader routed there is redirected in one hop — which is why check:adr-links is green against both filenames and always will be.

⭐ Why it is worth recording anyway

ADR-0008 does both things at once. Its line 3 is one of the three banners telling the reader "See ADR-0006 for the rationale"; its line 8 links ADR-0006 to the superseded record. ⇒ a reader following that document's own link lands on v3, looking for something that is in neither revision (see the sibling finding filed alongside this one).

And the incentive just changed: PR #12736 (#12473, maintainer-ruled) puts the API-surface vocabulary boundary into v4. That boundary exists to stop a recurring stream of drift cards. ⛔ Two of the inbound links point at the revision that does not carry it, and a redirect the reader must notice is weaker than a link that lands.

⚠️ Outside docs/adr/, two more places name one of the filenames: the repo CHANGELOG.md and scripts/check-adr-anchors.mjs. ⛔ Whoever takes this checks what the script's reference means before touching it — a checker naming a path is not necessarily a citation to retarget, and this seat did not determine which it is.

Options, ⛔ not prejudged

  1. Repoint the two v3 links to v4. Smallest diff. ⚠️ But it silently loses the fact that ADR-0007 and ADR-0008 were written against v3 — which may be the accurate historical statement, since a Builds on line records what a decision was actually built on.
  2. Leave them and say so. If "builds on v3" is historically true, annotate each so the next reader sees deliberateness instead of drift. Costs two short phrases.
  3. Add a mechanical rule. A check that a Builds on citation resolves to a record that is not Superseded — unless annotated. ⚠️ Largest cost, and it needs option 1-vs-2 settled first, since it encodes the answer.

⭐ The question underneath is not cosmetic: should a citation name the revision that was true when it was written, or the one that is true now? The repo currently answers both ways in the same directory, which is why this is a finding rather than a typo.

Re-check

git grep -nE "\(\./0006-project-environment-split\.md\)" origin/main -- 'docs/adr/*.md'
git grep -nE "0006-project-environment-split\.v4\.md"     origin/main -- 'docs/adr/*.md'
git show origin/main:docs/adr/0006-project-environment-split.md | sed -n '1,4p'

⛔ Reverse-check any zero against a term known present in the same population — and note the bare-filename pattern is a substring of the v4 one unless the closing paren is anchored, which is exactly the kind of overlap that has produced false readings in this lane.

Duplicate check

Searched this round. Nearest neighbour is #9072 (open, pm:queue, repo:cloud) — the same class, different subject: an ADR cited under two spellings, there across a repo boundary. ⛔ No open card covers ADR-0006's two filenames. ⚠️ Not exhaustively deduped outside domain:cli / domain:devx.

Refs

Activity

  1. huangyiirene commented on Aug 27, 2026

    @huangyiirene
    Collaborator

    Triage: routed domain:skills, ⛔ left ungraded — the finding label stays, and grading belongs to #7623 under the standing skills-lane self-triage carve-out. This seat produces the domain:* label and stops.

    Routing rationale, which is worth stating because two lanes have a plausible claim. The immediate fix surface is two link lines in docs/adr/0007-*.md:5 and docs/adr/0008-*.md:8 — governed face. Option 3 would add a gate, and scripts/ gates split by the gate's SUBJECT: a checker governing ADR citation integrity has the governed face as its subject, which the lane boundary assigns to skills rather than to domain:devx. Both halves therefore land in the same lane. ⚠️ scripts/check-adr-anchors.mjs and the repo CHANGELOG.md also name one of the filenames; the card is explicit that it did not determine whether the script's reference is a citation to retarget or a checker naming a path. ⛔ That distinction gets established before either is touched — retargeting a checker's own path constant would be a silent behaviour change dressed as a docs fix.

    The question underneath is a convention, not a typo, and it is why this is worth the skills seat's attention rather than a two-line patch: should a citation name the revision that was true when it was written, or the one that is true now? A Builds on line is a historical statement — "ADR-0007 was built on v3" may well be accurate, in which case option 1 (repoint to v4) does not fix a defect, it destroys a true record. The repo currently answers both ways inside one directory, which is the actual finding.

    ⇒ Consequence for grading, stated so it is not missed: option 1 is the smallest diff and is not obviously the right one. Ordering matters — option 3 encodes whichever answer wins, so it cannot be taken before 1-vs-2 is settled. The card has this right and this seat endorses the ordering.

    ⚠️ check:adr-links is green against both filenames and always will be, because the v3 record's own header redirects in one hop. So there is no mechanical pressure here at all — nothing will ever go red to remind anyone. That is the argument for recording it, and equally the argument that it is not urgent.

    What changed the stakes (and the card names it correctly): PR #12736 (#12473, maintainer-ruled) puts the API-surface vocabulary boundary into v4. That boundary exists to stop a recurring stream of drift cards — and two inbound links point at the revision that does not carry it. A redirect the reader must notice is weaker than a link that lands, and the readers here are mostly agents.

    ⭐ Sibling interlock with #12747 — routed to the same lane this round, and they are not independent. ADR-0008 does both things at once: its line 3 is one of the three "See ADR-0006 for the rationale" banners, and its line 8 links ADR-0006 to the superseded v3. ⇒ A reader following that single document lands on the wrong revision, looking for content that exists in neither revision. Fixing either card alone leaves that combined path broken, so whichever is taken first must read the other.

    Re-check instruction carried forward: the bare-filename pattern is a substring of the .v4 one unless the closing paren is anchored — the card's greps anchor it deliberately. ⛔ An unanchored re-check will conflate the two populations and report the finding as already fixed. Reverse-check any zero against a term known present in the same population.

    Dedup as filed: nearest neighbour #9072 (open, pm:queue, repo:cloud) is the same class with a different subject — an ADR cited under two spellings across a repo boundary. ⛔ No open card covers ADR-0006's two filenames. ⚠️ Not exhaustively deduped outside domain:cli / domain:devx; this seat did not extend that sweep.

    Same filing-hygiene note as the sibling: measured by the #12473 dev, which could not run the mandatory pre-file dedup search (403 from a dev seat) and reported rather than filing blind; re-measured independently by the domain:cli seat before filing.


    Generated by Claude Code

  2. added theissue type on Aug 28, 2026
  3. huangyiirene commented on Aug 28, 2026

    @huangyiirene
    Collaborator

    <!-- os-decision-facets -->

    定级:Bug · priority:p2 · domain:skills · needs-user-decision

    分诊席位,session session_01Aujz2zykf5LXt3T98gRsGe。落点 docs/adr/**(治理面)⇒ domain:skills;卡自己指出的那个底层问题(引用该指向写下时为真的修订,还是此刻为真的修订?)是一条约定裁决 ⇒ needs-user-decision。

    卡的读数全部复现 ✅

    我按卡自己的告诫用了锚定右括号的模式(⛔ 裸文件名是 .v4 的子串,不锚定会出假读数):

    bare-filename(v3)链接 — 2 处,均在 Builds on 行:
      0007-settings-manifest-and-kv-store.md:5
      0008-metadata-repository-and-change-log.md:8
    .v4 链接 — 5 个文件:0005 / 0016(×2) / 0027 / 0086(+ v3 自身的 Superseded-by 前向指针)
    裸文件头: "# ADR-0006: … — v3"  /  "**Status**: Superseded by v4 … — 2026-05-20"
    

    ⭐ 复现之外:第四个 ADR-0006 缺陷,本卡未覆盖

    docs/adr/0006-project-environment-split.v2.md
      # ADR-0006: Three-Layer Tenancy — Organization, Project, Environment
      **Status**: Accepted (v2)        ⬅ ⚠️ 未标记为已被取代
    
    文件 修订 Status
    .md v3 Superseded by v4 ✅
    .v2.md v2 ⚠️ Accepted (v2)
    .v4.md v4 Accepted ✅

    ⇒ ⭐ 同一个 ADR 号下有两份文件同时自称 Accepted,而 v2 描述的是被 v3/v4 取代掉的三层租户模型。

    ⚠️ 这比本卡的缺陷更危险,理由是本卡自己的论证方式:

    • 本卡的两处链接指向 v3,而 v3 会把读者一跳重定向到 v4 ⇒ 读者能到达正确位置。
    • v2 没有任何重定向 —— 它自称 Accepted 且无人链接。⇒ 一个通过文件系统或 grep 找到它的读者(或 agent,或任何按 Status: Accepted 扫描 ADR 语料的门),会得到一份自称当前有效的过时记录,且没有任何东西告诉它去看 v4。

    ⭐ 这与今天的事故同构:#12786 那道门就是按语料扫描的,而语料里一份自称 Accepted 的僵尸修订,正是这类扫描最容易被骗的形状。


    四棱

    ① 项目长远合理性

    ⭐ 卡把底层问题提得很好:「a citation should name the revision that was true when it was written, or the one that is true now?」 —— 而本仓在同一个目录里两种答案都给了。⇒ 这不是笔误,是缺一条约定。⚠️ 而缺约定的代价会随修订数增长:ADR-0006 已经有三份文件。

    ② 实际业务拉动

    零。 重定向有效,⛔ 什么都没坏。⭐ 卡自己第一句就说清楚了,这个自我设限是对的。

    ③ 防 AI 犯错

    ⭐ 最重。两条独立的路径都在生产错误:

    ④ 创业阶段不扩散

    ⚠️ ⛔ 不要借本卡给 ADR 语料加链接策略工程(选项 3)。⭐ 但 ADR-0006 现在挂着四张开放卡(本卡 + #12747 + #12918 + #12786),⇒ 建议维护者把这四张一起裁,而不是四次分别修 —— 那比逐张便宜。


    选项 × 成本

    做法 评价
    1 把两处 v3 链接改指 v4 最小 diff。⚠️ 卡的反对意见成立:Builds on 行记录的是"当初建立在什么之上",改掉会静默丢失历史事实
    2 ⭐ 保留并注明是刻意的 两个短语的成本;⭐ 让下一个读者看到"刻意"而非"漂移"
    3 加机械规则(Builds on 不得解析到 Superseded 记录,除非有注明) ⚠️ 成本最大,且必须先裁 1 vs 2 —— 它把答案编码进去了
    ⭐ 新增 把 .v2.md 的 Status 改为 Superseded ⭐ 纯减法、无争议、不需要裁 1 vs 2

    建议:先做"新增"那一条(可直接派发),1 vs 2 由维护者裁

    ⭐ 把一份自称 Accepted 的过时修订标成 Superseded,不涉及"引用该指向哪个修订"的争论 —— 它只是让文件说真话。⛔ 而 1 与 2 是一条真正的约定选择,本席位不代裁。

    退路

    若维护者认为 Builds on 就该指历史修订(选项 2)⇒ 那么正解可能是给 Builds on 行一个专门的写法(例如标注修订号),使"指向历史"变成可读的意图而非看起来像漂移。


    ⚠️ 置信缺口

    1. 我没有确认 v2 是否真的应当被标记 Superseded —— 它的标题(三层租户)与 v3/v4(Environment 与 Project 为独立同级)明显是同号的更早修订,⛔ 但我没有读 v2 正文确认它没有仍然生效的部分。⇒ 取卡者先确认再改。
    2. docs/adr/ 之外的两处引用我没有分类(repo CHANGELOG.md 与 scripts/check-adr-anchors.mjs)。⭐ 卡的告诫成立且重要:一个 checker 命名一个路径,未必是一条待改指的引用 —— ⛔ 先弄清那处引用的含义再动它。
    3. "三处横幅逐字节相同"我没有复核(那是 [finding] ADR-0006 is what AGENTS.md and three ADR banners cite for the v5.0 project → environment rename — and its body does not contain that rename, nor does the changeset they name still exist #12747 的读数)。

    裁后执行段

    相关

    #12473 / PR #12736(把边界放进 v4,⭐ 正是它让本卡有了牙齿)· ⭐ #12747(同批的姊妹卡:ADR-0006 正文不含它被引用的那次改名)· ⭐ #12918 · ⭐ #12786 · #9072(同类,跨仓)


    Generated by Claude Code

  4. zhuangjianguo commented on Aug 30, 2026

    @zhuangjianguo
    Collaborator

    Claim: PM loop round 1 — ruled convoy member; chain head is #12747
    Session: session_01EXxTW8mvPBhoHxmyPZ63de
    Branch: claude/issue-12747-adr0006-rename-rationale (shared convoy branch, named by the chain head — this member card deliberately has no branch of its own)
    Worktree: objectstack-issue-12747
    Domain: domain:skills
    File surface: docs/adr/0007-settings-manifest-and-kv-store.md:5 + docs/adr/0008-metadata-repository-and-change-log.md:8 (Builds-on repoints to .v4 with the ruled historical parenthetical) · docs/adr/0006-project-environment-split.v2.md (Status verify-then-correct) · inspect-only: CHANGELOG.md, scripts/check-adr-anchors.mjs (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus — same derivation as the chain-head claim (no path mandate; PM judgment, default opus)
    Clause-②: yes | no — no
    Serial constraints cleared: see the chain-head claim on #12747 — the full serial-constraint check lives there. Ruled convoy: one governed PR, one Fixes line per member, per-member commits.


    Generated by Claude Code

  5. zhuangjianguo commented on Aug 30, 2026

    @zhuangjianguo
    Collaborator

    Dev claim (os-dev seat, ruled convoy member; chain head is #12747 — runs as a subagent of the dispatching session, so the session id is shared with the PM claim above).

    Session: session_01EXxTW8mvPBhoHxmyPZ63de
    Branch: claude/issue-12747-adr0006-rename-rationale (shared convoy branch, named by the chain head; this member has no branch of its own)
    Worktree: objectstack-issue-12747, base 56c5b1d

    Executing the 2026-08-29 ruling above (option 1 with the historical annotation): the two Builds on links in docs/adr/0007-settings-manifest-and-kv-store.md and docs/adr/0008-metadata-repository-and-change-log.md repoint to the Accepted .v4 filename, each with a short parenthetical recording that the decision was originally built on v3. Option 3 (a mechanical Builds-on rule) is not taken. CHANGELOG.md and scripts/check-adr-anchors.mjs are inspected before anything is touched, per the card's caution; the report says what each mention actually is.

    Also carried, as a PM assumption riding this card's grading recommendation rather than the ruling text: verify by reading its body whether docs/adr/0006-project-environment-split.v2.md's Accepted (v2) Status line is a zombie, and correct it to Superseded only if verification holds. Neither v2 nor v3 is deleted.

    Assignee untouched. Governed face: the PR stays draft for human merge.


    Generated by Claude Code

  6. zhuangjianguo commented on Aug 30, 2026

    @zhuangjianguo
    Collaborator

    ACCEPT (convoy member) — the review of record for this card lives on the chain head: see the ACCEPT on #12747 (same PR, #13364). This card's own verification item, re-run by the reviewing seat against the PR diff: both Builds-on links now land on .v4 with the ruled historical parenthetical, and the card's own anchored re-check pattern (closing paren anchored, since the bare filename is a substring of the .v4 one) returns zero bare-filename links under docs/adr/. The v2 zombie-Accepted Status this card's grading surfaced is corrected in the same PR, verified against v2's body first. Card closes via the PR's Fixes line on merge.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions