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
14 changes: 14 additions & 0 deletions .changeset/28771-sealed-overlay-report-served-override.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@objectstack/metadata-protocol': patch
---

fix(metadata-protocol): the boot's sealed-overlay report no longer counts a served `.custom` override or tells the operator to delete it (#28771)

Clause-②: no
Metadata-protocol: none

At boot, `[metadata_sealed_overlay_unserved]` lists the environment rows that overlay sealed managed content, says no read serves them, and prescribes deleting each stored row. Since #28412 the shipping package's declared override in its paired `<base>.custom` package is served, and for a flow it is armed in place of the base. The report still counted that row, so it told the operator to delete the live customization.

- **A served override is not counted.** The census skips a row that the one served-override predicate (`isServedOverrideRowOf`) admits, judged on the row's `package_id` column, never on a body's `_packageId`.
- **Every unserved row is still reported, with its remedies.** That includes the legacy package-less row a declared override leaves shadowed, the pair's undeclared row, a dependent package's declaration, and a package-less row whose body only names the pair. The count goes down by exactly the served rows.
- **Nothing else changes.** Which row is served, loaded or armed stays the same; only the report line changes.
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,56 @@ describe('§3 the boot report names the sealed overlays, per type, with their re
expect(sealed[0]).toContain('datasource×1 (pkg_ds)');
expect(sealed[0]).not.toContain('host_ds');
});

// [#28771, ADR-0146 D2] The shipping package's declared `.custom` override
// of a shipped flow is served (and armed) since #28412, so the census that
// says "no read serves them … delete the stored row" does not count it. The
// judgement is `isServedOverrideRowOf` on the row's `package_id` column.
describe('[#28771] a served .custom override is not counted as unserved', () => {
const FLOW = 'managed_flow';
const PAIR = `${PKG}.custom`;
const DECLARED = { overrides: { package: PKG, basedOn: '1.0.0' } };
const flowArtifact: Artifact = { type: 'flow', name: FLOW, body: { name: FLOW, _packageId: PKG } };
const override = (over: Row = {}, body: Row = DECLARED) =>
metaRow('flow', FLOW, { label: 'override', ...body }, { id: 'r_flow_override', package_id: PAIR, ...over });
const legacy = () => metaRow('flow', FLOW, { label: 'legacy' }, { id: 'r_flow_legacy' });
const sealedLines = (warns: string[]) => warns.filter((w) => w.includes('[metadata_sealed_overlay_unserved]'));

it('a boot holding only the declared override prints no sealed-overlay line', async () => {
const { warns } = await boot({ sys_metadata: [override()] }, [flowArtifact]);
expect(sealedLines(warns)).toEqual([]);
});

it('a boot holding the override and a legacy package-less row reports the legacy row alone, with its remedies', async () => {
const { warns } = await boot({ sys_metadata: [override(), legacy()] }, [flowArtifact]);
const sealed = sealedLines(warns);
expect(sealed).toHaveLength(1);
expect(sealed[0]).toContain(`1 active environment sys_metadata row(s)`);
expect(sealed[0]).toContain(`flow×1 (${FLOW})`);
expect(sealed[0]).toContain('linkage-free clone');
expect(sealed[0]).toContain('delete the stored row');
});

it('control: a legacy row alone is reported as before', async () => {
const { warns } = await boot({ sys_metadata: [legacy()] }, [flowArtifact]);
const sealed = sealedLines(warns);
expect(sealed).toHaveLength(1);
expect(sealed[0]).toContain(`flow×1 (${FLOW})`);
});

for (const [label, row] of [
['the pair\'s undeclared row', () => override({}, {})],
['a dependent package\'s declaration', () => override({ package_id: 'app.partner' })],
['a package-less row whose body stamps the pair', () => metaRow('flow', FLOW, { label: 'stamped', _packageId: PAIR, ...DECLARED }, { id: 'r_flow_stamped' })],
] as const) {
it(`control: ${label} is served by no rule, so it is still reported`, async () => {
const { warns } = await boot({ sys_metadata: [row()] }, [flowArtifact]);
const sealed = sealedLines(warns);
expect(sealed).toHaveLength(1);
expect(sealed[0]).toContain(`flow×1 (${FLOW})`);
});
}
});
});

describe('§4 [ADR-0131 C7] the anonymous form doors\' legacy organization read is deleted', () => {
Expand Down
16 changes: 15 additions & 1 deletion packages/metadata-protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29382,7 +29382,21 @@ export class ObjectStackProtocolImplementation implements
// defines in code is named once, by the
// datasource-admin boot restore's warning, which
// carries its own remedy — not here as well.
if (!this.isHostCodeDatasource(normalizedType, String(record.name))) {
//
// [#28771, ADR-0146 D2] …nor a row the served-override
// rule serves: the shipping package's declared `.custom`
// override IS served (and, for a flow, armed), so a line
// saying "no read serves them … delete the stored row"
// would prescribe deleting the live customization. The
// one predicate, on the row's `package_id` column. The
// census only: what this loop loads is unchanged.
if (
!this.isHostCodeDatasource(normalizedType, String(record.name))
&& !isServedOverrideRowOf(
record as ServedOverrideRow,
this.packagedArtifactOwner({ type: normalizedType, name: String(record.name) }),
)
) {
sealedOverlays.push({ type: normalizedType, name: String(record.name) });
}
if (normalizedType === 'object') continue;
Expand Down
Loading