Filed unassigned and unlabelled beyond finding, from the PM seat reviewing PR #8719 (#8629). Grading and routing are triage's field. Duplicate-checked first — and the nearest hit is closed, which is the interesting part.
The observation
packages/metadata-protocol now issues three unique-index migrations at kernel:ready:
| migration | table |
|---|
ensureOverlayIndex | sys_metadata |
ensureViewDefinitionActiveIndex | sys_view_definition |
ensureSysSettingIdentityIndex (new, PR #8719) | sys_setting |
Each folds a NULL-safe key the declared-index vocabulary cannot express, and each must be excluded from detectManagedDrift() — otherwise the reconciler would propose rebuilding the tightened index back into its NULL-distinct declared form on the next boot. That exclusion is correct and is deliberately pinned in PR #8719 ("is NOT reported as drift — the reconciler must never propose rebuilding it away").
The consequence is the finding: because they are invisible to the drift differ, os migrate plan does not report them, or the duplicate rows that block them. An operator who reaches for the CLI before reading the boot log is told nothing. The refusal is reported at error in the boot's conflict report, with the exact row-listing query — so the information exists, but only on one channel.
Why this is NOT a duplicate of #3728
#3728 — "unique 索引迁移在启动时静默执行 DDL,os migrate plan 看不到 —— 运维无预检手段" — describes this symptom exactly. It was closed completed by merged PR #3737, "feat(driver-sql)!: index drift is planned, not silently executed at boot".
That fix was real, and it addressed a different mechanism: SqlDriver.syncTableIndexes() → dropLegacyGlobalUniques(), inside schema sync. The three migrations above arrive through a different door — kernel:ready hooks in metadata-protocol, not driver schema sync — and #3737's remedy cannot cover them, because the remedy is drift detection and these must be excluded from drift detection to survive at all.
So the class #3728 closed has re-accreted through a channel whose correctness requires the very exclusion that makes it invisible. Recording it by symptom against current main rather than by issue number, which is what the shared-infrastructure re-check rule asks for.
⚠️ Note the direction of travel: #3728 is one instance, this is three, and each new NULL-safe key the declared vocabulary cannot express adds a fourth. #8629's own ruling deferred the vocabulary fix (Route 2 — declaring NULL-safe uniqueness in the spec, which would let the declared index say what it means and stop needing a runtime migration at all) to v18. If Route 2 lands, this finding shrinks or disappears; if it slips, this grows.
Not claimed
- No user-facing defect is demonstrated. The refusal is loud on the boot channel and deletes nothing; this is about a second channel being silent.
- No opinion on the fix. Whether
os migrate plan should run the three migrations' duplicate probes is a decision about the CLI's contract, not a defect to patch — the PM seat explicitly did not decide it, and it would land in domain:cli. - Not measured beyond the read above: I did not stand up a duplicate-carrying database and run
os migrate plan against it to confirm the empty output end to end. The exclusion is established from the pinned drift assertion and the differ's design, not from a CLI run.
Related
Filed unassigned and unlabelled beyond
finding, from the PM seat reviewing PR #8719 (#8629). Grading and routing are triage's field. Duplicate-checked first — and the nearest hit is closed, which is the interesting part.The observation
packages/metadata-protocolnow issues three unique-index migrations atkernel:ready:ensureOverlayIndexsys_metadataensureViewDefinitionActiveIndexsys_view_definitionensureSysSettingIdentityIndex(new, PR #8719)sys_settingEach folds a NULL-safe key the declared-index vocabulary cannot express, and each must be excluded from
detectManagedDrift()— otherwise the reconciler would propose rebuilding the tightened index back into its NULL-distinct declared form on the next boot. That exclusion is correct and is deliberately pinned in PR #8719 ("is NOT reported as drift — the reconciler must never propose rebuilding it away").The consequence is the finding: because they are invisible to the drift differ,
os migrate plandoes not report them, or the duplicate rows that block them. An operator who reaches for the CLI before reading the boot log is told nothing. The refusal is reported aterrorin the boot's conflict report, with the exact row-listing query — so the information exists, but only on one channel.Why this is NOT a duplicate of #3728
#3728 — "unique 索引迁移在启动时静默执行 DDL,
os migrate plan看不到 —— 运维无预检手段" — describes this symptom exactly. It was closedcompletedby merged PR #3737, "feat(driver-sql)!: index drift is planned, not silently executed at boot".That fix was real, and it addressed a different mechanism:
SqlDriver.syncTableIndexes()→dropLegacyGlobalUniques(), inside schema sync. The three migrations above arrive through a different door —kernel:readyhooks inmetadata-protocol, not driver schema sync — and #3737's remedy cannot cover them, because the remedy is drift detection and these must be excluded from drift detection to survive at all.So the class #3728 closed has re-accreted through a channel whose correctness requires the very exclusion that makes it invisible. Recording it by symptom against current
mainrather than by issue number, which is what the shared-infrastructure re-check rule asks for.Not claimed
os migrate planshould run the three migrations' duplicate probes is a decision about the CLI's contract, not a defect to patch — the PM seat explicitly did not decide it, and it would land indomain:cli.os migrate planagainst it to confirm the empty output end to end. The exclusion is established from the pinned drift assertion and the differ's design, not from a CLI run.Related
sys_setting's declared row identity is unenforced on everytenantandglobalrow —user_idis NULL there and SQL UNIQUE is NULL-distinct #8629 / PR fix(metadata-protocol): enforce sys_setting's declared row identity on the tenant and global layers (#8629) #8719 — where this surfaced; the third instance.