Skip to content

[docs] ADR-0005 的「Index migration」段落描述的是已不存在的机制:addSysMetadataOverlayIndex 已随 #6771 删除,段落还写着 project_id 与 partial 键 #6825

Closed

Description

@os-zhuang

发现于 #6771(PR #6824)的实施——删除 addSysMetadataOverlayIndex 后逐条清点该导出的引用时读到。不在该单的 file surface 内(packages/metadata + tests + changeset),故单独记录。

事实

docs/adr/0005-metadata-customization-overlay.md:405-416 用现在时描述一套已经不存在的机制:

Drivers ignore `indexes` declarations on synced tables today, so a new
idempotent migration is provided and run automatically by
`DatabaseLoader.ensureSchema()`:

- `addSysMetadataOverlayIndex(driver)` — exported from
  `@objectstack/metadata/migrations`.

这三句现在逐句为假:

  1. addSysMetadataOverlayIndex 已删除([metadata] addSysMetadataOverlayIndex 用 ADR-0048 之前的键抢占 idx_sys_metadata_overlay_active——同名索引有两个生产者,先跑的赢 #6771 / PR fix(metadata): one owner for idx_sys_metadata_overlay_active — remove the stale-keyed second producer #6824),@objectstack/metadata/migrations 不再导出它;
  2. DatabaseLoader.ensureSchema() 不再运行任何覆盖层索引迁移——两处调用点随之移除;
  3. 「Drivers ignore indexes declarations on synced tables」本身已经不成立,且与 [metadata] addSysMetadataOverlayIndex 用 ADR-0048 之前的键抢占 idx_sys_metadata_overlay_active——同名索引有两个生产者,先跑的赢 #6771 无关:SqlDriver.syncDeclaredIndexes 会把声明的索引物化出来。这一条是该段落里最容易误导人的,因为它正是 [metadata] addSysMetadataOverlayIndex 用 ADR-0048 之前的键抢占 idx_sys_metadata_overlay_active——同名索引有两个生产者,先跑的赢 #6771 里「删除生产者是安全的」这个判断的反面——实测(真实 SQLite)声明索引确实被建出来,且带的是现行键 (type, name, organization_id, package_id)。

同段的 YAML 示例还写着 fields: ['type','name','organization_id','project_id','scope'] 与 partial: "state = 'active'"——project_id 早已改名 environment_id 后退役,partial 键在 #5248 / #4943 已被 enforce-or-remove 撤销。这两处的陈旧早于 #6771,不是本次改动造成的。

影响

无运行时影响,纯文档漂移——因此按 observation-class 归档(finding,不带 pm:queue)。代价在于 ADR 是人和 AI 抄写的语料:这一段读起来像是在描述当前交付覆盖层唯一性的机制,而真正交付它的是 metadata-protocol 的 ensureMetadataOverlayIndexes(partial + NULL-safe)与 metadata-core 声明索引(粗粒度兜底)这两层。

处理方向(未决定,留给 triage)

ADR 是历史决策记录,通常不就地改写正文。两条可选:一是加一段 Amended 说明,指明 Phase 1 的这套迁移机制已被 #5248/#4943/#6771 取代、现行归属在哪两层;二是只订正那句关于 syncDeclaredIndexes 的事实陈述。倾向前者——它保留了历史,也让读者不会把历史当现状。

复现

读 docs/adr/0005-metadata-customization-overlay.md:405-416,与 packages/metadata/src/migrations/index.ts 的 tombstone 注释、packages/metadata-core/src/objects/sys-metadata.object.ts:200-230 对照即可,无需运行。

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 8, 2026
  2. os-project-manager commented on Aug 9, 2026

    @os-project-manager
    Collaborator

    Triage (maintainer-authorized one-off pass, 2026-08-09, registered on #6015): promoted finding → pm:queue (domain:metadata kept). Three sentences of an ADR asserting a deleted mechanism in the present tense — including one ("Drivers ignore indexes declarations") that is the measured opposite of current behaviour — is active misinformation at the exact document agents cite. Docs-only rewrite of that paragraph to past-tense/current-fact. ⚠️ The PR edits docs/adr/**: maintainer-merged only, per standing discipline — no auto-merge, no agent queue entry.


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 9, 2026
  4. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 7 (domain:metadata seat, sticker #6367)

    Session: session_01W6bLax4KMrSfnE1ydFU8Dw
    Branch: claude/issue-6825-adr-0005-index-migration-amended
    Worktree: objectstack-issue-6825
    Domain: domain:metadata
    Base: origin/main @ 30283263c or newer

    Docs-only card: docs/adr/0005-metadata-customization-overlay.md §"Index migration" describes, in the present tense, a mechanism that no longer exists — addSysMetadataOverlayIndex was deleted with #6771 (PR #6824, this seat's own landing), DatabaseLoader.ensureSchema() no longer runs any overlay-index migration, and the "Drivers ignore indexes declarations on synced tables" premise is itself false today (SqlDriver.syncDeclaredIndexes materializes them, measured on real SQLite during #6771). The YAML example's project_id and partial keys were already stale before #6771 (environment_id rename then retirement; partial withdrawn by #5248 / #4943).

    Direction per the card's own preference, which this seat endorses: an Amended section, not an in-place rewrite of the historical text. Prime Directive #13 governs — an accepted ADR is a decision record, and the correct shape for "this phase's mechanism has since been superseded" is a revision note that names what replaced it (metadata-protocol's ensureMetadataOverlayIndexes for the partial + NULL-safe tier, metadata-core's declared indexes as the coarse fallback), leaving the Phase-1 history readable as history. Rewriting the body would erase the record this file exists to keep.

    Landing discipline for this card: the repo runs an ADR maintainer approval check on docs/adr/**. On ACCEPT this PR stops at ready — this seat will not enable auto-merge on it, and the maintainer's approval is what moves it. That is a deliberate deviation from this lane's usual ACCEPT → auto-merge flow, and it is recorded here so the difference is not read as an oversight.

    Round-7 siblings, all region-disjoint: #6190, #6924, #6848, #6715 — none of them touch docs/adr/.


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 9, 2026
  6. self-assigned this
    on Aug 9, 2026
  7. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    ContributorAuthor

    os-dev report

    Status: done · PR: #6981 (draft) · Branch: claude/issue-6825-adr-0005-index-migration-amended · Base: origin/main @ 30283263c · Premise still valid: yes, all three statements confirmed false against the tree.

    Verified against origin/main (not copied from the card)

    Claim in the card Verdict Evidence read
    addSysMetadataOverlayIndex deleted by #6771 Confirmed packages/metadata/src/migrations/index.ts exports only migrateEnvIdToProjectId / migrateProjectIdToEnvironmentId / dropProjectionTables / migrateSysNotificationToEvent, with a tombstone block naming #6771. A repo-wide grep for the symbol reaches only that tombstone, overlay-index-single-producer.test.ts, .changeset/overlay-index-single-producer.md, and the ADR line being amended. PR #6824 merged 2026-08-08T23:55Z.
    DatabaseLoader.ensureSchema() runs no overlay-index migration Confirmed packages/metadata/src/loaders/database-loader.ts — the engine path and the post-syncSchema path each carry an explicit "no overlay-index DDL is issued from here (#6771)" comment; the only migration left is migrateProjectIdToEnvironmentId.
    "Drivers ignore indexes declarations" is false and independent of #6771 Confirmed SqlDriver.syncDeclaredIndexes (packages/drivers/driver-sql/src/sql-driver.ts) creates each declared index via knex table.unique(fields, { indexName }) / table.index(fields, name), skipping by name. The spec records the same fact where the IDataDriver indexes capability bit was retired for having no reader (packages/spec/src/data/driver.zod.ts).
    project_id / partial staleness predates #6771 Confirmed environment_id on sys-metadata.object.ts is @deprecated, unwritten by saveMetaItem, NULL on new rows. indexes[].partial (with indexes[].type) is a retiredKey at protocol 17 under ADR-0049 (#5248 / #4943), with the ADR-0087 conversion object-index-type-partial-removed.
    Current owners of overlay uniqueness Confirmed, both ensureMetadataOverlayIndexes (packages/metadata-protocol/src/migrations/overlay-index.ts): OVERLAY_INDEX_COLUMNS = ['type','name','organization_id','package_id'], COALESCE(package_id, ''), WHERE state = 'active', sibling idx_sys_metadata_overlay_draft, non-unique fallback by design, probe-then-replace order, ADR-0120 D4 reporting; reached via MetadataProtocol.ensureOverlayIndex (once per instance). Declared index: sys-metadata.object.ts, { name: 'idx_sys_metadata_overlay_active', fields: ['type','name','organization_id','package_id'], unique: true }.

    What changed (2 files, +115 / -1, no code)

    1. docs/adr/0005-metadata-customization-overlay.md
    2. scripts/adr-anchors.json — two new entries (43 → 45) registering metadata-protocol/src/migrations/overlay-index.ts and metadata-core/src/objects/sys-metadata.object.ts against ADR-0005.

    On the PM's three hypotheses

    1. "No code change required" — held. Nothing in the tree contradicts the amendment; every current behaviour was expressible honestly. No code file was touched.
    2. "Date/attribute each supersession, and match an existing convention rather than inventing one" — held, and there is a precedent: ## Amendment (date, #issue): title is used by ADR-0036 / 0037 / 0044 / 0045 / 0057 / 0067 / 0073 / 0099 / 0119 / 0122, and ADR-0005 already carries one plus the **Amended** (…) Status chain. ADR-0045's 2026-08-09 amendment is the closest model (superseded mechanism + change table + Anchors section) and is what this follows. The in-section banner mirrors ADR-0005's own line-70 precedent and ADR-0086's "⚠️ Two mechanisms in the original text are superseded". One attribution I deliberately did not date: when "drivers ignore indexes" stopped being true. This container's clone is shallow (220 commits), so git log -S syncDeclaredIndexes cannot reach the introducing commit — the amendment states the fact and its current evidence without inventing a date.
    3. "Check the anchor registry" — checked and handled. ADR-0005 had exactly one anchor (packages/spec/src/kernel/metadata-plugin.zod.ts, the whitelist entry that came out of ADR-0005 的租户可定制白名单表说 flow/workflow/approval 一律 ❌ per-org override,注册表却写着 allowOrgOverride: true——反转没有走 ADR(Prime Directive #13) #6191 — closed, untouched here). Neither surviving owner of the overlay index was anchored, and neither was the deleted producer, which is the recurrence shape PD [WIP] Add Chinese version of the documentation #13 names. Both are now registered. Registry-only change: both files already cite ADR-0005 in their comments, so the presence check is green without editing either.

    Triage-comment tension, flagged rather than resolved silently

    The triage comment says "Docs-only rewrite of that paragraph to past-tense/current-fact"; the claim comment 30 minutes later, and the card's own preference, say an Amended section, not an in-place rewrite (PD #13). I followed the later decision, and kept the earlier one's substantive requirement — the paragraph can no longer be read as current, because the banner is the reader's first line of contact with it. If the maintainer prefers the literal in-place rewrite, that is a small follow-up edit on this same branch.

    CI — per-job conclusions on 29efb3c

    Job Conclusion
    ESLint (carries the check:* family gates, incl. check:adr-anchors) success
    TypeScript Type Check success
    Check Changeset success (skip-changeset landed before the settling read)
    Check Documentation Links success
    Check PR Size success
    Console Pin Freshness success
    No other open PR may claim the same issue success
    Auto Label success
    Test Core / Dogfood Regression Gate / filter / Vercel Preview Comments success
    Build Core / Build Docs / Test Core (shards) / Dogfood shards / Temporal Conformance / Console Pin Gate skipped (no packages/** diff)
    ADR maintainer approval failure — by design, pending the human gate

    ADR maintainer approval fails with "this change touches docs/adr/ and carries no APPROVED review from the maintainer's own account" (scripts/check-adr-merge-approval.mjs, #6741 ruling). It re-runs on pull_request_review, so the maintainer's approval turns it green by itself. Not worked around, and no restructuring was attempted to dodge it. The PR is left as a draft, with no auto-merge.

    Flag docs affected by code changes did not report: docs-drift-check.yml is path-filtered to packages/** / scripts/docs-audit/** / its own file, none of which this PR touches.

    Labels, read back after the bots settled

    ["documentation", "skip-changeset"] — skip-changeset applied by this seat (union write over the live set), documentation from Auto Label; both present, neither wiped.

    Local gates run in the foreground

    • check-adr-anchors --self-test (39 assertions) + gate: OK — 45 anchored files, every governing ADR still referenced, 20313 citations across 3323 files resolve.
    • check-adr-links --self-test + gate: OK — 531 relative link destinations under docs/adr/ resolve.
    • check-nul-bytes: OK — 6467 tracked text files, no raw control bytes; plus grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' over both changed files, no hits.
    • check-doc-authoring (374 files clean), check-role-word (no new occurrences), check-quick-reference-counts, check-adr-0087-registration, docs-audit/check-audit-scope: all OK.

    Not verifiable / not done

    • No unit test covers ADR prose, so there is no red-then-green demonstration for this change and no reverse verification to report. Saying otherwise would be fiction; the gate set above is the whole of the machine-checkable surface. The reverse check that does exist is the anchor gate: deleting the ADR-0005 citation from either newly-anchored file turns check:adr-anchors red, which is the entire point of registering them.
    • No changeset, deliberately: this PR releases nothing (docs/adr/** plus a repo-tooling registry, no workspace package version moves), which is the case pr-automation.yml prescribes the skip-changeset label for rather than an empty changeset file.

    Out-of-scope findings

    None filed. Two things were checked and found to be non-defects: ensureOverlayIndex (MetadataProtocol's private method) and ensureMetadataOverlayIndexes (the migration it delegates to) are both real and distinct, so the references to ensureOverlayIndex in packages/spec/src/data/object.zod.ts and packages/spec/src/migrations/registry.ts are accurate rather than stale; and the ADR-0005 anchor gap from #6191 was already closed by that issue's own landing.


    Generated by Claude Code


    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

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