import assert from 'node:assert/strict'; import { afterEach, beforeEach, describe, it } from 'node:test'; import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { createLiveSessionStore } from '../skill/scripts/live/session-store.mjs'; import { prepareGenerationArtifact, publishGenerationArtifact, sha256, } from '../skill/scripts/live/generation-publisher.mjs'; describe('transactional generation publisher', () => { let tmp; let source; let artifact; let store; beforeEach(() => { tmp = mkdtempSync(join(tmpdir(), 'impeccable-publisher-')); source = join(tmp, 'page.html'); artifact = join(tmp, 'variant.html'); writeFileSync(source, '
Original
'); store = createLiveSessionStore({ cwd: tmp, sessionId: 'abc12345' }); store.appendEvent({ type: 'generate', id: 'abc12345', generationEpoch: 1, action: 'polish', count: 3, element: { outerHTML: '
Original
' }, }); }); afterEach(() => rmSync(tmp, { recursive: true, force: true })); it('atomically publishes an artifact that matches the fenced source revision', () => { const before = readFileSync(source, 'utf-8'); writeFileSync(artifact, '
Original
Variant
'); const result = publishGenerationArtifact({ id: 'abc12345', epoch: 1, sourceFile: source, artifactFile: artifact, expectedSourceHash: sha256(before), expectedVariants: 3, cwd: tmp, }); assert.equal(result.ok, true); assert.equal(result.arrivedVariants, 1); assert.equal(readFileSync(source, 'utf-8'), readFileSync(artifact, 'utf-8')); const snapshot = store.getSnapshot('abc12345'); assert.equal(snapshot.phase, 'variants_progress'); assert.equal(snapshot.publishedRevision, 1); assert.equal(snapshot.deliveredVariants['1'].digest, result.digest); }); it('prepares a revision artifact with the current epoch and source fence', () => { const result = prepareGenerationArtifact({ id: 'abc12345', sourceFile: source, cwd: tmp }); assert.equal(result.ok, true); assert.equal(result.epoch, 1); assert.equal(result.revision, 1); assert.equal(result.expectedSourceHash, sha256(readFileSync(source, 'utf-8'))); assert.equal(readFileSync(join(tmp, result.artifactFile), 'utf-8'), readFileSync(source, 'utf-8')); }); it('rejects a late publication after early accept without touching source', () => { const before = readFileSync(source, 'utf-8'); writeFileSync(artifact, '
Late
'); store.appendEvent({ type: 'accept', id: 'abc12345', variantId: '1' }); const result = publishGenerationArtifact({ id: 'abc12345', epoch: 1, sourceFile: source, artifactFile: artifact, expectedSourceHash: sha256(before), cwd: tmp, }); assert.deepEqual(result, { ok: false, error: 'stale_generation_epoch', canceled: true, phase: 'accept_requested', }); assert.equal(readFileSync(source, 'utf-8'), before); }); it('rejects a stale artifact when source changed after the worker snapshot', () => { const before = readFileSync(source, 'utf-8'); writeFileSync(artifact, '
Variant
'); writeFileSync(source, before.replace('Original', 'Changed')); const result = publishGenerationArtifact({ id: 'abc12345', epoch: 1, sourceFile: source, artifactFile: artifact, expectedSourceHash: sha256(before), cwd: tmp, }); assert.equal(result.ok, false); assert.equal(result.error, 'source_hash_mismatch'); assert.match(readFileSync(source, 'utf-8'), /Changed/); }); it('keeps an already reviewable source variant immutable across revisions', () => { const firstSource = '
Original
First
'; writeFileSync(artifact, firstSource); const first = publishGenerationArtifact({ id: 'abc12345', epoch: 1, sourceFile: source, artifactFile: artifact, expectedSourceHash: sha256(readFileSync(source, 'utf-8')), arrivedVariants: 1, expectedVariants: 3, cwd: tmp, }); assert.equal(first.ok, true); const prepared = prepareGenerationArtifact({ id: 'abc12345', sourceFile: source, cwd: tmp }); const changed = firstSource.replace('First', 'Silently changed') .replace('', '
Second
'); writeFileSync(join(tmp, prepared.artifactFile), changed); const result = publishGenerationArtifact({ id: 'abc12345', epoch: prepared.epoch, sourceFile: source, artifactFile: prepared.artifactFile, expectedSourceHash: prepared.expectedSourceHash, arrivedVariants: 2, expectedVariants: 3, cwd: tmp, }); assert.equal(result.ok, false); assert.equal(result.error, 'published_variant_changed'); assert.equal(result.variant, 1); assert.equal(readFileSync(source, 'utf-8'), firstSource); }); it('rejects later source revisions that restyle an already reviewable variant', () => { const firstSource = '
Original

First

'; writeFileSync(artifact, firstSource); const first = publishGenerationArtifact({ id: 'abc12345', epoch: 1, sourceFile: source, artifactFile: artifact, expectedSourceHash: sha256(readFileSync(source, 'utf-8')), arrivedVariants: 1, expectedVariants: 3, cwd: tmp, }); assert.equal(first.ok, true); const prepared = prepareGenerationArtifact({ id: 'abc12345', sourceFile: source, cwd: tmp }); const changed = firstSource.replace('color: red', 'color: blue'); writeFileSync(join(tmp, prepared.artifactFile), changed); const result = publishGenerationArtifact({ id: 'abc12345', epoch: prepared.epoch, sourceFile: source, artifactFile: prepared.artifactFile, expectedSourceHash: prepared.expectedSourceHash, arrivedVariants: 1, expectedVariants: 3, cwd: tmp, }); assert.equal(result.ok, false); assert.equal(result.error, 'published_variant_css_changed', JSON.stringify(result)); assert.equal(readFileSync(source, 'utf-8'), firstSource); }); }); describe('transactional Svelte component publisher', () => { let tmp; let source; let manifestPath; let componentDir; let store; beforeEach(() => { tmp = mkdtempSync(join(tmpdir(), 'impeccable-svelte-publisher-')); source = join(tmp, 'src', 'routes', '+page.svelte'); componentDir = join(tmp, 'node_modules', '.impeccable-live', 'svelte123'); manifestPath = join(componentDir, 'manifest.json'); mkdirSync(join(tmp, 'src', 'routes'), { recursive: true }); mkdirSync(componentDir, { recursive: true }); writeFileSync(source, '

{title}

\n'); writeFileSync(manifestPath, JSON.stringify({ id: 'svelte123', previewMode: 'svelte-component', sourceFile: 'src/routes/+page.svelte', sourceStartLine: 1, sourceEndLine: 1, count: 3, propContract: [{ prop: 'title', expr: 'title', placeholder: '{title}' }], originalMarkup: '

{title}

', componentDir: 'node_modules/.impeccable-live/svelte123', runtimeModule: '/node_modules/.impeccable-live/__runtime.js', }, null, 2) + '\n'); for (let variant = 1; variant <= 3; variant++) { writeFileSync(join(componentDir, `v${variant}.svelte`), `
Stub ${variant}
\n`); } store = createLiveSessionStore({ cwd: tmp, sessionId: 'svelte123' }); store.appendEvent({ type: 'generate', id: 'svelte123', generationEpoch: 1, action: 'polish', count: 3, element: { outerHTML: '

Original

' }, }); }); afterEach(() => rmSync(tmp, { recursive: true, force: true })); it('prepares an isolated component directory fenced against the real route', () => { const result = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); assert.equal(result.ok, true); assert.equal(result.previewMode, 'svelte-component'); assert.equal(result.sourceFile, 'node_modules/.impeccable-live/svelte123/manifest.json'); assert.equal(result.targetSourceFile, 'src/routes/+page.svelte'); assert.equal(result.expectedSourceHash, sha256(readFileSync(source, 'utf-8'))); const artifactManifest = JSON.parse(readFileSync(join(tmp, result.artifactFile), 'utf-8')); assert.equal(artifactManifest.componentDir, result.componentDir); assert.equal(readFileSync(join(tmp, result.componentDir, 'v1.svelte'), 'utf-8'), '
Stub 1
\n'); writeFileSync(join(tmp, result.componentDir, 'v1.svelte'), '
Prepared only
\n'); assert.equal(readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'), '
Stub 1
\n'); }); it('publishes components before committing the arrived manifest and journals preview metadata', () => { const prepared = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); const artifactManifestPath = join(tmp, prepared.artifactFile); const artifactManifest = JSON.parse(readFileSync(artifactManifestPath, 'utf-8')); artifactManifest.arrivedVariants = 1; writeFileSync(artifactManifestPath, JSON.stringify(artifactManifest, null, 2) + '\n'); writeFileSync(join(tmp, prepared.componentDir, 'v1.svelte'), '
First live variant
\n'); const result = publishGenerationArtifact({ id: 'svelte123', epoch: prepared.epoch, sourceFile: manifestPath, artifactFile: artifactManifestPath, expectedSourceHash: prepared.expectedSourceHash, arrivedVariants: 1, expectedVariants: 3, cwd: tmp, }); assert.equal(result.ok, true); assert.equal(result.previewMode, 'svelte-component'); assert.equal(result.sourceFile, 'src/routes/+page.svelte'); assert.equal(result.previewFile, 'node_modules/.impeccable-live/svelte123/manifest.json'); assert.equal(readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'), '
First live variant
\n'); assert.equal(readFileSync(source, 'utf-8'), '

{title}

\n'); const liveManifest = JSON.parse(readFileSync(manifestPath, 'utf-8')); assert.equal(liveManifest.arrivedVariants, 1); assert.equal(liveManifest.componentDir, 'node_modules/.impeccable-live/svelte123'); const snapshot = store.getSnapshot('svelte123'); assert.equal(snapshot.arrivedVariants, 1); assert.equal(snapshot.previewMode, 'svelte-component'); assert.equal(snapshot.previewFile, 'node_modules/.impeccable-live/svelte123/manifest.json'); }); it('keeps published variants immutable across later revisions', () => { const first = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); publishSveltePrepared(first, { arrived: 1, edits: { 1: '
First live variant
\n' } }); const second = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); const before = readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'); const result = publishSveltePrepared(second, { arrived: 2, edits: { 1: '
Silently changed first variant
\n', 2: '
Second live variant
\n', }, }); assert.equal(result.ok, false); assert.equal(result.error, 'published_variant_changed'); assert.equal(result.variant, 1); assert.equal(readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'), before); assert.equal(JSON.parse(readFileSync(manifestPath, 'utf-8')).arrivedVariants, 1); }); it('publishes later variants and params without rewriting an already reviewable variant', () => { const first = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); publishSveltePrepared(first, { arrived: 1, edits: { 1: '
First live variant
\n' } }); const second = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); writeFileSync(join(tmp, second.componentDir, 'params.json'), '{"2":[{"id":"density"}]}\n'); const result = publishSveltePrepared(second, { arrived: 3, edits: { 2: '
Second live variant
\n', 3: '
Third live variant
\n', }, }); assert.equal(result.ok, true); assert.equal(result.arrivedVariants, 3); assert.equal(readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'), '
First live variant
\n'); assert.equal(readFileSync(join(componentDir, 'v2.svelte'), 'utf-8'), '
Second live variant
\n'); assert.equal(existsSync(join(componentDir, 'params.json')), true); assert.deepEqual(JSON.parse(readFileSync(join(componentDir, 'params.json'), 'utf-8')), { 2: [{ id: 'density' }], }); }); it('rejects a prepared Svelte publication after Accept without touching live artifacts', () => { const prepared = prepareGenerationArtifact({ id: 'svelte123', sourceFile: manifestPath, cwd: tmp }); const beforeManifest = readFileSync(manifestPath, 'utf-8'); const beforeVariant = readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'); store.appendEvent({ type: 'accept', id: 'svelte123', variantId: '1' }); const result = publishSveltePrepared(prepared, { arrived: 1, edits: { 1: '
Too late
\n' }, }); assert.equal(result.ok, false); assert.equal(result.error, 'stale_generation_epoch'); assert.equal(readFileSync(manifestPath, 'utf-8'), beforeManifest); assert.equal(readFileSync(join(componentDir, 'v1.svelte'), 'utf-8'), beforeVariant); }); it('rejects a live component directory masquerading as a staged artifact', () => { const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')); manifest.arrivedVariants = 1; writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n'); const result = publishGenerationArtifact({ id: 'svelte123', epoch: 1, sourceFile: manifestPath, artifactFile: manifestPath, expectedSourceHash: sha256(readFileSync(source, 'utf-8')), arrivedVariants: 1, expectedVariants: 3, cwd: tmp, }); assert.equal(result.ok, false); assert.equal(result.error, 'artifact_not_staged'); }); function publishSveltePrepared(prepared, { arrived, edits }) { const artifactManifestPath = join(tmp, prepared.artifactFile); const artifactManifest = JSON.parse(readFileSync(artifactManifestPath, 'utf-8')); artifactManifest.arrivedVariants = arrived; writeFileSync(artifactManifestPath, JSON.stringify(artifactManifest, null, 2) + '\n'); for (const [variant, content] of Object.entries(edits)) { writeFileSync(join(tmp, prepared.componentDir, `v${variant}.svelte`), content); } return publishGenerationArtifact({ id: 'svelte123', epoch: prepared.epoch, sourceFile: manifestPath, artifactFile: artifactManifestPath, expectedSourceHash: prepared.expectedSourceHash, arrivedVariants: arrived, expectedVariants: 3, cwd: tmp, }); } });