feat(session-persistence): readFrom(seq) primitive for watermark tail reads
SessionPersistence grows readFrom(id, fromSeq, signal?): the non-mutating read-from-seq primitive for checkpoint consumers (the persisted projection cache folds only the tail past its watermark). Coordinator owns validation, per-id serialization, and the sequential fallback (loadStored + forward skip); SQLite implements the optional seek-capable loadStoredFrom hook (WHERE seq >= ?), JSONL stays sequential by contract. Contract suite covers suffix exactness, empty-tail, non-mutation, and cancellation; seam README (both languages) documents the method and the hook.
This commit is contained in:
@@ -149,6 +149,11 @@ class TestPersistence extends SessionPersistence {
|
||||
return structuredClone(entry)
|
||||
}
|
||||
|
||||
async readFrom(id: SessionIdType, fromSeq: number, signal?: AbortSignal): Promise<{ meta: SessionHeader; events: SessionEvent[] }> {
|
||||
const whole = await this.inspect(id, signal)
|
||||
return { meta: whole.meta, events: whole.events.filter(event => event.seq >= fromSeq) }
|
||||
}
|
||||
|
||||
async list(): Promise<SessionHeader[]> {
|
||||
TestPersistence.listStarted?.()
|
||||
await TestPersistence.listGate
|
||||
|
||||
@@ -96,6 +96,11 @@ class TestPersistence extends SessionPersistence {
|
||||
return Promise.resolve(result)
|
||||
}
|
||||
|
||||
async readFrom(id: SessionIdType, fromSeq: number, signal?: AbortSignal): Promise<{ meta: SessionHeader; events: SessionEvent[] }> {
|
||||
const whole = await this.inspect(id, signal)
|
||||
return { meta: whole.meta, events: whole.events.filter(event => event.seq >= fromSeq) }
|
||||
}
|
||||
|
||||
list(signal?: AbortSignal): Promise<SessionHeader[]> {
|
||||
TestPersistence.listCalls += 1
|
||||
TestPersistence.listSignals.push(signal)
|
||||
|
||||
@@ -76,6 +76,11 @@ class TracePersistence extends SessionPersistence {
|
||||
return Promise.resolve(structuredClone(entry))
|
||||
}
|
||||
|
||||
async readFrom(id: SessionIdType, fromSeq: number): Promise<{ meta: SessionHeader; events: SessionEvent[] }> {
|
||||
const whole = await this.inspect(id)
|
||||
return { meta: whole.meta, events: whole.events.filter(event => event.seq >= fromSeq) }
|
||||
}
|
||||
|
||||
list(): Promise<SessionHeader[]> {
|
||||
TracePersistence.listCalls += 1
|
||||
if (TracePersistence.listFailure !== undefined) return Promise.reject(TracePersistence.listFailure)
|
||||
|
||||
Reference in New Issue
Block a user