|
| 1 | +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. |
| 2 | + |
| 3 | +/** |
| 4 | + * [#25467 cut 21] The boot report of `ObjectStackProtocolImplementation` |
| 5 | + * that says out loud which stored ENVIRONMENT `sys_metadata` rows no read |
| 6 | + * serves because they overlay sealed managed content |
| 7 | + * (`reportSealedOverlayRows`, ADR-0131 D6): per type, a capped sample of |
| 8 | + * names and the two remedies. Moved out of `protocol.ts` whole. |
| 9 | + * |
| 10 | + * A MOVE, not a redesign. The function below is the body of the |
| 11 | + * `ObjectStackProtocolImplementation` method of the same name as it stood, |
| 12 | + * re-indented one level and otherwise unedited: the same grouping by type, |
| 13 | + * the same sample cap, and the same warning text. |
| 14 | + * |
| 15 | + * ## How the moved body reaches the class |
| 16 | + * |
| 17 | + * The shape #23050 set for `rest-server.ts` (its `data-action-routes.ts` |
| 18 | + * header carries the full reasoning). The class keeps the method — the |
| 19 | + * published `dist/*.d.ts` lists its name, docblock and declared signature. |
| 20 | + * The body reads no member of the class, so there is no host: the method's |
| 21 | + * stub calls the plain function directly, as `namesWithOwnStoredRow`'s does |
| 22 | + * in `protocol-stored-overlay-reads.ts`. Its one caller keeps calling the |
| 23 | + * class method. |
| 24 | + * |
| 25 | + * The body reads none of `protocol.ts`'s module-level declarations and |
| 26 | + * imports nothing. Nothing re-exports this module, so the published surface |
| 27 | + * does not move. |
| 28 | + */ |
| 29 | + |
| 30 | +/** The body of `ObjectStackProtocolImplementation#reportSealedOverlayRows`; the method's docblock there is its contract. */ |
| 31 | +export function reportSealedOverlayRows(rows: ReadonlyArray<{ type: string; name: string }>): void { |
| 32 | + if (rows.length === 0) return; |
| 33 | + const SAMPLE_PER_TYPE = 5; |
| 34 | + const byType = new Map<string, string[]>(); |
| 35 | + for (const { type, name } of rows) { |
| 36 | + const names = byType.get(type) ?? []; |
| 37 | + names.push(name); |
| 38 | + byType.set(type, names); |
| 39 | + } |
| 40 | + const detail = Array.from(byType.entries()) |
| 41 | + .map(([type, names]) => { |
| 42 | + const shown = names.slice(0, SAMPLE_PER_TYPE); |
| 43 | + const more = names.length > shown.length ? `, +${names.length - shown.length} more` : ''; |
| 44 | + return `${type}×${names.length} (${shown.join(', ')}${more})`; |
| 45 | + }) |
| 46 | + .join('; '); |
| 47 | + console.warn( |
| 48 | + `[Protocol] [metadata_sealed_overlay_unserved] ${rows.length} active environment sys_metadata row(s) ` + |
| 49 | + `overlay an item a managed package ships, on a type that is sealed against overlays (ADR-0131 D6): ` + |
| 50 | + `${detail}. No read serves them — the package's own definition is served. ` + |
| 51 | + `Each row is kept at rest, untouched (an object's table and its columns stay as they are). To keep ` + |
| 52 | + `the change, re-express it as a new item under a new ` + |
| 53 | + `name (a linkage-free clone of the managed item), then delete the stored row; otherwise delete the ` + |
| 54 | + `stored row.`, |
| 55 | + ); |
| 56 | +} |
0 commit comments