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
56 changes: 56 additions & 0 deletions packages/metadata-protocol/src/protocol-sealed-overlay-report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* [#25467 cut 21] The boot report of `ObjectStackProtocolImplementation`
* that says out loud which stored ENVIRONMENT `sys_metadata` rows no read
* serves because they overlay sealed managed content
* (`reportSealedOverlayRows`, ADR-0131 D6): per type, a capped sample of
* names and the two remedies. Moved out of `protocol.ts` whole.
*
* A MOVE, not a redesign. The function below is the body of the
* `ObjectStackProtocolImplementation` method of the same name as it stood,
* re-indented one level and otherwise unedited: the same grouping by type,
* the same sample cap, and the same warning text.
*
* ## How the moved body reaches the class
*
* The shape #23050 set for `rest-server.ts` (its `data-action-routes.ts`
* header carries the full reasoning). The class keeps the method — the
* published `dist/*.d.ts` lists its name, docblock and declared signature.
* The body reads no member of the class, so there is no host: the method's
* stub calls the plain function directly, as `namesWithOwnStoredRow`'s does
* in `protocol-stored-overlay-reads.ts`. Its one caller keeps calling the
* class method.
*
* The body reads none of `protocol.ts`'s module-level declarations and
* imports nothing. Nothing re-exports this module, so the published surface
* does not move.
*/

/** The body of `ObjectStackProtocolImplementation#reportSealedOverlayRows`; the method's docblock there is its contract. */
export function reportSealedOverlayRows(rows: ReadonlyArray<{ type: string; name: string }>): void {
if (rows.length === 0) return;
const SAMPLE_PER_TYPE = 5;
const byType = new Map<string, string[]>();
for (const { type, name } of rows) {
const names = byType.get(type) ?? [];
names.push(name);
byType.set(type, names);
}
const detail = Array.from(byType.entries())
.map(([type, names]) => {
const shown = names.slice(0, SAMPLE_PER_TYPE);
const more = names.length > shown.length ? `, +${names.length - shown.length} more` : '';
return `${type}×${names.length} (${shown.join(', ')}${more})`;
})
.join('; ');
console.warn(
`[Protocol] [metadata_sealed_overlay_unserved] ${rows.length} active environment sys_metadata row(s) ` +
`overlay an item a managed package ships, on a type that is sealed against overlays (ADR-0131 D6): ` +
`${detail}. No read serves them — the package's own definition is served. ` +
`Each row is kept at rest, untouched (an object's table and its columns stay as they are). To keep ` +
`the change, re-express it as a new item under a new ` +
`name (a linkage-free clone of the managed item), then delete the stored row; otherwise delete the ` +
`stored row.`,
);
}
28 changes: 4 additions & 24 deletions packages/metadata-protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ import { flowSaveReplaysRetired } from './protocol-flow-save-replay.js';
import { resolveWritePackageScope } from './protocol-write-package-scope.js';
// [#25467 cut 20] The code-layer read through the `metadata` service: package-scoped, singular/plural fallback, a stored object row's copy not counted as code.
import { readItemFromMetadataService } from './protocol-metadata-service-read.js';
// [#25467 cut 21] The boot report of the stored overlay rows no read serves because they overlay sealed managed content.
import { reportSealedOverlayRows } from './protocol-sealed-overlay-report.js';

/**
* Canonical Zod schema per metadata type lives in
Expand Down Expand Up @@ -28658,30 +28660,8 @@ export class ObjectStackProtocolImplementation implements
* sealed overlays are still not served.
*/
private reportSealedOverlayRows(rows: ReadonlyArray<{ type: string; name: string }>): void {
if (rows.length === 0) return;
const SAMPLE_PER_TYPE = 5;
const byType = new Map<string, string[]>();
for (const { type, name } of rows) {
const names = byType.get(type) ?? [];
names.push(name);
byType.set(type, names);
}
const detail = Array.from(byType.entries())
.map(([type, names]) => {
const shown = names.slice(0, SAMPLE_PER_TYPE);
const more = names.length > shown.length ? `, +${names.length - shown.length} more` : '';
return `${type}×${names.length} (${shown.join(', ')}${more})`;
})
.join('; ');
console.warn(
`[Protocol] [metadata_sealed_overlay_unserved] ${rows.length} active environment sys_metadata row(s) ` +
`overlay an item a managed package ships, on a type that is sealed against overlays (ADR-0131 D6): ` +
`${detail}. No read serves them — the package's own definition is served. ` +
`Each row is kept at rest, untouched (an object's table and its columns stay as they are). To keep ` +
`the change, re-express it as a new item under a new ` +
`name (a linkage-free clone of the managed item), then delete the stored row; otherwise delete the ` +
`stored row.`,
);
// [#25467 cut 21] The body moved to `protocol-sealed-overlay-report.ts`.
return reportSealedOverlayRows(rows);
}

// ==========================================
Expand Down
Loading