You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 85abb2e
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/adr/0005-metadata-customization-overlay.md
+19-9Lines changed: 19 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@
5
5
> **Protocol 18 update (2026-10-12, ADR-0131 C5, #22340):** The per-type overlay opt-in on `MetadataTypeRegistryEntry` is spelled `allowEnvironmentOverlay` from protocol 18 (`packages/spec/src/kernel/metadata-plugin.zod.ts#allowEnvironmentOverlay`). [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D6 retired the per-organization overlay axis, so the key now names the one scope it governs — whether an environment may overlay an item of this type that a managed package ships. The old key `allowOrgOverride` stays on the registry entry schema only as a tombstone that refuses at parse with the new name in its prescription: no second key, no alias, no conversion. The lines below that name `allowOrgOverride` describe the field as it was spelled when they were written and are preserved verbatim.
6
6
7
7
8
-
**Status**: Accepted (2026-05-16) · **Amended** (2026-05-22, see "Amendment: post-ADR-0006 v4 scope") · **Amended** (2026-04-13, branch concept removed — see [ADR-0008 §0](./0008-metadata-repository-and-change-log.md#0-2026-04-13-amendment--drop-project-and-branch-from-metaref)) · **Amended** (2026-08-09, #6825 — the Phase-1 overlay-index migration is deleted; see "Amendment (2026-08-09, #6825): overlay-index delivery after the Phase-1 migration was deleted") · **Amended** (2026-09-04, [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D6 — the per-organization overlay axis is **retired for now**: `sys_metadata` carries no organization column, org-scoped writes of the five tier-A types are refused, and the environment layer is the whole ledger; the environment → code layered resolution and the "no overlay row = the registry" reading are unchanged) · **Amended** (2026-09-30, #20051 ruling 甲 — in "Addendum — 2026-05-16 (c)", which code cites as appendix (c), the persisted document is the **parsed body** once every round-trip key is declared, reversing the verbatim `request.item` save; a stored `view` row's round-trip keys are declared, and the storage switch itself, the ruling's last stage, is in force for `view` since PR #20868 (`9905e61ca2`) — see the amendment notes under that addendum's persisted-document bullet) · **Amended** (2026-09-30, #20051 ruling B — the parsed body a `view` stores is the parsed value of every key its request body carried, not the whole parse output: undeclared keys dropped, schema defaults not materialised, a moved key stored under its canonical spelling; every other type still stores its request body — see the second amendment note under that bullet)
8
+
**Status**: Accepted (2026-05-16) · **Amended** (2026-05-22, see "Amendment: post-ADR-0006 v4 scope") · **Amended** (2026-04-13, branch concept removed — see [ADR-0008 §0](./0008-metadata-repository-and-change-log.md#0-2026-04-13-amendment--drop-project-and-branch-from-metaref)) · **Amended** (2026-08-09, #6825 — the Phase-1 overlay-index migration is deleted; see "Amendment (2026-08-09, #6825): overlay-index delivery after the Phase-1 migration was deleted") · **Amended** (2026-09-04, [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) D6 — the per-organization overlay axis is **retired for now**: `sys_metadata` carries no organization column, org-scoped writes of the five tier-A types are refused, and the environment layer is the whole ledger; the environment → code layered resolution and the "no overlay row = the registry" reading are unchanged) · **Amended** (2026-09-30, #20051 ruling 甲 — in "Addendum — 2026-05-16 (c)", which code cites as appendix (c), the persisted document is the **parsed body** once every round-trip key is declared, reversing the verbatim `request.item` save; a stored `view` row's round-trip keys are declared, and the storage switch itself, the ruling's last stage, is in force for `view` since PR #20868 (`9905e61ca2`) — see the amendment notes under that addendum's persisted-document bullet) · **Amended** (2026-09-30, #20051 ruling B — the parsed body a `view` stores is the parsed value of every key its request body carried, not the whole parse output: undeclared keys dropped, schema defaults not materialised, a moved key stored under its canonical spelling; every other type still stores its request body — see the second amendment note under that bullet) · **Amended** (2026-10-12, #22877 ruling A — the overlay uniqueness key gains a fifth part, `bundle_member`: the member of a bundled type, such as an `email_template`'s locale, so two members of one item are two overlay rows; NULL is the canonical member, so every row of a type whose identity is `name` alone is unchanged. In force since `5677add93f` (PR #22954) — see "What delivers overlay uniqueness today")
**Amended by**: [ADR-0006 v4](./0006-project-environment-split.v4.md) (drops `sys_project` entirely), [ADR-0008](./0008-metadata-repository-and-change-log.md) (re-expresses overlay as `LayeredRepository`; subsequently drops `project`/`branch` from `MetaRef`), [ADR-0029 D9](./0029-kernel-object-ownership-and-platform-objects-decomposition.md#amendment-2026-08-09-6853-a-tenant-overlay-of-an-object-is-its-own-contributor-layer-not-a-second-own) (for `object` only: the overlay is a registry contributor LAYER over the packaged owner, resolved as `base = overlay ?? own`, instead of a destructive in-place overwrite), [ADR-0131](./0131-total-organization-ownership-no-null-organization-id.md) C5 / D6 (the per-organization overlay axis is retired and the per-type opt-in is spelled `allowEnvironmentOverlay` from protocol 18 — the note at the top of this record)
@@ -838,6 +838,10 @@ migration. The deleted producer could therefore only ever no-op (while reporting
838
838
`status: 'created'`) or, in its one non-no-op window, install the retired key
839
839
that nothing afterwards repaired.
840
840
841
+
> **2026-10-12 note** — "the current key" above is the four-part key #6771 measured.
842
+
> Since `5677add93f` (#22877 ruling A) the declared index and the runtime key carry a
843
+
> fifth part, `bundle_member` — see the status line and the two owners below.
844
+
841
845
### Two staleness items in the same block that PREDATE #6771
842
846
843
847
The YAML example there is stale for reasons of its own; attributing them to
@@ -864,22 +868,28 @@ The YAML example there is stale for reasons of its own; attributing them to
864
868
(`packages/metadata-protocol/src/migrations/overlay-index.ts`, run at most once
865
869
per protocol instance through its own `ensureOverlayIndex`) — the tier this ADR
866
870
actually wants. Raw SQL, partial and NULL-safe:
867
-
`(type, name, organization_id, COALESCE(package_id, ''))``WHERE state = 'active'`,
871
+
`(type, name, organization_id, COALESCE(package_id, ''), COALESCE(bundle_member, ''))``WHERE state = 'active'`,
868
872
with a sibling `idx_sys_metadata_overlay_draft` so an active row and a draft row
869
-
for one key can coexist. `COALESCE` is what constrains package-less (global)
870
-
overlays, which a plain UNIQUE leaves unconstrained because SQL treats NULLs as
871
-
distinct. On a dialect that cannot build the partial form it degrades to a
873
+
for one key can coexist. The fifth part (since `5677add93f`, #22877 ruling A) is a
874
+
bundled type's member — an `email_template`'s locale — so two members of one item
875
+
are two rows; it is NULL for the canonical member and for every row of a name-only
876
+
type. `COALESCE` is what constrains package-less (global) overlays and canonical
877
+
members, which a plain UNIQUE leaves unconstrained because SQL treats NULLs as
878
+
distinct; folded to `''`, those rows are constrained exactly as under the four-part
879
+
key. On a dialect that cannot build the partial form it degrades to a
872
880
**non-unique** composite index — deliberately, since an unrestricted UNIQUE
873
881
would reject the active/draft coexistence — and reports that uniqueness is not
874
882
enforced instead of claiming success. It builds under a throwaway name first and
875
883
only then replaces the real one, so a failure keeps the previous index; every
876
884
failure is reported in the ADR-0120 D4 shape and none blocks the boot.
877
885
2.**The declaration in `metadata-core`'s `sys-metadata.object.ts`** —
Copy file name to clipboardExpand all lines: docs/adr/0139-engine-internal-semi-join-leaf-readable-parent-ids.md
+14-7Lines changed: 14 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,16 @@
1
1
# ADR-0139: One engine-internal semi-join leaf — "the ids of object X this caller may read" — pushed down by ObjectQL, never authorable; ADR-0055 row (a) and ADR-0056's non-goal revisited for this one leaf
2
2
3
-
**Status**: Proposed (2026-10-10). **This record declares; it implements nothing.** It becomes **Accepted** on the
4
-
maintainer's approval (`docs/adr/**` is Tier H, Prime Directive #14); the execution cards under
5
-
[Execution plan](#execution-plan-after-acceptance) are cut after acceptance and ⛔ never before it. Until then the
6
-
platform stays in the ruling's letter D state, and letter C (a located 400 at the bound, after objectui#12081 item 8)
7
-
is the `domain:services` lane's interim on [#22590](https://github.com/objectstack-ai/objectstack/issues/22590).
3
+
**Status**: Accepted (2026-10-11), accepted by the merge that landed it on `main`
Copy file name to clipboardExpand all lines: scripts/adr-anchors/packages__metadata-core__src__objects__sys-metadata.object.ts.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -3,5 +3,5 @@
3
3
"adrs": [
4
4
"ADR-0005"
5
5
],
6
-
"invariant": "ADR-0005 overlay uniqueness (amended 2026-08-09, #6825) — the declared `idx_sys_metadata_overlay_active` on `(type, name, organization_id, package_id)` is the COARSE fallback a stack assembled without `metadata-protocol`'s runtime migration gets: unrestricted and NULL-distinct, so it also collides with archived/reset rows. That is deliberate, not an oversight to fix here — knex's `table.unique()`, which `SqlDriver.syncDeclaredIndexes` builds through, can express neither `WHERE state = 'active'` nor `COALESCE(package_id, '')`, which is why the runtime tier exists. Do NOT re-add a `partial:` key (retired at protocol 17, #5248 / #4943, ADR-0049 — no driver ever emitted the predicate) and do NOT put `environment_id` or `scope` back in the discriminator: `environment_id` is retired and NULL on new rows, `package_id` is in the key under ADR-0048 so two packages shipping the same (type, name) each keep their own overlay row."
6
+
"invariant": "ADR-0005 overlay uniqueness (amended 2026-08-09, #6825) — the declared `idx_sys_metadata_overlay_active` on `(type, name, organization_id, package_id, bundle_member)` is the COARSE fallback a stack assembled without `metadata-protocol`'s runtime migration gets: unrestricted and NULL-distinct, so it also collides with archived/reset rows. That is deliberate, not an oversight to fix here — knex's `table.unique()`, which `SqlDriver.syncDeclaredIndexes` builds through, can express neither `WHERE state = 'active'` nor `COALESCE(package_id, '')`, which is why the runtime tier exists. Do NOT re-add a `partial:` key (retired at protocol 17, #5248 / #4943, ADR-0049 — no driver ever emitted the predicate) and do NOT put `environment_id` or `scope` back in the discriminator: `environment_id` is retired and NULL on new rows, `package_id` is in the key under ADR-0048 so two packages shipping the same (type, name) each keep their own overlay row."
Copy file name to clipboardExpand all lines: scripts/adr-anchors/packages__metadata-protocol__src__migrations__overlay-index.ts.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -3,5 +3,5 @@
3
3
"adrs": [
4
4
"ADR-0005"
5
5
],
6
-
"invariant": "ADR-0005 overlay uniqueness (amended 2026-08-09, #6825) — `ensureMetadataOverlayIndexes` is the FINE tier that actually delivers the decision: `(type, name, organization_id, COALESCE(package_id, ''))` `WHERE state = 'active'`, plus the `_draft` sibling. Three properties look improvable from inside this file alone and are each a recorded decision: (a) the fallback on dialects without partial indexes stays NON-unique, because an unrestricted UNIQUE would reject the active+draft coexistence the two indexes exist to allow; (b) `idx_sys_metadata_overlay_active` deliberately reuses the name `metadata-core`'s `sys-metadata.object.ts` declares, since `SqlDriver.syncDeclaredIndexes` skips by name and that is what stops the coarser declared form from being re-imposed; (c) it builds under a probe name before replacing the real one, and every failure keeps the previous index and is reported per ADR-0120 D4 without blocking the boot. #6771 deleted `@objectstack/metadata`'s second, stale-keyed producer of this same index name — do not grow a third."
6
+
"invariant": "ADR-0005 overlay uniqueness (amended 2026-08-09, #6825) — `ensureMetadataOverlayIndexes` is the FINE tier that actually delivers the decision: `(type, name, organization_id, COALESCE(package_id, ''), COALESCE(bundle_member, ''))` `WHERE state = 'active'`, plus the `_draft` sibling. Three properties look improvable from inside this file alone and are each a recorded decision: (a) the fallback on dialects without partial indexes stays NON-unique, because an unrestricted UNIQUE would reject the active+draft coexistence the two indexes exist to allow; (b) `idx_sys_metadata_overlay_active` deliberately reuses the name `metadata-core`'s `sys-metadata.object.ts` declares, since `SqlDriver.syncDeclaredIndexes` skips by name and that is what stops the coarser declared form from being re-imposed; (c) it builds under a probe name before replacing the real one, and every failure keeps the previous index and is reported per ADR-0120 D4 without blocking the boot. #6771 deleted `@objectstack/metadata`'s second, stale-keyed producer of this same index name — do not grow a third."
0 commit comments