Skip to content

[finding] ADR-0002's "already discarded in v3.4's ADR-0001" points at a document this repo never contained — the number it cites held an unrelated decision #7963

Closed

Description

@hotlong

Filing unassigned; observation-class. Found while writing the ADR-0001 tombstone (#7866 / PR #7960), which documents the discrepancy for a reader arriving at the number. This card is about the citing record's own wording, which that PR deliberately did not touch.

The observation

docs/adr/0002-environment-database-isolation.md:122, under Alternatives Considered:

  1. One global DB + tenant column. Was never on the table — already discarded in v3.4's ADR-0001.

That reference does not resolve to the record which actually held the number. Measured against full history (clone unshallowed — a shallow clone silently answers "never existed"):

  • docs/adr/0001-metadata-service-architecture.md — added 2026-02-10 (908d95c82), deleted 2026-02-11 (9da8e3e72). It decided how the metadata service is registered (ObjectQL vs MetadataPlugin precedence) and says nothing about tenancy or database topology.
  • git log --all --diff-filter=AD -- '*0001-*' returns exactly those two commits, on any path, on any branch. No other file ever claimed the number.

So "v3.4's ADR-0001" is a reference to a pre-registry document that has never existed in this repository. Today's ADR-0002 is itself dated 2026-04-19 and supersedes the v3.4/v4.0 per-organization database model, which is consistent with the reference being to a v3.4-era artifact that predates docs/adr/.

Worth noting the same mistaken attribution had propagated into tooling: the UNRESOLVED_ADR_CITATIONS entry in scripts/check-adr-anchors.mjs justified itself as "cited as history by ADR-0002". That half is corrected in PR #7960 (the entry is removed and the tombstone dissects the discrepancy).

Why this is not urgent

After PR #7960 the citation resolves — docs/adr/0001-withdrawn-metadata-service-architecture.md exists and has a "What ADR-0002 actually cites" section written for exactly this reader. No gate is red and no navigation dead-ends. The residual cost is that ADR-0002's sentence still asserts, in its own voice, a provenance that is not this repository's.

Why it was not fixed in PR #7960

ADR-0002 is an accepted record. Editing its prose is a decision about the decision log, not a rider on a tooling change, and docs/adr/ is maintainer-merge territory with no size exemption. Left for a maintainer call.

Possible dispositions

  1. Leave it. The tombstone already carries the explanation. Zero cost, mild residual inaccuracy in an accepted record.
  2. Qualify the sentence — e.g. name it as a pre-registry v3.4 document rather than a bare ADR-0001, so it stops reading as a pointer into docs/adr/. Smallest edit that makes the record self-consistent.
  3. Drop the citation, keeping the rejection ("was never on the table") without the provenance claim.

No recommendation offered — this is the maintainer's record to word.

Activity

  1. hotlong commented on Aug 12, 2026

    @hotlong
    ContributorAuthor

    Findings-round first grading: hold as finding.

    Premise verified on origin/main: the phantom citation is live at docs/adr/0002-environment-database-isolation.md:122 (sole hit repo-wide), and no ADR-0001 file exists in today's tree — the citation currently dangles harder than the card's "not urgent" section assumed, because the tombstone that would catch it (PR #7960) is still an open draft, maintainer-merge-only.

    Not escalated YET, deliberately: the fix is a one-line wording choice in an accepted ADR — the maintainer's record to word (adr-class, human merge) — but it sequences naturally behind #7960, and the decision box should receive it once, with the tombstone in place.

    Restart condition: PR #7960 (ADR-0001 tombstone) merges ⇒ escalate this card to needs-user-decision with the three candidate wordings from the body, as a one-pick decision.

    本评论来自分诊座位(scheduled session session_01DLzE5XVRASxFotEU1h9cjH),不构成认领。


    Generated by Claude Code

  2. hotlong commented on Aug 13, 2026

    @hotlong
    ContributorAuthor

    State-machine migration, maintainer-authorized (2026-08-13, live triage session: 「我授权你先迁标签」; semantics on #8449): graded hold with a named escalation trigger (PR #7960 tombstone merges ⇒ escalate to needs-user-decision as a one-pick wording decision) — finding → pm:on-hold. Verdict, trigger, domain unchanged.


    Generated by Claude Code

  3. claude commented on Aug 14, 2026

    @claude
    Contributor

    Restart condition met — pm:on-hold → needs-user-decision, exactly as this card's hold specified.

    The recorded condition: "PR #7960 (ADR-0001 tombstone) merges ⇒ escalate this card to needs-user-decision with the three candidate wordings from the body, as a one-pick decision."

    PR #7960 is merged. The tombstone is in place, so the decision box now receives this once, with the sequencing the hold wanted.

    This is an ADR-class wording choice in an accepted ADR — the maintainer's record to word. The ask is one pick among the three candidate wordings already written in the body; no new analysis is being requested.

    Authorization: maintainer directive (this session) —「先做 23 张 blocked 解锁 10 张 on-hold 按各自自述处理」· PM session 01JaVVMrSxt7Tgi1uwEuDtH7


    Generated by Claude Code

  4. hotlong commented on Aug 14, 2026

    @hotlong
    ContributorAuthor

    Maintainer ruling (2026-08-14, verbatim: 「同意你的建议」, approving item 3 of the eight-item decision-box list: 「#7963:措辞 2?」): wording option 2 — qualify the sentence so the discarded alternative is attributed to the pre-registry v3.4 document rather than a bare "ADR-0001", preserving the historical rejection while restoring self-consistency. One-sentence docs edit to an accepted ADR ⇒ ADR-class: draft PR + human merge. needs-user-decision → pm:queue.


    Generated by Claude Code

  5. os-steve commented on Aug 16, 2026

    @os-steve
    Collaborator

    Claim: PM loop round 1
    Session: session_01XqDQYVU5smx29ts9pAErja
    Branch: claude/issue-7963-adr0002-v34-citation
    Worktree: objectstack-issue-7963
    Domain: domain:devx
    File surface: docs/adr/0002-environment-database-isolation.md — one sentence at :122. Stop on breach; explain in the report
    Container & model: S, mode:subagent, model: opus — dispatch-gates.mjs --tier reports no path-derived mandate; clause ① does not fire (no skills path) and clause ② does not fire (an ADR prose edit changes no accept/reject behaviour). Tiny diff, but it is prose in an accepted decision record where the exact wording is the entire deliverable ⇒ opus, not sonnet.
    Serial constraints cleared: docs/adr/0002-* is on no hot-file serial row (#6023's ADR rows are 0076-* and 0105-*, both other files). No in-flight claim names it. In-flight siblings: #9092 (content/docs/**), #9122 (issue-body only, no repo files) — disjoint. #8531/#7276 are assigned to a different account ⇒ ⛔ untouched.

    ⚠️ This card was NOT maintainer-owned — it has been RULED since 2026-08-14, and was misread as undispatchable

    Recording this plainly because a prior seat's shift report listed this card among "items handed to the maintainer", and I nearly inherited that reading.

    The maintainer ruled on 2026-08-14 (comment 5293337394, verbatim 「同意你的建议」, approving item 3 of an eight-item decision-box list): wording option 2 — qualify the sentence so the discarded alternative is attributed to the pre-registry v3.4 document rather than a bare ADR-0001, preserving the historical rejection while restoring self-consistency. Label was flipped needs-user-decision → pm:queue in the same stroke.

    ⇒ The pm:queue label is correct and current. The card's body still says "No recommendation offered — this is the maintainer's record to word" — true when filed, superseded two days later in the comments.

    ⭐ This is the exact failure #6023's pitfall list carries at ⛔⭐⭐⭐: 「卡片正文冻结在立卡那一刻…只读正文,系统性地读到『决策之前的世界』」, with #7245 as the recorded precedent — body read as undecided, maintainer had ruled days earlier. Same shape, same lane, two cards apart. The body is the least current thing on the page.

    Premise re-check, against origin/main at 2026-08-16T15:3xZ (date -u) — all hold

    premise measured now
    the phantom citation is still live ✅ docs/adr/0002-environment-database-isolation.md:122 — 4. **One global DB + tenant column.** Was never on the table — already discarded in v3.4's ADR-0001.
    the tombstone the ruling leans on exists ✅ docs/adr/0001-withdrawn-metadata-service-architecture.md present, with its ## What ADR-0002 actually cites section at :77
    instrument control ✅ Alternatives Considered returns 1 in the same file — the grep reaches the corpus

    ⛔ Landing constraint, stated up front

    docs/adr/** is maintainer-merge territory with no size exemption. This PR ⛔ will not be merged, queued, or auto-merged by any agent seat — it gets flipped to ready-for-review and left visibly awaiting a human. Its ADR maintainer approval context going red is by design (the gate reads a human PR review, which no seat can supply); that red is explained on the PR and ⛔ not "fixed".


    Generated by Claude Code

  6. os-steve commented on Aug 16, 2026

    @os-steve
    Collaborator
    {
      "issue": 7963,
      "status": "done",
      "branch": "claude/issue-7963-adr0002-v34-citation",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9153",
      "premise_still_valid": true,
      "summary": "Implemented the 2026-08-14 maintainer ruling (wording option 2) as a one-line edit to docs/adr/0002-environment-database-isolation.md:122. The historical rejection is preserved word for word; only its provenance changes, from a bare `ADR-0001` to 'the v3.4-era \"ADR-0001\", a pre-registry document this repository has never contained', plus a link to the tombstone section written for this reader. The wording deliberately reuses the ADR-0001 tombstone's own two phrases verbatim rather than inventing a parallel description, per the dispatch's consistency check; the tombstone's `## What ADR-0002 actually cites` section was read first and needed no change. Nothing else in ADR-0002, the tombstone, or the tooling was touched. Two notes for the PM. (1) Contract conflict, declared rather than silently resolved: the standing dev contract says report at DRAFT PR, while this card's landing constraint says flip to ready-for-review because a human cannot press merge on a draft; I followed the card-specific clause, so PR #9153 is ready-for-review, not merged, not queued, no auto-merge armed. (2) The tombstone records a real open gap in its own voice - the single-provider metadata-service architecture that replaced the withdrawn record has no ADR of its own, and the tombstone states re-homing it is a maintainer call. Already recorded in-repo with a stated disposition, so I filed no duplicate card for it; flagging it here rather than withholding it.",
      "tests": "Docs-only change; no package build or test surface, and no pnpm install was needed (all three gates are node-builtin scripts), so the shared heavy-verify lock was not taken. Gate list re-derived from the actual changed path - `node scripts/pm/dispatch-gates.mjs docs/adr/0002-environment-database-isolation.md` returned exactly the three the dispatch named, no additions; `check-nul-bytes` added because any edit is in its surface. Full union run against the FINAL commit `3b3bb0a0c` (`git rev-parse --short HEAD`), the tree pushed to the PR: `node scripts/check-adr-anchors.mjs` -> exit 0, 'OK (49 anchored file(s) ... 121 decision number(s) ... 25855 citation(s) across 3227 file(s) resolve)'; `node scripts/check-adr-links.mjs` -> exit 0, '544 relative link destination(s) under docs/adr/ resolve'; `node scripts/check-nul-bytes.mjs` -> exit 0, 'scanned 5998 text file(s) ... no raw ASCII control bytes'. Reverse verification, both legs run from the COMMITTED state and predicted red beforehand: mutating the citation to a record-less number made check-adr-anchors exit 1 naming this file ('ADR-9993 is cited by 1 file(s) but names no record under docs/adr/ - docs/adr/0002-environment-database-isolation.md'); mutating the new link target made check-adr-links exit 1 at 'docs/adr/0002-environment-database-isolation.md:122'. Both proved the gates actually read the edited line rather than passing vacuously. Restores verified byte-identical, not merely by --stat: `git hash-object` returned 237278c747c4d609404568786a91c383a290b536 both before and after each leg, with `git status --porcelain` empty. The heading fragment `#what-adr-0002-actually-cites` is checked by NO gate - check-adr-links strips `#fragment` by design - so it was verified by hand against the tombstone's `## What ADR-0002 actually cites` heading. CI status at report time: in_progress, not waited on, per the standing clause. `ADR maintainer approval` is expected RED by design and is declared as such in the PR body; `mergeable_state` reads 'blocked' as it should. `skip-changeset` applied as a read-then-union write (bot had already set `size/xs`) and confirmed by read-back: labels are ['size/xs','skip-changeset'], draft is false, CODEOWNERS auto-requested hotlong.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code


    Generated by Claude Code

  7. os-steve commented on Aug 16, 2026

    @os-steve
    Collaborator

    PM review — ✅ ACCEPT. domain:devx seat (#6023), session session_01XqDQYVU5smx29ts9pAErja, 2026-08-16T15:4xZ (date -u). PR #9153.

    ⛔ This PR will NOT be merged, enqueued, or auto-merged by this seat. It is ready-for-review and awaiting a human. See the terminal disposition at the bottom.

    PR form — read from the API, ⛔ not the PR body

    ✅ base main · first line Fixes #7963 · 1 file, +1 / −1 · labels size/xs / skip-changeset · draft: false — correctly flipped to ready, because a human cannot press merge on a draft.

    The ruled wording, verified against the ruling

    Maintainer ruling 5293337394 was option 2: qualify the provenance, preserve the rejection. The landed diff:

    4. **One global DB + tenant column.** Was never on the table — already discarded in the v3.4-era "ADR-0001", a pre-registry document this repository has never contained and not the unrelated metadata-service record that held the number here ([tombstone](./0001-withdrawn-metadata-service-architecture.md#what-adr-0002-actually-cites)).

    ✅ "Was never on the table — already discarded in" survives word for word — the historical rejection is intact, so this is option 2 and ⛔ not option 3.
    ✅ The bare ADR-0001 no longer reads as a pointer into docs/adr/, which was the actual defect: the repo now has a 0001-withdrawn-… file, so the old text was a wrong-but-resolving citation — the kind check:adr-anchors structurally cannot catch, since it verifies existence and not aptness.
    ✅ It reuses the tombstone's own phrases rather than inventing a parallel description, and links to the section written for this exact reader. Two records now describe one discrepancy in one vocabulary.
    ✅ Scope held: nothing else in ADR-0002, nothing in the tombstone, nothing in the tooling.

    ⭐ Reverse verification actually earned its keep here

    Both legs were run from the committed state with the red predicted in advance:

    • mutating the citation to a record-less number ⇒ check-adr-anchors exits 1 naming this file;
    • mutating the new link target ⇒ check-adr-links exits 1 at :122.

    ⇒ The gates demonstrably read the edited line rather than passing vacuously. Restores were proved byte-identical via git hash-object (same OID before and after each leg), ⛔ not by --stat. That is the standard this lane asks for.

    ⭐ And the honest residue: the heading fragment #what-adr-0002-actually-cites is checked by no gate — check-adr-links strips fragments by design — so it was verified by hand against the tombstone's actual heading, and said so rather than letting a green run imply coverage it does not have.

    Contract conflict — declared, not silently resolved. Confirming the dev chose correctly.

    The dev flagged that the standing role-file clause says report at draft PR, while this card's dispatch required flip to ready. It followed the card-specific clause and declared the conflict instead of quietly picking one. ✅ That is the right call and the right disclosure: for docs/adr/**, "not merged by an agent" ≠ "left as a draft" — a draft is unmergeable by the human it is waiting on, which is how ADR PRs silently rot.

    The one open gap it surfaced and correctly did NOT file

    The tombstone records, in its own voice, that the single-provider metadata-service architecture which replaced the withdrawn record has no ADR of its own, and states that re-homing it is a maintainer call. Already recorded in-repo with a stated disposition ⇒ ✅ filing a duplicate card would have been noise. Flagged up rather than withheld — correct handling of the reporting clause.

    ⛔ Terminal disposition — docs/adr/**

    1. ✅ Review conclusion recorded here (not mergeable by an agent ≠ not reviewed).
    2. ⛔ Left visibly awaiting the maintainer — no merge, no queue, no auto-merge. Ready-for-review so the button is live.
    3. ⚠️ ADR maintainer approval is RED by design and is ⛔ NOT to be "fixed" — that gate reads a human PR review, which no agent seat can supply. Its red is the mechanism working, not a failure. mergeable_state: blocked is likewise correct. The dev declared this in the PR body, as required.
    4. This card will be listed under awaiting a human merge in the round report — because "waiting for a person" and "forgotten" look identical on GitHub.

    CODEOWNERS auto-requested hotlong.


    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

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions