Skip to content

Commit 4c561be

Browse files
os-zhuangclaude
andcommitted
test(objectql): align install/duplicate tests with #2540 durable persistence
Two objectql protocol tests asserted the pre-#2540 behavior: - installPackage used to SKIP sys_packages persistence for versionless manifests (the {id,name} shape the builder/Setup create), so base packages vanished on restart (#2532). It now defaults version to '0.1.0' and persists. Test updated to expect persistence with the defaulted version. - duplicatePackage used to do a bare registry.installPackage write and keep the source scope. It now routes through installPackage (so the copy also lands in sys_packages) and strips scope (a duplicate must be a writable base, not inherit the source's read-only scope). Test updated to assert the routed call + scope stripped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0b7b056 commit 4c561be

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

packages/objectql/src/protocol-install-package.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,20 @@ describe('protocol.installPackage (ADR-0033 consolidation)', () => {
8181
warn.mockRestore();
8282
});
8383

84-
it('skips persistence when the manifest has no version (cannot key sys_packages)', async () => {
84+
it('persists a versionless manifest with a defaulted version (#2540: base packages must survive restart)', async () => {
85+
// Builder/Setup create base packages as bare { id, name } with no version.
86+
// Pre-#2540 these were skipped for persistence and vanished on restart (#2532).
87+
// Now installPackage defaults version to '0.1.0' so they key into sys_packages.
8588
const publish = vi.fn(async () => ({ success: true }));
8689
const { protocol, registry } = makeProtocol({ pkgSvc: { publish } });
8790
const manifest = { id: 'app.nov', name: 'NoVer', type: 'application' };
8891

8992
await protocol.installPackage({ manifest } as never);
9093

9194
expect(registry.installPackage).toHaveBeenCalledOnce();
92-
expect(publish).not.toHaveBeenCalled();
95+
expect(publish).toHaveBeenCalledTimes(1);
96+
expect((publish.mock.calls[0] as unknown[])[0]).toMatchObject({
97+
manifest: { id: 'app.nov', version: '0.1.0' },
98+
});
9399
});
94100
});

packages/objectql/src/protocol-package-lifecycle.test.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,16 @@ describe('protocol.duplicatePackage (ADR-0070 D4)', () => {
145145
sourcePackageId: 'app.iojn', targetPackageId: 'app.iojn2', targetNamespace: 'iojn2',
146146
});
147147

148-
// target package installed as a writable copy (new id + namespace, scope kept)
149-
expect(installPackage).toHaveBeenCalledWith(
150-
expect.objectContaining({ id: 'app.iojn2', namespace: 'iojn2', scope: 'environment' }),
151-
);
148+
// #2540: the copy routes through installPackage (not a bare registry
149+
// write) so it ALSO lands in sys_packages and survives a restart. And
150+
// the copy is SCOPE-LESS on purpose — the source carries scope
151+
// 'environment', but branding that onto the duplicate would make it
152+
// read-only in the writability heuristics; a duplicate must be a
153+
// writable base.
154+
expect(installPackage).toHaveBeenCalledTimes(1);
155+
const dupManifest = (installPackage as any).mock.calls[0][0];
156+
expect(dupManifest).toMatchObject({ id: 'app.iojn2', namespace: 'iojn2' });
157+
expect(dupManifest.scope).toBeUndefined();
152158

153159
const calls = (saveMetaItem as any).mock.calls.map((c: any) => c[0]);
154160
const ticket = calls.find((c: any) => c.name === 'iojn2_repair_ticket');

0 commit comments

Comments
 (0)