Improve Live progressive responsiveness

Add transactional progressive publication, durable cancellation, responsive accept cleanup, and framework-safe Svelte and Nuxt previews.\n\nAI-assisted: OpenAI Codex.
This commit is contained in:
Paul Bakaus
2026-07-12 17:54:50 -07:00
parent ff67ad359e
commit 2106a2881f
40 changed files with 3833 additions and 206 deletions
+84 -2
View File
@@ -3,6 +3,13 @@ import path from 'node:path';
import { getLegacyLiveSessionsDir, getLiveSessionsDir } from '../lib/impeccable-paths.mjs';
const COMPLETED_PHASES = new Set(['completed', 'discarded']);
const GENERATION_FENCED_PHASES = new Set([
'accept_requested',
'discard_requested',
'carbonize_required',
'completed',
'discarded',
]);
export function createLiveSessionStore({ cwd = process.cwd(), sessionId } = {}) {
const rootDir = getLiveSessionsDir(cwd);
@@ -38,7 +45,10 @@ export function createLiveSessionStore({ cwd = process.cwd(), sessionId } = {})
if (!fs.existsSync(journalPath) && fs.existsSync(legacyJournalPath)) {
fs.copyFileSync(legacyJournalPath, journalPath);
}
const prior = loadCachedOrRebuild(normalized.id);
// Publisher/complete helpers can append from a separate process while
// the server is alive. Rebuild here so sequence numbers and phase
// fences never come from a stale in-memory cache.
const prior = rebuildSnapshotFromJournal(getReadableJournalPath(normalized.id), normalized.id);
const seq = prior.nextSeq;
const entry = {
seq,
@@ -119,6 +129,14 @@ function baseSnapshot(id) {
activeOwner: null,
sourceMarkers: {},
fallbackMode: null,
generationPhase: null,
generationTimings: {},
generationEpoch: 1,
publishedRevision: 0,
deliveredVariants: {},
generationCanceled: false,
generationCanceledAt: null,
cancelReason: null,
annotationArtifacts: [],
diagnostics: [],
updatedAt: null,
@@ -158,6 +176,8 @@ function applyEvent(snapshot, entry, inheritedDiagnostics = []) {
...snapshot,
paramValues: { ...(snapshot.paramValues || {}) },
sourceMarkers: { ...(snapshot.sourceMarkers || {}) },
generationTimings: { ...(snapshot.generationTimings || {}) },
deliveredVariants: { ...(snapshot.deliveredVariants || {}) },
annotationArtifacts: [...(snapshot.annotationArtifacts || [])],
diagnostics: [...(snapshot.diagnostics || [])],
updatedAt: entry.ts || new Date().toISOString(),
@@ -170,14 +190,66 @@ function applyEvent(snapshot, entry, inheritedDiagnostics = []) {
switch (event.type) {
case 'generate':
next.phase = 'generate_requested';
next.generationEpoch = Number(event.generationEpoch || next.generationEpoch || 1);
next.pageUrl = event.pageUrl ?? next.pageUrl;
next.expectedVariants = event.count ?? next.expectedVariants;
next.pendingEventSeq = entry.seq ?? next.pendingEventSeq;
next.pendingEvent = toPendingEvent(event);
if (event.screenshotPath) upsertArtifact(next.annotationArtifacts, { type: 'screenshot', path: event.screenshotPath });
break;
case 'variant_published':
if (next.generationCanceled || GENERATION_FENCED_PHASES.has(next.phase)) {
next.diagnostics.push({
error: 'late_generation_event_ignored',
type: event.type,
phase: next.phase,
revision: event.revision ?? null,
});
break;
}
if (Number(event.generationEpoch || 0) !== Number(next.generationEpoch || 1)) {
next.diagnostics.push({
error: 'stale_generation_epoch_ignored',
epoch: event.generationEpoch ?? null,
expectedEpoch: next.generationEpoch || 1,
});
break;
}
next.phase = 'variants_progress';
next.publishedRevision = Math.max(next.publishedRevision || 0, Number(event.revision || 0));
next.arrivedVariants = Math.max(next.arrivedVariants || 0, Number(event.arrivedVariants || 0));
next.expectedVariants = Number(event.expectedVariants || next.expectedVariants || 0);
next.sourceFile = event.sourceFile ?? next.sourceFile;
next.previewFile = event.previewFile ?? next.previewFile;
next.previewMode = event.previewMode ?? next.previewMode;
if (event.revision) {
next.deliveredVariants[String(event.revision)] = {
digest: event.digest || null,
arrivedVariants: Number(event.arrivedVariants || 0),
publishedAt: event.at || null,
};
}
break;
case 'agent_phase':
next.generationPhase = event.phase ?? next.generationPhase;
if (event.phase) {
next.generationTimings[event.phase] = {
at: event.at ?? (Date.parse(entry.ts || '') || null),
durationMs: event.durationMs ?? null,
};
}
break;
case 'variants_ready':
case 'agent_done':
if ((next.generationCanceled || GENERATION_FENCED_PHASES.has(next.phase))
&& !(event.type === 'agent_done' && event.carbonize === true && next.phase === 'accept_requested')) {
next.diagnostics.push({
error: 'late_generation_event_ignored',
type: event.type,
phase: next.phase,
});
break;
}
next.phase = event.carbonize === true ? 'carbonize_required' : 'variants_ready';
next.sourceFile = event.sourceFile ?? event.file ?? next.sourceFile;
next.previewFile = event.previewFile ?? next.previewFile;
@@ -194,7 +266,7 @@ function applyEvent(snapshot, entry, inheritedDiagnostics = []) {
}
break;
case 'checkpoint':
if (COMPLETED_PHASES.has(next.phase)) {
if (next.generationCanceled || GENERATION_FENCED_PHASES.has(next.phase)) {
next.diagnostics.push({ error: 'checkpoint_after_terminal_ignored', phase: event.phase ?? null, revision: event.revision ?? null });
break;
}
@@ -215,6 +287,9 @@ function applyEvent(snapshot, entry, inheritedDiagnostics = []) {
case 'accept':
case 'accept_intent':
next.phase = 'accept_requested';
next.generationCanceled = true;
next.generationCanceledAt = event.at ?? (Date.parse(entry.ts || '') || Date.now());
next.cancelReason = 'accept';
next.visibleVariant = Number(event.variantId ?? next.visibleVariant);
if (event.paramValues) next.paramValues = { ...event.paramValues };
next.pendingEventSeq = entry.seq ?? next.pendingEventSeq;
@@ -243,6 +318,9 @@ function applyEvent(snapshot, entry, inheritedDiagnostics = []) {
break;
case 'discard':
next.phase = 'discard_requested';
next.generationCanceled = true;
next.generationCanceledAt = event.at ?? (Date.parse(entry.ts || '') || Date.now());
next.cancelReason = 'discard';
next.pendingEventSeq = entry.seq ?? next.pendingEventSeq;
next.pendingEvent = toPendingEvent(event);
break;
@@ -260,6 +338,10 @@ function applyEvent(snapshot, entry, inheritedDiagnostics = []) {
next.pendingEvent = null;
break;
case 'agent_error':
if (next.generationCanceled && event.sourceEventType === 'generate') {
next.diagnostics.push({ error: 'late_generation_event_ignored', type: event.type, phase: next.phase });
break;
}
next.phase = 'agent_error';
next.pendingEventSeq = null;
next.pendingEvent = null;