Skip to content

Commit 99b3cfa

Browse files
committed
Merge origin/main into claude/issue-20676-mount-flow-clone
Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
2 parents ab7d501 + 085ca6b commit 99b3cfa

5 files changed

Lines changed: 162 additions & 84 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
The `manifest`, `dataset` and `permission` liveness ledgers cite the commit that decided each note, or say the decision in words, instead of a tracker number that no longer resolves
6+
7+
Clause-②: no
8+
9+
Notes in these three ledgers named GitHub issues that no longer exist, so a reader could
10+
not tell why a row carries its verdict. Each such note now either names the commit that
11+
made the decision or, where the number alone carried the meaning, says what was decided. The
12+
`liveness/` ledgers ship in this package's tarball, which is why this is a release note at
13+
all. Note text only: no row's status, evidence, proof or date changes, and no schema,
14+
export or runtime behaviour changes.

‎docs/adr/0005-metadata-customization-overlay.md‎

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
> **v5.0 update (2026):** Throughout this document, the term *project* has been renamed to *environment* (no aliases; CLI flags, URL paths, schemas, env vars all hard-renamed). See [ADR-0006 v4 — the v5.0 rename and its no-alias decision](./0006-project-environment-split.v4.md#the-v50-rename-and-its-no-alias-decision) for the rationale. The body below is preserved verbatim for historical context.
44
55

6-
**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)
6+
**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 is the ruling's last stage, not yet landed — see the amendment note under that addendum's persisted-document bullet)
77
**Deciders**: ObjectStack Protocol Architects
88
**Builds on**: [ADR-0003](./0003-package-as-first-class-citizen.md) (Package as first-class citizen), [ADR-0004](./0004-cloud-multi-kernel.md) (Cloud + per-project kernels)
99
**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)
@@ -334,12 +334,76 @@ Implementation (`packages/metadata-protocol/src/protocol.ts`):
334334
carrying `path/message/code` for each Zod issue. REST layer
335335
(`packages/rest/src/rest-server.ts`) already propagates `status`
336336
and `code` to the response.
337-
- The persisted document is the **original** `request.item`, NOT
338-
`parsed.data`. Studio attaches auxiliary fields (`isPinned`,
339-
`isDefault`, `sortOrder`, `objectName`, …) that aren't in the canonical
340-
schema; storing `parsed.data` would silently strip them on every save.
341-
This trades strict-stripping against forward compatibility for Studio
342-
extensions — the canonical fields are still type-checked.
337+
- The persisted document is the **parsed body** (`parsed.data`) once every
338+
round-trip key is declared. A key a client writes onto a stored row and
339+
reads back after a reload is declared on the type's schema, with its
340+
meaning, so the parse keeps it; a key nothing declares is not stored. The
341+
canonical fields are type-checked, and the stored row is what the contract
342+
says it is. ⚠️ **Ruled, not yet in force:** the storage switch is the
343+
ruling's last stage and has not landed, so today `saveMetaItem` still
344+
stores the request body (`request.item`). The note below records what is
345+
declared and what remains.
346+
347+
> **Amended (2026-09-30) — the persisted document is the parsed body once
348+
> every round-trip key is declared, and a stored `view` row's round-trip
349+
> keys now are.** Provenance: ruling 甲 on #20051 — maintainer
350+
> 「开始总监决裁」, 2026-09-27, director batch #227 item 2, recorded on the
351+
> card as comment 5856781584 — which keeps the persistence half of ruling A
352+
> (comment 5824043998, item 2) as the end state: 「a saved view is the
353+
> parsed body, every key the console reads back is declared on the
354+
> contract, and ADR-0005 appendix (c) is amended to say so」. Code cites
355+
> this addendum as "ADR-0005 appendix (c)". Why: stored as sent, the Studio
356+
> keys lived in the store and nowhere in the contract, and nothing failed
357+
> while the parse dropped them unread. State the console needs after a
358+
> reload is declared, not kept alive by a store-the-raw-request exception.
359+
>
360+
> 1. **Superseded.** The bullet above read, as written on 2026-05-16:
361+
> "The persisted document is the **original** `request.item`, NOT
362+
> `parsed.data`. Studio attaches auxiliary fields (`isPinned`,
363+
> `isDefault`, `sortOrder`, `objectName`, …) that aren't in the
364+
> canonical schema; storing `parsed.data` would silently strip them on
365+
> every save. This trades strict-stripping against forward compatibility
366+
> for Studio extensions — the canonical fields are still type-checked."
367+
> 2. **What "every round-trip key is declared" means for `view`** (stage
368+
> (ii) of the ruling, #20456, PR #20474). It means one record:
369+
> `packages/spec/src/ui/view.zod.ts#VIEW_CONSOLE_ROUND_TRIP_KEYS`, each key the console writes onto a stored `view` row and reads back, mapped to the `#VIEW_METADATA_MEMBERS` branches it is declared on.
370+
> `packages/spec/src/ui/view-console-round-trip-keys.test.ts` holds the
371+
> record equal to the census of objectui's console at the
372+
> `.objectui-sha` pin, and holds each (key, member) pair declared,
373+
> described and kept by a parse. A new round-trip key joins the record,
374+
> declared on its members, in the change that adds the console write.
375+
> 3. **The declarations, key by key** — a reading at `origin/main`
376+
> `c9c182ed`; the record, not this list, is the authority. Two members
377+
> carry them: `viewItem`, published as `packages/spec/src/ui/view.zod.ts#ViewItemWireSchema`, and `listOverlay`, published as `packages/spec/src/ui/view.zod.ts#VIEW_METADATA_MEMBERS.listOverlay`.
378+
> - `isPinned`, `sortOrder`, `visibility`: one declaration, `packages/spec/src/ui/view.zod.ts#viewSwitcherRowStateFields`, spread into the two members by `#viewItemWireFields` and `#listOverlayRoundTripFields`.
379+
> - `isDefault`: `packages/spec/src/ui/view.zod.ts#viewItemBaseShape` on `viewItem`, `#flattenedViewOverlayFields` on `listOverlay`.
380+
> - `columnState`: `packages/spec/src/ui/view.zod.ts#viewItemWireFields` on `viewItem`, `#flattenedViewOverlayFields` on `listOverlay`.
381+
> - `_isOverride`: `packages/spec/src/ui/view.zod.ts#listOverlayRoundTripFields`, on `listOverlay` only, the one row shape the console's settings-overlay marker is written on.
382+
>
383+
> No form-overlay row carries these keys: the switcher lists list-family
384+
> views only.
385+
> 4. **The census's other finds map to a spelling already declared, not to
386+
> a new key.** `objectName`, named in the superseded bullet, maps to
387+
> `object`; a top-level `id` maps to `name`; a bare-array
388+
> `exportOptions` maps to the object form the parse lifts it to.
389+
> `filter[].id` / `sort[].id` are removed before the parse by `packages/spec/src/ui/view.zod.ts#stripViewConsoleDecorations` (`#VIEW_CONSOLE_ROW_DECORATIONS`).
390+
> `_draft` / `_diagnostics` are `packages/spec/src/kernel/metadata-read-decorations.ts#METADATA_READ_DECORATIONS`, stamped on the read and never stored.
391+
> The record's docblock gives the reason for each.
392+
> 5. **Interim state: the storage switch is stage (iv) of #20051, and it
393+
> has not landed.** Until it does, `packages/metadata-protocol/src/protocol.ts#saveMetaItem` stores the request body, with the normalizations it grafts back from the parse, and the pins that hold that verbatim save stay green.
394+
> One of them is `packages/objectql/src/protocol-meta.test.ts`
395+
> "preserves Studio-only auxiliary fields verbatim (not stripped)", the
396+
> 2026-05-16 "unknown extras preserved" case listed below. So today a
397+
> key no member declares is still stored: "declared" does not yet mean
398+
> "the only keys stored".
399+
> 6. **What stage (iv) does, on #20051 itself.** Persistence stores the
400+
> parsed body; the GUARD pins flip to assert the declared round-trip
401+
> instead of the verbatim save; the top-level `options` of
402+
> `ViewItemWireSchema` is judged in the same step; and the switch lands
403+
> only once the count of stored `view` rows carrying undeclared top-level
404+
> keys has been measured against production `sys_metadata`. Made before
405+
> its prerequisites, the switch turns 「stored and unread」 into 「200,
406+
> then the user's pinned / sort / visibility state silently dropped」.
343407
344408
Sample 422 response:
345409

0 commit comments

Comments
 (0)