Repository navigation
docs(adr): ADR-0005 states the five-part overlay key — bundle_member since 5677add93f (#23006) - #23037
Conversation
…since 5677add ADR-0005 still spelled the overlay uniqueness key with four parts in its present-tense "What delivers overlay uniqueness today" block, and quoted the declared index with four fields and the retired bare `unique: true`. Since 5677add (#22877 ruling A) both the runtime partial indexes and the declared index carry `bundle_member`. - Status line: one dated Amended entry for #22877 ruling A. - The #6771 measurement sentence is kept verbatim and gains a dated note. - Owner 1 (runtime): the five-part key, with the member's reason. - Owner 2 (declared): five fields, `unique: 'global'`, and its NULL-distinctness on `bundle_member` stated. - The two ADR-0005 anchors' invariant text spells the five-part key. Claude-Session: https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Inputs read: card #23006 (body and all three comments: triage 6123056260, the dispatch ① Derived judgmentsAccept-set and public surface: none changed — right. The diff touches Factual claims the diff adds, each read against source — all right:
Site coverage: at the head's parent Line citations into ADR-0005: all eight on Check-runs on the head (their conclusions are the gate verdicts): ② Semver level
③ Boundary flags
Dev deviations (four), each judged:
The two anchor edits: the dispatch's Out-of-scope findings (five), escalated to the seat, none a FAIL reason — every one is outside the claim's file surface and the dev reported it rather than expanding scope:
Tier: Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)PR #23037 · card #23006 · head 改了什么
为什么改
风险与代价(含回滚)
席位意见
你要做的
Generated by Claude Code |
Fixes #23006
Clause-②: no
ADR-0005's present-tense "What delivers overlay uniqueness today" block still spelled the overlay uniqueness key with four parts and quoted the declared index with four fields and the retired bare
unique: true. Since5677add93f(PR #22954, #22877 ruling A) the runtime key and the declared index both carry a fifth part,bundle_member. This PR restates the current key from the tree and records the change as a dated amendment. Docs and ADR-anchor text only; nothing publishes.What changed
docs/adr/0005-metadata-customization-overlay.md(898 → 908 lines, +19 / −9, net +10):· **Amended** (2026-10-12, #22877 ruling A — …). It names the fifth part and what it is (a bundled type's member, such as anemail_template's locale). It also states that NULL is the canonical member, so name-only types are unchanged, and names the producer5677add93f(PR fix(metadata-protocol): two locales of one email template survive a restart — sys_metadata overlay rows keyed by bundle member (#22877, stage 1) #22954). The entry goes on the existing line, so no line above the body moves.DatabaseLoaderboot already storesCREATE UNIQUE INDEX … (type, name, organization_id, package_id)— the declared index, with the current key"): kept verbatim, because it records a measurement. A dated2026-10-12 notefollows it, saying that key was the four-part key of its day and pointing to the status line and the two owners.overlay-index.ts):(type, name, organization_id, COALESCE(package_id, ''), COALESCE(bundle_member, ''))WHERE state = 'active'. One sentence gives the reason, taken from the module header: two members of one item are two rows. NULL is the canonical member and every row of a name-only type, and folding it to''constrains those rows exactly as the four-part key did.sys-metadata.object.ts): the quotation now matches the tree:fields: ['type', 'name', 'organization_id', 'package_id', 'bundle_member'], unique: 'global'. A parenthetical notes that'global'is protocol 18's spelling of the baretrueit retired (ADR-0120 D2). The trailing sentence about the coarse fallback is restated from measurement (see Acceptance notes ②).scripts/adr-anchors/…overlay-index.ts.jsonand…sys-metadata.object.ts.jsonchange one key span each, from the four-part to the five-part spelling. This is a bounded in-place fix (Acceptance notes ③).The quoted code is taken from the tree at
edecd4485:OVERLAY_INDEX_COLUMNS(packages/metadata-protocol/src/migrations/overlay-index.ts:169),buildOverlayIndexSql(same file), and the declared index (packages/metadata-core/src/objects/sys-metadata.object.ts:250-254).Gates (all on HEAD
a75f9f225)I derived the gate list with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, passing no paths. It found 3 paths against merge baseedecd4485and listed 27 commands. All 27 exit 0:check-adr-links(+--self-test) ·check-adr-symbol-anchors(+--self-test) ·check-ci-filter-parity·check-closing-keyword-parity(+--self-test) ·check-comment-mask-corpus·check-scripts-symbol-anchors(+--self-test) ·@objectstack/lint check:doc-formula-expressions·check:adr-anchors·check:agent-test-spelling·check:bash32-floor·check:cli-command-ids·check:cross-package-test-inputs·check:doc-authoring·check:driver-memory-census·check:entry-guard·check:gitlink-declared·check:nul-bytes·check:parse-guard·check:pm-governed-merges·check:pm-prior-rulings·check:pnpm-filter-targets·check:refd-timer-probe·check:watch-hint-literal.Key verdict lines:
check-adr-anchors: OK (68 anchored file(s), every governing ADR still referenced; … 44138 citation(s) across 5846 file(s) resolve …)check-adr-links: 730 relative link destination(s) under docs/adr/ resolvecheck-nul-bytes: OK (scanned 11039 text file(s) …; no raw ASCII control bytes)The first run of
check:doc-formula-expressionsexited 3 (PREREQUISITE NOT MET:@objectstack/formulaand@objectstack/lintwere unbuilt). I built them under the verify lock (VERDICT command-exit 0) and re-ran it: exit 0,22 record-scoped formula example(s) … judged clean.dispatch-gates --ranreconciliation:27 derived famil(ies) accounted for — 27 run, 0 NOT-MEASURED (a DERIVED zero — all 27 recorded an exit code and none of them is 3).I also ran some roster gates outside the 27:
check:overlay-whitelist-table,check-published-list-mirrors,check:dts-closure,check:engine-double-contract,check:i18n-stale-fill.check:published-readme-exportsexited 3 because it needs a full build; this diff touches no package and no README.check:console-injectionskipped itself because there is no console dist.No changeset:
docs/adr/**and repo-rootscripts/adr-anchors/**publish nothing, so this PR takesskip-changeset.Acceptance notes
Every present-tense four-part site, found by a full re-grep. At
edecd4485there were three, not the two the card names: the [metadata] addSysMetadataOverlayIndex 用 ADR-0048 之前的键抢占 idx_sys_metadata_overlay_active——同名索引有两个生产者,先跑的赢 #6771 measurement (:835), Owner 1 (:867) and the Owner 2 quotation (:878, which the card does not name). After the edit, the only four-part spelling left in present-tense context is the preserved:835measurement, and the dated note now follows it. Every other four-part or older spelling is in dated historical blocks that this record keeps standing on purpose:project_id,scope,unique: true,partial;(type, name)per organization" is unchanged.Owner 2's trailing sentence was false after
5677add93fand is restated. The old text read "it still prevents duplicate active overlays … and it stays NULL-distinct onpackage_id". The declared index is a plain UNIQUE over five columns. It is NULL-distinct onbundle_member, and that column is NULL for every canonical member, so the fallback no longer holds any canonical row unique. I measured this on an in-memory SQLite (better-sqlite3 12.11.1) with that exact five-column plainCREATE UNIQUE INDEX:bundle_memberNULL): both INSERTED;zh-CNmember rows: the second REFUSED withSQLITE_CONSTRAINT_UNIQUE.The ADR now says "NULL-distinct on
package_idand onbundle_member— NULL for every canonical member, so it holds no canonical row unique".The code comment beside the declaration (
sys-metadata.object.ts:244-249, "it still prevents duplicate ACTIVE overlays") carries the same stale claim. It is outside this card's file surface and is not edited. I have not measured whether any real composition gets only the declared tier, so this stays a note, not a card.Bounded in-place fix: two ADR anchors. Both
invariantstrings stated the current key in the present tense with four parts:overlay-index.ts.json: "(type, name, organization_id, COALESCE(package_id, ''))WHERE state = 'active'";sys-metadata.object.ts.json: "the declaredidx_sys_metadata_overlay_activeon(type, name, organization_id, package_id)".Each now spells the five-part key, and nothing else in either string changed. All four conditions hold:
5677add93f);check:adr-anchorsis in the derived family, and it is green.The ADR line range another anchor cites did not move.
scripts/adr-anchors/packages__spec__src__kernel__metadata-plugin.zod.ts.jsoncitesdocs/adr/0005-metadata-customization-overlay.md:53-64. The status entry was appended to the existing line, so lines 53-64 are byte-identical betweenedecd4485and HEAD (diffexit 0). That anchor file is not touched.The same four-part statement in other places, not edited here (other files or other governed surfaces; listed for whoever closes the family):
docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md:669docs/adr/0126-packaged-metadata-customization-model.md:313skills/objectstack-data/rules/indexing.md:165(the published skill's partial-index example quotes the platform's runtime SQL with four parts)docs/qa/platform-checklist/areas/cli.json:1125(a QA step recreates "the declared NULL-distinct form" with four columns; the step still seeds the duplicates it needs, so this is drift only)Pre-existing, not introduced here. Both indexes keep
organization_idbare and NULL-distinct. The overlay-index module header already names this as "a separate question with its own ADR-0120 D4 ceremony". Environment rows are written withorganization_idNULL (sys-metadata-repository.ts, the ADR-0131 D6 environment-rows read), so the DB-level key does not constrain those rows on either tier. This is a read-only observation, not filed.维护者速读(草稿)
改了什么
bundle_member。unique: 'global'。为什么改
5677add93f(PR fix(metadata-protocol): two locales of one email template survive a restart — sys_metadata overlay rows keyed by bundle member (#22877, stage 1) #22954)起,运行时唯一索引和声明索引都多了bundle_member。例如同一封邮件模板的不同语言版本,现在各存一行。bundle_member是 NULL-distinct,而规范成员该列为 NULL,所以这个兜底索引已不再约束任何规范成员行。原句「仍能防止重复的 active overlay」不再成立,本 PR 按实测改写(SQLite 实测见 Acceptance notes 第 2 条)。风险与代价(含回滚)
席位意见
你要做的
Generated by Claude Code