Skip to content

sys-metadata's declared overlay index shape diverges from the migration-owned partial form — every composed migrate plan proposes a recreate_index that would break draft/active coexistence #13203

Closed as not planned

Description

@hotlong

From cloud#1736's audit (control-plane drift): the framework's overlay-index migration owns idx_sys_metadata_overlay_active and installs a PARTIAL, NULL-safe form (WHERE state='active', COALESCE(package_id,'')), but sys-metadata.object.ts DECLARES a plain index under the same name. Consequences: (1) os migrate plan proposes recreate_index [destructive] on every run against a DB carrying the migration's form; (2) if anyone ever applies it, the plain form collides draft with active and leaves package-less overlays unconstrained — and because syncDeclaredIndexes skips by NAME, the framework migration would never repair it. Deliverable: make the DECLARED shape carry the partial/NULL-safe form (or teach the declaration vocabulary to express it), so the plan stops proposing the wrong index. Consumer evidence: cloud#1736 table, findings on sys_metadata.

Activity

  1. added
    bugSomething isn't working
    priority:p1High: required for production / M2
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    on Aug 29, 2026
  2. os-zhuang commented on Aug 29, 2026

    @os-zhuang
    Contributor

    PM triage — seat session_01LZbWd2jNV1FErXTPSS4Dry (PM seat #6367, domain:engine lane). ⚠️ Not dispatching this, because the stated mechanism does not reproduce at current main (e22158fff), and the deliverable as written is measured impossible. Both readings below, so a later seat does not repeat the work.

    1. The divergence is deliberate and documented on both sides — not an oversight

    packages/metadata-core/src/objects/sys-metadata.object.ts:221-230 already carries a comment explaining the plain declaration, in the card's own terms — it calls itself "the coarser fallback that a driver without that runtime migration gets: it still prevents duplicate ACTIVE overlays, at the cost of also colliding with archived/reset rows."

    The reason it cannot be otherwise is recorded at packages/metadata-protocol/src/migrations/overlay-index.ts:15-19: syncDeclaredIndexes materializes declarations through knex's table.unique(), which "can express neither a WHERE nor a COALESCE."

    So the card's first branch — "make the DECLARED shape carry the partial/NULL-safe form" — cannot be done at the materializer as it stands. Only the parenthetical second branch ("or teach the declaration vocabulary to express it") is open, and that is a contract widening of the index-declaration vocabulary, not a p1 bugfix. It would change this card's tier and its review path.

    2. Consequence (1) is already carved out — including on a cold process

    packages/drivers/driver-sql/src/schema-drift.ts:1769-1777 skips this exact index before it can emit a recreate_index, with a comment that quotes the declaration's own "fallback shape" sentence and concludes "Not ours to reconcile (#4884)."

    The carve-out is isRuntimeManagedIndex (:1262-1268), and its two limbs matter separately here:

    1. runtimeCreated?.has(index.name) — process-local. runtimeCreatedIndexes is an in-memory Map on the SqlDriver instance (sql-driver.ts:7951), populated only when this very process executed the CREATE INDEX. A cold os migrate plan has it empty, so this limb does not fire for the card's scenario.
    2. !isSyncReproducibleIndex(index, tenantField) — and :1242 is if (index.partial === true) return false;. The migration-installed index is partial, so this returns false, the negation is true, and the index is carved out anyway.

    Limb 2's docblock (:1258-1260) says it is there for precisely this case: "durable across restarts, and the only witness available on the second boot, when the runtime ledger starts empty again." A cold planning process is that second boot.

    I also found no drift differ on the CLI side at all: detectSchemaDrift / diffManagedIndexes / schema-drift have zero non-test importers under packages/cli/src and packages/metadata/src, and recreate_index is produced nowhere in packages/cli/src, packages/metadata/src, or packages/runtime/src. The op can only come from the driver differ above — the one that skips.

    What would make the card true, and what I need

    The reading that survives is a DB where the physical index is not the partial form — i.e. the CREATE degraded or failed, which overlay-index.ts's own header documents as a real historical outcome (#6418: an ordering defect that could leave sys_metadata with no unique index and no log line). On such a DB limb 2 does not fire, the physical index is sync-reproducible, and recreate_index would be proposed — matching the audit.

    If that is what cloud#1736 observed, the card is real but its title is aimed at the wrong object: the defect would be the degraded physical state, not the declared shape, and the fix is repair/detection of that state rather than teaching the declaration a partial form.

    @hotlong — to move this, could you say from cloud#1736 which of these the audited DB actually had:

    • the physical idx_sys_metadata_overlay_active as the partial WHERE state='active' / COALESCE(package_id,'') form (⇒ my reading says no recreate_index, and I would want the plan output that shows one), or
    • some other physical shape — plain, missing, or partially built (⇒ card is real, and I will re-scope it to the degradation and re-dispatch).

    The os migrate plan output for sys_metadata from that audit would settle it in one paste. Leaving this on pm:queue, unassigned, until then — ⛔ dispatching it as written would ask a dev to either do the impossible branch or silently widen a spec vocabulary.


    Generated by Claude Code

  3. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 30, 2026
  4. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    ⚖️ RULED — 维护者,2026-08-31,第 5 场总监席决裁批 #11,verbatim「13203 同意,其他你不处理」(本卡采选项 A)

    裁定:关卡(not planned)。依据为分诊 2026-08-29 的逐条测量,原样入档:

    • 卡述机制在 main(e22158fff)不复现:schema-drift.ts:1769-1777 的 carve-out 把该索引挡在 recreate_index 之外,其第二肢(isSyncReproducibleIndex 的 partial===true ⇒ false)在冷进程同样生效(docblock 自述「the only witness available on the second boot」正为此而设);CLI 侧 detectSchemaDrift/diffManagedIndexes 零非测试消费者。
    • 分歧双侧刻意且已文档化:声明形自述「the coarser fallback that a driver without that runtime migration gets」(sys-metadata.object.ts:221-230);迁移侧记录了不可能性根因(overlay-index.ts:15-19:knex table.unique() 表达不了 WHERE/COALESCE)。
    • 卡的第一分支(声明形直接带 partial)测量不可能;唯一开放分支(索引声明词表加 partial/NULL-safe 表达力)是零实测拉动的契约加宽,不入队——以无定级 finding 存档(同笔另立),供将来第二个消费者出现时取用。

    席位边界:录裁 + 关卡,关闭即摘状态标。裁决入本场追认摘要表。


    Generated by Claude Code

  5. removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions