|
| 1 | +--- |
| 2 | +'@objectstack/metadata-protocol': minor |
| 3 | +--- |
| 4 | + |
| 5 | +A package's stored copy of a view container it ships overlays that package's shipped views, so a withdrawal saved in the copy holds at the anonymous form endpoints; the runtime save door refuses three copies it accepted before |
| 6 | + |
| 7 | +Clause-②: no (narrowing) |
| 8 | + |
| 9 | +<!-- adr-0087: not-required (no-migration-prescription) A validity narrowing at one runtime write door over existing keys, the consequence of where the read doors now place a stored copy's views: no key of `ViewSchema` or of any other metadata schema is removed, renamed or re-shaped, so there is no tombstone and nothing mechanical for `objectstack migrate meta` to rewrite. Whether a refused copy meant its added member as a view of its own, as an override of the other package's view, or under a key of its own is authoring intent no conversion entry can decide. New saves are refused with the remedy; a row stored before this change keeps its bytes, and no stored row is re-saved. No census of the writers that save such copies (a package's stored copy of a container it ships on another package's object) was taken: Studio, package duplication, `migrate meta --stored`, the example apps, hosted tenants and the cloud AI author were not measured. The other categories are closed on facts: the package publishes (not unpublished); no ADR-0087 id covers this rule and this diff adds none (not registered / already-registered); and the change narrows what a runtime write door accepts, not a runtime interface or a type surface alone (not runtime-interface-only / type-surface-only). --> |
| 10 | + |
| 11 | +**BREAKING** accept-set narrowing at the runtime save door, shipped as `minor` under the repo's launch-window convention for breaking changes, the grade the same door's earlier view container refusals shipped with. |
| 12 | + |
| 13 | +- **What was wrong.** The source loaders register a view container a package ships as `OBJECT.KEY` views for that package, whichever package owns the object. When that package stored a copy of the same container (a `PUT /api/v1/meta/view/NAME` of the container) and the object belonged to another code package, the copy expanded under its own name instead, as `OBJECT.CONTAINER.KEY` (a bare `list` as `OBJECT.CONTAINER`). So the copy overlaid none of the views its package ships: a form withdrawn from anonymous intake in the copy stayed open in the package's shipped form of that name, and the anonymous form endpoints kept serving it. |
| 14 | +- **What it does now.** A package's stored copy of a container that package ships, bound to the same object, expands as the loaders expand the shipped container: each member is served under the loaders' name, `OBJECT.KEY`, in the copying package's own slot on the view list and on the by-name read naming that package. So a withdrawal saved in the copy holds at the anonymous form endpoints. The copy still declares no default view for an object another package owns. Any other container on another package's object keeps expanding under its own name, unchanged. |
| 15 | +- **The by-name read on an unscoped kernel.** On a kernel with no environment id, a stored container's expanded views are also registered in the schema registry, under the bare name. A view whose name another package also ships is no longer registered there: the registry answered that bare entry ahead of the other package's own view, so `getMetaItem` naming the other package served this container's view. Every kernel's by-name read already serves such a view from its stored row, for its own package and for a read that names no package. Two packages that ship one container, with one of them storing a copy, were affected before this change too. |
| 16 | + |
| 17 | +**What is refused now.** `saveMetaItem`, which `PUT /api/v1/meta/view/NAME` and the dispatcher's metadata save both call, judges a copy at the names it now expands to, so three copies it accepted before are refused with `VALIDATION_ERROR` / 400, before anything is stored. Each is a package's copy of a container it ships on another package's object: |
| 18 | + |
| 19 | +- The copy adds a bare `list` whose name, `OBJECT.default`, only the other package ships. Before: accepted, served as `OBJECT.CONTAINER`. After: refused, naming the package that ships `OBJECT.default`. |
| 20 | +- The copy adds a keyed member (a `formViews` or `listViews` entry, a named `list`, or a `form`) whose name, `OBJECT.KEY`, only the other package ships. Before: accepted, served as `OBJECT.CONTAINER.KEY`. After: refused, naming the package that ships `OBJECT.KEY`. |
| 21 | +- Another stored container, saved under a different name, already expands a name the copy now expands. Before: accepted. After: refused, naming that stored container. |
| 22 | + |
| 23 | +**The fix.** For the first two, give the added member a key of its own that no package ships and no stored container expands, or save a view item (`name`, `object`, `viewKind`, `config`) under that name to override the other package's view. For the third, add the view as a member of the stored container that already expands the name, or save a view item under that name. |
| 24 | + |
| 25 | +**What still saves.** A copy that keeps the members its package's shipped container has, their contents edited, under the container's own name. A copy that adds a member under a key no package ships and no stored container expands. A view item under any of these names. Every container that is not a copy of its own package's shipped container, as before. |
| 26 | + |
| 27 | +**Rows stored before this change.** They keep their bytes. A stored copy of a container its package ships, on another package's object, is now served under the loaders' names (`OBJECT.KEY`) instead of `OBJECT.CONTAINER.KEY`, so it overlays the package's shipped views from the next read on, with no re-save. A reference to one of its old names (a navigation `viewName`, a form action `target`) no longer resolves; point it at `OBJECT.KEY`. A new save of a stored copy in one of the refused shapes, a re-save included, is refused until its body stops colliding. Delete stays open. |
0 commit comments