refactor: make workspace descriptors schema v3 only

This commit is contained in:
2026-08-10 20:21:20 +02:00
parent 5d016ce635
commit 512b0261b1
12 changed files with 187 additions and 295 deletions
+21 -52
View File
@@ -327,6 +327,8 @@ function persistPreStateManifest(root: string, commit: string): void {
const envExample = "# Legacy registry artifact\n";
const markdown = "# Legacy registry artifact\n";
chmodSync(join(snapshotDirectory, envName), 0o600);
chmodSync(join(snapshotDirectory, docsName), 0o600);
writeFileSync(join(snapshotDirectory, envName), envExample);
writeFileSync(join(snapshotDirectory, docsName), markdown);
active.revisions = active.revisions.map(({ state: _state, ...revision }: Record<string, unknown>) => revision);
@@ -693,25 +695,19 @@ test("resets an ahead checkout after a rejected push and retries publication", a
await expect(registry.publish(request)).resolves.toMatchObject({ id: "push-recovery" });
});
test("lists a v1 descriptor in migration-required state without rendering operational artifacts", async () => {
const legacyYaml = legacyV1Yaml();
test.each([
["v1", legacyV1Yaml()],
["v2", legacyV2Yaml()],
])("rejects a schema %s descriptor instead of activating it", async (_version, legacyYaml) => {
const remote = await fixture(legacyYaml);
const registry = new WorkspaceRegistry(config(join(remote.root, "registry"), remote.remote));
const status = await registry.bootstrap();
const [revision] = await registry.list();
expect(revision).toMatchObject({ state: "migration_required" });
await expect(registry.read("psd-clinical")).resolves.toMatchObject({
workspace: { workspace: { schema_version: 1 } },
});
expect(existsSync(join(remote.root, "registry", "snapshots", status.head!, "psd-clinical.env.example"))).toBe(false);
expect(existsSync(join(remote.root, "registry", "snapshots", status.head!, "psd-clinical.md"))).toBe(false);
await expect(registry.bootstrap()).rejects.toMatchObject({ code: "workspace_invalid" });
expect(existsSync(join(remote.root, "registry", "state", "active.json"))).toBe(false);
});
test("migrates a validated pre-state manifest and keeps its v1 workspace migration-gated", async () => {
const legacyYaml = legacyV1Yaml();
const remote = await fixture(legacyYaml);
test("migrates a validated pre-state manifest while preserving its v3 operational state", async () => {
const remote = await fixture();
const root = join(remote.root, "registry");
const firstRegistry = new WorkspaceRegistry(config(root, remote.remote));
await firstRegistry.bootstrap();
@@ -723,19 +719,20 @@ test("migrates a validated pre-state manifest and keeps its v1 workspace migrati
degraded: false,
});
await expect(restoredRegistry.list()).resolves.toMatchObject([
{ id: "psd-clinical", state: "migration_required" },
{ id: "psd-clinical", state: "operational" },
]);
const active = JSON.parse(readFileSync(join(root, "state", "active.json"), "utf8"));
const manifest = JSON.parse(readFileSync(join(root, "snapshots", remote.initialCommit, "snapshot.json"), "utf8"));
expect(active.revisions[0].state).toBe("migration_required");
expect(manifest.revisions[0].state).toBe("migration_required");
expect(Object.keys(manifest.files)).toEqual(["psd-clinical.yaml"]);
expect(active.revisions[0].state).toBe("operational");
expect(manifest.revisions[0].state).toBe("operational");
expect(Object.keys(manifest.files).sort()).toEqual([
"psd-clinical.env.example", "psd-clinical.md", "psd-clinical.yaml",
]);
});
test("finishes a pre-state active manifest migration after its snapshot was atomically updated", async () => {
const legacyYaml = legacyV1Yaml();
const remote = await fixture(legacyYaml);
test("finishes a pre-state active manifest migration after its v3 snapshot was atomically updated", async () => {
const remote = await fixture();
const root = join(remote.root, "registry");
const registry = new WorkspaceRegistry(config(root, remote.remote));
await registry.bootstrap();
@@ -743,19 +740,17 @@ test("finishes a pre-state active manifest migration after its snapshot was atom
const snapshotPath = join(root, "snapshots", remote.initialCommit, "snapshot.json");
const manifest = JSON.parse(readFileSync(snapshotPath, "utf8"));
manifest.revisions[0].state = "migration_required";
manifest.files = { "psd-clinical.yaml": manifest.files["psd-clinical.yaml"] };
manifest.revisions[0].state = "operational";
writeFileSync(snapshotPath, JSON.stringify(manifest));
const restoredRegistry = new WorkspaceRegistry(config(root, remote.remote));
await expect(restoredRegistry.list()).resolves.toMatchObject([
{ id: "psd-clinical", state: "migration_required" },
{ id: "psd-clinical", state: "operational" },
]);
});
test("rejects a corrupt pre-state manifest rather than accepting it during migration", async () => {
const legacyYaml = legacyV1Yaml();
const remote = await fixture(legacyYaml);
const remote = await fixture();
const root = join(remote.root, "registry");
const registry = new WorkspaceRegistry(config(root, remote.remote));
await registry.bootstrap();
@@ -872,32 +867,6 @@ test("a session revision lease survives stale retention scans until its manifest
expect(existsSync(registry.snapshotPath(remote.initialCommit, "psd-clinical"))).toBe(false);
});
test("does not acquire a session revision lease for a migration_required workspace", async () => {
const remote = await fixture(legacyV1Yaml());
const registry = new WorkspaceRegistry(config(join(remote.root, "registry"), remote.remote));
await registry.bootstrap();
await expect(registry.acquireSessionRevision("psd-clinical")).rejects.toMatchObject({
code: "workspace_invalid",
});
});
test("lists a schema v2 descriptor as migration_required and refuses to acquire it", async () => {
const remote = await fixture(legacyV2Yaml());
const registry = new WorkspaceRegistry(config(join(remote.root, "registry"), remote.remote));
await registry.bootstrap();
await expect(registry.list()).resolves.toMatchObject([
{ id: "psd-clinical", state: "migration_required" },
]);
await expect(registry.acquireSessionRevision("psd-clinical")).rejects.toMatchObject({
code: "workspace_invalid",
});
await expect(registry.readPinned("psd-clinical", remote.initialCommit)).rejects.toMatchObject({
code: "workspace_invalid",
});
});
test("lists operational descriptors retained after their workspace was removed from the active revision", async () => {
const remote = await fixture();
const root = join(remote.root, "registry");