Skip to content

Commit 4f11fa3

Browse files
committed
fix(rest,runtime): the published doors serve the loader's body when the layered read decided it for a shipped flow name (#21002)
Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5635944 commit 4f11fa3

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

‎packages/rest/src/rest-server.ts‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8494,7 +8494,26 @@ export class RestServer {
84948494
: {}),
84958495
});
84968496
if (layered?.overlay !== undefined && layered?.overlay !== null) {
8497-
publishedOverlay = layered.overlay;
8497+
// [#21002, ADR-0126 §2] When the layered
8498+
// read put the LOADER's body over this stored
8499+
// row — a shipped flow name, decided by the
8500+
// protocol's `isShippedFlowName` — this door
8501+
// serves that effective layer, not the row:
8502+
// `flow` is Regime C, "never an overlay read
8503+
// path". The predicate is ASKED of its owner
8504+
// with the answer's own `type` / `name`,
8505+
// never re-derived here, so this door and
8506+
// `getMetaItemLayered` read one rule. Every
8507+
// other stored row is served exactly as
8508+
// before — an `object` too, whose effective
8509+
// layer differs from its row by folding, not
8510+
// by this decision — and so is every row of a
8511+
// protocol that brings no such predicate.
8512+
const shippedFlow: { isShippedFlowName?(type: string, name: unknown): boolean } = publishedProtocol;
8513+
publishedOverlay = typeof shippedFlow.isShippedFlowName === 'function'
8514+
&& shippedFlow.isShippedFlowName(layered.type, layered.name)
8515+
? layered.effective
8516+
: layered.overlay;
84988517
}
84998518
} catch (overlayError: any) {
85008519
// [#5532] The overlay read is NOT blanket-swallowed,

‎packages/runtime/src/domains/meta.ts‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ import {
4242
// which is the whole reason `MetaDomainProtocol` below is `Pick`ed rather than
4343
// written out. Same move `domains/packages.ts` and `domains/mcp.ts` make.
4444
import type { MetadataProtocol } from '@objectstack/spec/api';
45+
// [#21002] The implementation class, for the ONE member it declares that this
46+
// domain asks (`isShippedFlowName`) — `Pick`ed below, never restated.
47+
import type { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol';
4548
// [#20193] THE per-caller read gate of a `/meta/:type/:name` document — the one
4649
// `RestServer` asks, published by `@objectstack/rest` so this transport asks it
4750
// too instead of a second audience resolver (ruling `5793362670` item 1).
@@ -145,10 +148,18 @@ import type { DomainHandlerDeps, DomainRoute } from '../domain-handler-registry.
145148
* `unknown` rather than `string`, for the same reason the verbs above keep
146149
* `any` requests — nothing declares its type, and the only thing that branch
147150
* asks of it is whether it is `undefined`.
151+
*
152+
* [#21002] A third group: `isShippedFlowName`, the predicate the layered read
153+
* decides its effective layer with, which `/published` asks so it follows that
154+
* decision. Its signature is DECLARED — on `ObjectStackProtocolImplementation`
155+
* itself — so it is `Pick`ed from that class, never restated: a rename at the
156+
* producer is a compile error here, the same move `domains/automation.ts`
157+
* makes for `packagedBaseRefusal`.
148158
*/
149159
export type MetaDomainProtocol =
150160
Partial<Pick<MetadataProtocol,
151161
'getMetaTypes' | 'getMetaItems' | 'getMetaItem' | 'saveMetaItem' | 'getMetaItemLayered'>>
162+
& Partial<Pick<ObjectStackProtocolImplementation, 'isShippedFlowName'>>
152163
& {
153164
/** ⚠️ Undeclared request shapes — see "Where the ledger honestly ends". */
154165
listDrafts?(request: any): Promise<any>;
@@ -1132,7 +1143,19 @@ export async function handleMetadataRequest(deps: DomainHandlerDeps, path: strin
11321143
...(organizationId ? { organizationId } : {}),
11331144
});
11341145
if (layered?.overlay !== undefined && layered?.overlay !== null) {
1135-
publishedOverlay = layered.overlay;
1146+
// [#21002, ADR-0126 §2] As `RestServer`'s `/published`: when
1147+
// the layered read put the LOADER's body over this stored
1148+
// row — a shipped flow name, decided by the protocol's
1149+
// `isShippedFlowName`, asked with the answer's own `type` /
1150+
// `name` and never re-derived here — serve that effective
1151+
// layer, not the row (`flow` is Regime C, "never an overlay
1152+
// read path"). Every other stored row, an `object`'s
1153+
// included, and every row of a protocol without the
1154+
// predicate, is served exactly as before.
1155+
publishedOverlay = typeof protocol.isShippedFlowName === 'function'
1156+
&& protocol.isShippedFlowName(layered.type, layered.name)
1157+
? layered.effective
1158+
: layered.overlay;
11361159
}
11371160
} catch { /* fall through to the code/package snapshot below */ }
11381161
}

0 commit comments

Comments
 (0)