Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .changeset/28673-every-read-row-column-binding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@objectstack/metadata-protocol": patch
---

fix(metadata-protocol)!: every metadata read states a stored row's package from its column, never from its body

The list read serves a stored row's `_packageId` from its `package_id` column only (#28594); the other reads of a stored row still stamped the column's package only while the body carried none, so a body stamp the save door would strip was echoed back. Now one rule serves them all: the by-name active and strict draft reads, the by-name draft preview, the draft list, the list merge and the registry hydration (with the items a view container row expands to) state the column's package, replacing a body stamp that names another package and dropping one on a row bound to no package.

Clause-②: no (narrowing) — a stored row whose body carries a `_packageId` other than its column's is served and registered under its column's package (or none) at every read, no longer under the body's. Nothing is widened.

Metadata-protocol: none

<!-- adr-0087: not-required (no-migration-prescription) No key is added, removed or renamed and no stored body is rewritten or refused: the row's package binding is its `package_id` column, which every read already served whenever the body carried no stamp; a body stamp that disagrees with the column was never written by the save door, so no author has anything to convert. -->

**BREAKING** read narrowing (`@objectstack/metadata-protocol`), shipped as `patch`.

- **Before.** A by-name read, a draft read or preview, the draft list and the registry hydration served a stored row whose body carried `_packageId` with the body's value, whatever its column said.
- **Now.** Each serves it with its column's package, or with none when the row is bound to no package, as the list read does.
- **Unchanged.** A row whose body carries no stamp, or one equal to its column, is served exactly as before.
- **Who sees it.** Only a row written before the save door began stripping body stamps, or by a writer other than the save door.
12 changes: 4 additions & 8 deletions packages/metadata-protocol/src/protocol-stored-overlay-reads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
type MetaOverlayCacheKey,
} from './meta-overlay-cache.js';
import type { ObjectStackProtocolImplementation, StoredOverlayEntry } from './protocol.js';
import { addressPackages } from './protocol.js';
import { addressPackages, withRowBinding } from './protocol.js';

/**
* The `ObjectStackProtocolImplementation` members the functions below read —
Expand Down Expand Up @@ -171,13 +171,9 @@ export function storedOverlayEntries(
// asks an item's owner of `_packageId` — the connector materializer
// deciding whose root a file ref reads among them. A copy, so a cached
// row's body is never written.
let data = parsed;
if (data && typeof data === 'object' && !Array.isArray(data) && (data as any)._packageId !== recPkg) {
const bound: Record<string, unknown> = { ...(data as Record<string, unknown>) };
if (recPkg) bound._packageId = recPkg;
else delete bound._packageId;
data = bound;
}
// [#28673] The one rule every read of a stored row states its package
// by: {@link withRowBinding}.
const data = withRowBinding(parsed, recPkg) as any;
// [ADR-0131 D6/D7] Every row is the environment's: the family
// declares no organization column, and the reads that feed this
// ({@link readActiveOverlayRows}) leave a legacy organization's
Expand Down
Loading
Loading