diff --git a/packages/session/session-persistence/src/coordinator.ts b/packages/session/session-persistence/src/coordinator.ts index eb5f9714c4..5bb182b925 100644 --- a/packages/session/session-persistence/src/coordinator.ts +++ b/packages/session/session-persistence/src/coordinator.ts @@ -1170,7 +1170,7 @@ export class PersistenceCoordinator { this.live.set(session, restored) return restored } - const seed = session.events.map(e => structuredClone(e)) + const seed = session.events const live: LiveSessionState = { init: Promise.resolve(), writes: this.createWriteBehind(session, () => live.init), diff --git a/packages/session/session-persistence/tests/persistence.spec.ts b/packages/session/session-persistence/tests/persistence.spec.ts index 50ad798e04..1e66fec709 100644 --- a/packages/session/session-persistence/tests/persistence.spec.ts +++ b/packages/session/session-persistence/tests/persistence.spec.ts @@ -180,6 +180,7 @@ class ControlledBackend implements PersistenceBackend { readonly name = 'session-persistence-controlled' readonly store: MemoryStore = new Map() readonly lifecycle: string[] = [] + lastAppendedBatch: readonly SessionEvent[] | undefined appendAttempts = 0 loadAttempts = 0 repairAttempts = 0 @@ -212,6 +213,7 @@ class ControlledBackend implements PersistenceBackend { } async appendBatch(m: SessionHeader, events: readonly SessionEvent[], _isMaterialized: boolean): Promise { + this.lastAppendedBatch = events const attempt = ++this.appendAttempts await this.beforeAppend?.(attempt) const entry = this.store.get(m.id) @@ -280,6 +282,26 @@ runCoordinatorContract('memory', async (): Promise => { }) describe('PersistenceCoordinator bounded writes', () => { + it('retains the immutable session seed without cloning it', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + const backend = new ControlledBackend() + const fiber = await ctx.plugin(Object.assign((inner: Context) => { + new PersistenceCoordinator(inner, backend) + }, { inject: ['sessions'] })) + + try { + const session = ctx.sessions.create(SessionId('shared-seed'), { seed: oneTurnLog() }) + const seed = session.events + await ctx.sessions.flush(session) + + expect(backend.lastAppendedBatch).toBe(seed) + } finally { + await fiber.dispose() + await ctx.fiber.dispose() + } + }) + it('cancels the batching deadline when live initialization rejects', async () => { vi.useFakeTimers() const ctx = new Context()