@iworkforces/tracelattice 2.3.6 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/dist/ServerConfig.d.ts +16 -0
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js +11 -0
- package/dist/ServerConfig.js.map +1 -1
- package/dist/cli.js +234 -18
- package/dist/cli.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +2 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +2 -0
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +26 -0
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/persistence-backlog.d.ts +21 -0
- package/dist/contracts/persistence-backlog.d.ts.map +1 -0
- package/dist/contracts/persistence-backlog.js +1 -0
- package/dist/core/HistoryManager.d.ts +15 -1
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +12 -2
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +2 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +25 -0
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +27 -5
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceBufferErrors.d.ts +10 -0
- package/dist/core/PersistenceBufferErrors.d.ts.map +1 -1
- package/dist/core/PersistenceBufferErrors.js +13 -1
- package/dist/core/PersistenceBufferErrors.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +25 -30
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWorkQueue.d.ts +9 -0
- package/dist/core/PersistenceWorkQueue.d.ts.map +1 -1
- package/dist/core/PersistenceWorkQueue.js +18 -0
- package/dist/core/PersistenceWorkQueue.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +6 -0
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +15 -1
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +3 -10
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/evaluator/VerificationLinks.d.ts +5 -0
- package/dist/core/evaluator/VerificationLinks.d.ts.map +1 -1
- package/dist/core/evaluator/VerificationLinks.js +47 -53
- package/dist/core/evaluator/VerificationLinks.js.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.js +4 -3
- package/dist/core/reasoning/ActiveEvidenceProjection.js.map +1 -1
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/health/HealthChecker.d.ts +42 -1
- package/dist/health/HealthChecker.d.ts.map +1 -1
- package/dist/health/HealthChecker.js +60 -8
- package/dist/health/HealthChecker.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/metrics/metrics.impl.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +2 -1
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +6 -1
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -0
- package/dist/persistence/FileSnapshotV2.d.ts.map +1 -1
- package/dist/persistence/FileSnapshotV2.js +39 -1
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +4 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +30 -0
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +6 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +31 -4
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +12 -0
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +19 -5
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/PersistenceBuffer.js","sources":["../../src/core/PersistenceBuffer.ts"],"sourcesContent":["/**\n * Joinable coordinator for attributable persistence work.\n *\n * @module PersistenceBuffer\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nimport type { PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport type { BranchId, SessionId, ThoughtId } from '../contracts/ids.js';\nimport type { PersistenceWork, PersistenceWorkToken } from '../contracts/persistence-work.js';\nimport {\n\tPersistenceDrainError,\n\tPersistenceSessionAdmissionClosedError,\n\tPersistenceSessionBarrierReentrancyError,\n} from './PersistenceBufferErrors.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { assertNever } from '../utils.js';\nimport type { Summary } from './compression/Summary.js';\nimport type { DurableIdentitySession } from './DurableThoughtIdentityIndex.js';\nimport type { Edge } from './graph/Edge.js';\nimport { PersistenceWorkQueue, type PersistenceSelectionMode } from './PersistenceWorkQueue.js';\nimport { PersistenceWriter, type PersistenceDelay } from './PersistenceWriter.js';\nimport type { ThoughtData } from './thought.js';\n\n/** Event emitter contract for persistence error events. */\nexport interface PersistenceEventEmitter {\n\temit(event: 'persistenceError', payload: { operation: string; error: Error }): boolean;\n}\n\n/** Observable persistence state relevant to safe in-memory session eviction. */\nexport type SessionEvictionState = 'quiescent' | 'pending' | 'failed' | 'barrier';\n\n/** Configuration options for {@link PersistenceBuffer}. */\nexport interface PersistenceBufferConfig {\n\treadonly persistence: PersistenceBackend;\n\treadonly bufferSize: number;\n\treadonly flushInterval: number;\n\treadonly maxRetries: number;\n\t/** Optional emitter for `persistenceError` events. */\n\treadonly eventEmitter?: PersistenceEventEmitter | null;\n\treadonly logger?: Logger;\n\t/** Optional retry scheduler for deterministic coordination and testing. */\n\treadonly delay?: PersistenceDelay;\n\treadonly durableHistorySize?: number;\n\treadonly persistBranches?: boolean;\n}\n\ntype ActiveDrain = {\n\treadonly promise: Promise<void>;\n\treadonly resolve: () => void;\n\treadonly reject: (reason: unknown) => void;\n\treadonly selectedTokens: Set<PersistenceWorkToken>;\n\tmode: PersistenceSelectionMode;\n\tbackgroundObserved: boolean;\n\tinFlightWork: PersistenceWork | null;\n\tsettlement: DrainSettlement | null;\n};\n\ntype SessionBarrierState = {\n\ttail: Promise<void>;\n\tpendingOwners: number;\n};\n\ntype DrainTermination =\n\t{ readonly kind: 'result' } | { readonly kind: 'fault'; readonly fault: unknown };\n\ntype DrainSettlement =\n\t{ readonly kind: 'resolved' } | { readonly kind: 'rejected'; readonly reason: unknown };\n\ntype SessionQuiescence =\n\t| { readonly kind: 'pending' }\n\t| { readonly kind: 'resolved' }\n\t| { readonly kind: 'rejected'; readonly reason: unknown };\n\n/**\n * Coordinates one globally joinable persistence generation at a time.\n *\n * Accepted work is owned by a queue independent of live session state. Explicit\n * callers can join and upgrade a background generation without starting another writer.\n */\nexport class PersistenceBuffer {\n\tprivate readonly _bufferSize: number;\n\tprivate readonly _flushInterval: number;\n\tprivate readonly _queue: PersistenceWorkQueue;\n\tprivate readonly _writer: PersistenceWriter;\n\tprivate _eventEmitter: PersistenceEventEmitter | null;\n\tprivate readonly _logger: Logger;\n\n\tprivate _flushTimer: ReturnType<typeof setInterval> | null = null;\n\tprivate _activeDrain: ActiveDrain | null = null;\n\tprivate readonly _sessionBarriers = new Map<SessionId, SessionBarrierState>();\n\tprivate readonly _sessionBarrierOwnership = new AsyncLocalStorage<ReadonlySet<SessionId>>();\n\tprivate readonly _sessionProgressWaiters = new Map<SessionId, Set<() => void>>();\n\tprivate readonly _quarantinedSessions = new Set<SessionId>();\n\tprivate readonly _evictionQuarantinedSessions = new Set<SessionId>();\n\tprivate _globalResetTail: Promise<void> = Promise.resolve();\n\tprivate _globalResetOwners = 0;\n\tprivate _globalQuarantined = false;\n\n\t/**\n\t * Creates a persistence-drain coordinator.\n\t *\n\t * @param config - Persistence dependencies, trigger thresholds, and retry policy.\n\t */\n\tpublic constructor(config: PersistenceBufferConfig) {\n\t\tthis._queue = new PersistenceWorkQueue(config.durableHistorySize, config.persistBranches);\n\t\tthis._bufferSize = config.bufferSize;\n\t\tthis._flushInterval = config.flushInterval;\n\t\tthis._eventEmitter = config.eventEmitter ?? null;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t\tthis._writer = new PersistenceWriter({\n\t\t\tpersistence: config.persistence,\n\t\t\tmaxRetries: config.maxRetries,\n\t\t\tdelay: config.delay,\n\t\t});\n\t}\n\n\t/** @returns The underlying flush timer for lifecycle introspection. */\n\tpublic get timer(): ReturnType<typeof setInterval> | null {\n\t\treturn this._flushTimer;\n\t}\n\n\t/** @returns Whether a global drain generation is active. */\n\tpublic get isFlushing(): boolean {\n\t\treturn this._activeDrain !== null;\n\t}\n\n\t/** @returns Number of accepted thought writes not yet acknowledged successful. */\n\tpublic get pendingThoughtCount(): number {\n\t\treturn this._queue.pendingThoughtCount;\n\t}\n\n\tpublic hasThoughtIdentity(sessionId: SessionId, thoughtId: ThoughtId): boolean {\n\t\treturn this._queue.hasThoughtIdentity(sessionId, thoughtId);\n\t}\n\n\tpublic replaceDurableThoughtIdentities(sessions: readonly DurableIdentitySession[]): void {\n\t\tthis._queue.replaceDurableThoughtIdentities(sessions);\n\t}\n\n\t/**\n\t * Sets or clears the persistence error event emitter.\n\t *\n\t * @param emitter - Replacement emitter, or `null` to disable events.\n\t */\n\tpublic setEventEmitter(emitter: PersistenceEventEmitter | null): void {\n\t\tthis._eventEmitter = emitter;\n\t}\n\n\t/**\n\t * Accepts a thought with authoritative session attribution.\n\t *\n\t * @param sessionId - Session that owns the accepted thought.\n\t * @param thought - Thought to persist.\n\t */\n\tpublic bufferThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tif (this._queue.pendingThoughtCount >= this._bufferSize && this.isFlushing) {\n\t\t\tthis._logger.info('Write buffer full and flush in progress, applying backpressure', {\n\t\t\t\tbufferSize: this._queue.pendingThoughtCount,\n\t\t\t\tmaxSize: this._bufferSize,\n\t\t\t});\n\t\t}\n\n\t\tthis._queue.enqueueThought(sessionId, thought);\n\t\tif (this._queue.pendingThoughtCount >= this._bufferSize) this._triggerBackgroundDrain();\n\t}\n\n\tpublic bufferBacktrack(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.enqueueBacktrack(sessionId, thought, targetThoughtId);\n\t\tif (this._queue.pendingThoughtCount >= this._bufferSize) this._triggerBackgroundDrain();\n\t}\n\n\t/**\n\t * Accepts the latest snapshot for one session-owned branch.\n\t *\n\t * @param sessionId - Session that owns the branch.\n\t * @param branchId - Stable branch coordinate.\n\t * @param thoughts - Branch snapshot copied by the queue.\n\t */\n\tpublic bufferBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.replaceBranch(sessionId, branchId, thoughts);\n\t}\n\n\t/**\n\t * @param sessionId - Session that owns the branch.\n\t * @param branchId - Stable branch coordinate to delete.\n\t */\n\tpublic deleteBranch(sessionId: SessionId, branchId: BranchId): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.deleteBranch(sessionId, branchId);\n\t}\n\n\t/**\n\t * Accepts the latest edge snapshot for one session.\n\t *\n\t * @param sessionId - Session that owns the edges.\n\t * @param edges - Edge snapshot copied by the queue.\n\t */\n\tpublic bufferEdges(sessionId: SessionId, edges: readonly Edge[]): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.replaceEdges(sessionId, edges);\n\t}\n\n\t/**\n\t * Accepts the latest summary snapshot for one session.\n\t *\n\t * @param sessionId - Session that owns the summaries.\n\t * @param summaries - Summary snapshot copied by the queue.\n\t */\n\tpublic bufferSummaries(sessionId: SessionId, summaries: readonly Summary[]): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.replaceSummaries(sessionId, summaries);\n\t}\n\n\t/** Rejects synchronously when lifecycle coordination has closed persistence admission. */\n\tpublic assertSessionAdmissionOpen(sessionId: SessionId): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t}\n\n\t/** Starts the periodic background-drain timer without keeping the process alive. */\n\tpublic startFlushTimer(): void {\n\t\tif (this._flushTimer !== null) return;\n\t\tthis._flushTimer = setInterval(() => this._triggerBackgroundDrain(), this._flushInterval);\n\t\tif (typeof this._flushTimer === 'object' && 'unref' in this._flushTimer) {\n\t\t\tthis._flushTimer.unref();\n\t\t}\n\t}\n\n\t/** Stops the periodic background-drain timer. */\n\tpublic stopFlushTimer(): void {\n\t\tif (this._flushTimer === null) return;\n\t\tclearInterval(this._flushTimer);\n\t\tthis._flushTimer = null;\n\t}\n\n\t/**\n\t * Starts or joins an explicit global drain generation.\n\t *\n\t * @returns The exact shared promise for the active generation.\n\t */\n\tpublic drain(): Promise<void> {\n\t\treturn this._joinOrStart('explicit').promise;\n\t}\n\n\t/** @returns The exact same promise as {@link drain} for the active generation. */\n\tpublic flush(): Promise<void> {\n\t\treturn this.drain();\n\t}\n\n\t/**\n\t * Joins the global explicit generation and projects its terminal failures to one session.\n\t * This method does not close admission; lifecycle owners must use\n\t * {@link withSessionBarrier} when work must not cross an owner callback.\n\t *\n\t * @param sessionId - Session whose accepted writes form the barrier projection.\n\t * @returns A promise that rejects only for that session's failures or an unknown fault.\n\t */\n\tpublic drainSession(sessionId: SessionId): Promise<void> {\n\t\tconst generation = this._joinOrStart('explicit');\n\t\treturn generation.promise.catch((reason: unknown) => {\n\t\t\tif (!(reason instanceof PersistenceDrainError)) throw reason;\n\t\t\tconst failures = reason.failures.filter((failure) => failure.sessionId === sessionId);\n\t\t\tif (failures.length > 0) throw new PersistenceDrainError(failures);\n\t\t});\n\t}\n\n\t/** Returns queue-derived persistence state for safe session eviction planning. */\n\tpublic sessionEvictionState(sessionId: SessionId): SessionEvictionState {\n\t\tif (this._globalResetOwners > 0 || this._sessionBarriers.has(sessionId)) return 'barrier';\n\t\tif (\n\t\t\tthis._globalQuarantined ||\n\t\t\tthis._queue.hasSessionTerminalFailure(sessionId) ||\n\t\t\tthis._quarantinedSessions.has(sessionId) ||\n\t\t\tthis._evictionQuarantinedSessions.has(sessionId)\n\t\t) {\n\t\t\treturn 'failed';\n\t\t}\n\t\treturn this._queue.hasSessionWork(sessionId) ? 'pending' : 'quiescent';\n\t}\n\n\t/**\n\t * Drains accepted session work before ordinary in-memory eviction cleanup.\n\t *\n\t * Unlike reset barriers, this operation never clears durable state or discards\n\t * accepted work. Failure retains admission quarantine until a later explicit\n\t * invocation successfully drains and completes cleanup.\n\t */\n\tpublic withSessionEvictionBarrier<T>(\n\t\tsessionId: SessionId,\n\t\toperation: () => Promise<T>\n\t): Promise<T> {\n\t\tif (\n\t\t\tthis._globalResetOwners > 0 ||\n\t\t\tthis._globalQuarantined ||\n\t\t\tthis._quarantinedSessions.has(sessionId)\n\t\t) {\n\t\t\treturn Promise.reject(new PersistenceSessionAdmissionClosedError(sessionId));\n\t\t}\n\t\tconst currentOwnership = this._sessionBarrierOwnership.getStore();\n\t\tif (currentOwnership?.has(sessionId) === true) {\n\t\t\treturn Promise.reject(new PersistenceSessionBarrierReentrancyError(sessionId));\n\t\t}\n\t\tconst operationOwnership = new Set(currentOwnership);\n\t\toperationOwnership.add(sessionId);\n\t\tconst state = this._sessionBarriers.get(sessionId) ?? {\n\t\t\ttail: Promise.resolve(),\n\t\t\tpendingOwners: 0,\n\t\t};\n\t\tthis._sessionBarriers.set(sessionId, state);\n\t\tstate.pendingOwners += 1;\n\n\t\tconst result = state.tail.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait this._awaitSessionQuiescence(sessionId);\n\t\t\t\tconst value = await this._sessionBarrierOwnership.run(operationOwnership, operation);\n\t\t\t\tthis._queue.forgetQuiescentSession(sessionId);\n\t\t\t\tthis._evictionQuarantinedSessions.delete(sessionId);\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tthis._evictionQuarantinedSessions.add(sessionId);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tstate.pendingOwners -= 1;\n\t\t\t\tif (state.pendingOwners === 0) this._sessionBarriers.delete(sessionId);\n\t\t\t}\n\t\t});\n\t\tstate.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** Forgets queue coordinates only when the session is fully quiescent. */\n\tpublic forgetQuiescentSession(sessionId: SessionId): boolean {\n\t\treturn this.sessionEvictionState(sessionId) === 'quiescent'\n\t\t\t? this._queue.forgetQuiescentSession(sessionId)\n\t\t\t: false;\n\t}\n\n\t/**\n\t * Runs one lifecycle operation while persistence admission is closed for a session.\n\t *\n\t * Admission closes synchronously when this method is called. Already accepted work for\n\t * the session is settled first; an exhausted session failure rejects without invoking\n\t * `operation`. Concurrent calls for the same session execute in FIFO call order and keep\n\t * admission closed until the final callback settles. Other sessions remain admissible and\n\t * may be owned by a nested callback. Reacquiring the same session from the owning callback's\n\t * async call chain rejects before joining the FIFO because awaiting it would deadlock its owner.\n\t *\n\t * @example\n\t * ```ts\n\t * await buffer.withSessionBarrier(sessionId, async () => {\n\t * await persistence.clearSession(sessionId);\n\t * });\n\t * ```\n\t *\n\t * @param sessionId - Session exclusively owned for the callback duration.\n\t * @param operation - Awaited lifecycle operation run only after prior work settles.\n\t * @returns The callback result after admission has reopened when no owner remains.\n\t * @throws {@link PersistenceSessionBarrierReentrancyError} when the owning async call chain\n\t * attempts to reacquire `sessionId`.\n\t */\n\tpublic withSessionBarrier<T>(sessionId: SessionId, operation: () => Promise<T>): Promise<T> {\n\t\tconst currentOwnership = this._sessionBarrierOwnership.getStore();\n\t\tif (currentOwnership?.has(sessionId) === true) {\n\t\t\treturn Promise.reject(new PersistenceSessionBarrierReentrancyError(sessionId));\n\t\t}\n\t\tconst operationOwnership = new Set(currentOwnership);\n\t\toperationOwnership.add(sessionId);\n\n\t\tconst state = this._sessionBarriers.get(sessionId) ?? {\n\t\t\ttail: Promise.resolve(),\n\t\t\tpendingOwners: 0,\n\t\t};\n\t\tthis._sessionBarriers.set(sessionId, state);\n\t\tstate.pendingOwners += 1;\n\n\t\tconst result = state.tail.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait this._awaitSessionQuiescence(sessionId);\n\t\t\t\treturn await this._sessionBarrierOwnership.run(operationOwnership, operation);\n\t\t\t} finally {\n\t\t\t\tstate.pendingOwners -= 1;\n\t\t\t\tif (state.pendingOwners === 0) this._sessionBarriers.delete(sessionId);\n\t\t\t}\n\t\t});\n\t\tstate.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Runs a scoped reset, retaining admission quarantine on failure.\n\t * A retry may pass retained write failures because successful durable deletion\n\t * invalidates those stale queue entries before admission reopens.\n\t */\n\tpublic withSessionResetBarrier<T>(sessionId: SessionId, operation: () => Promise<T>): Promise<T> {\n\t\tif (this._globalResetOwners > 0 || this._globalQuarantined) {\n\t\t\treturn Promise.reject(new PersistenceSessionAdmissionClosedError(sessionId));\n\t\t}\n\t\tconst currentOwnership = this._sessionBarrierOwnership.getStore();\n\t\tif (currentOwnership?.has(sessionId) === true) {\n\t\t\treturn Promise.reject(new PersistenceSessionBarrierReentrancyError(sessionId));\n\t\t}\n\t\tconst operationOwnership = new Set(currentOwnership);\n\t\toperationOwnership.add(sessionId);\n\t\tconst state = this._sessionBarriers.get(sessionId) ?? {\n\t\t\ttail: Promise.resolve(),\n\t\t\tpendingOwners: 0,\n\t\t};\n\t\tthis._sessionBarriers.set(sessionId, state);\n\t\tstate.pendingOwners += 1;\n\n\t\tconst result = state.tail.then(async () => {\n\t\t\ttry {\n\t\t\t\ttry {\n\t\t\t\t\tawait this._awaitSessionQuiescence(sessionId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!(error instanceof PersistenceDrainError)) throw error;\n\t\t\t\t}\n\t\t\t\tconst value = await this._sessionBarrierOwnership.run(operationOwnership, operation);\n\t\t\t\tthis._queue.discardSession(sessionId);\n\t\t\t\tthis._quarantinedSessions.delete(sessionId);\n\t\t\t\tthis._evictionQuarantinedSessions.delete(sessionId);\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tthis._quarantinedSessions.add(sessionId);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tstate.pendingOwners -= 1;\n\t\t\t\tif (state.pendingOwners === 0) this._sessionBarriers.delete(sessionId);\n\t\t\t}\n\t\t});\n\t\tstate.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** Runs a trusted global reset behind a global admission barrier. */\n\tpublic withGlobalResetBarrier<T>(operation: () => Promise<T>): Promise<T> {\n\t\tthis._globalResetOwners += 1;\n\t\tconst prior = this._globalResetTail;\n\t\tconst result = prior.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait Promise.all(Array.from(this._sessionBarriers.values(), (state) => state.tail));\n\t\t\t\ttry {\n\t\t\t\t\tawait this.drain();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!(error instanceof PersistenceDrainError)) throw error;\n\t\t\t\t}\n\t\t\t\tconst value = await operation();\n\t\t\t\tthis._queue.discardAll();\n\t\t\t\tthis._quarantinedSessions.clear();\n\t\t\t\tthis._evictionQuarantinedSessions.clear();\n\t\t\t\tthis._globalQuarantined = false;\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tthis._globalQuarantined = true;\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tthis._globalResetOwners -= 1;\n\t\t\t}\n\t\t});\n\t\tthis._globalResetTail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\tprivate _joinOrStart(mode: PersistenceSelectionMode): ActiveDrain {\n\t\tconst active = this._activeDrain;\n\t\tif (active !== null) {\n\t\t\tif (mode === 'explicit') active.mode = mode;\n\t\t\treturn active;\n\t\t}\n\n\t\tlet resolveGeneration = (): void => undefined;\n\t\tlet rejectGeneration = (_reason: unknown): void => undefined;\n\t\tconst promise = new Promise<void>((resolve, reject) => {\n\t\t\tresolveGeneration = resolve;\n\t\t\trejectGeneration = reject;\n\t\t});\n\t\tconst generation: ActiveDrain = {\n\t\t\tpromise,\n\t\t\tresolve: resolveGeneration,\n\t\t\treject: rejectGeneration,\n\t\t\tselectedTokens: new Set<PersistenceWorkToken>(),\n\t\t\tmode,\n\t\t\tbackgroundObserved: false,\n\t\t\tinFlightWork: null,\n\t\t\tsettlement: null,\n\t\t};\n\t\tthis._activeDrain = generation;\n\t\tvoid this._runDrain(generation).catch((fault: unknown) => {\n\t\t\tthis._closeGeneration(generation, { kind: 'fault', fault });\n\t\t});\n\t\treturn generation;\n\t}\n\n\tprivate _triggerBackgroundDrain(): void {\n\t\tconst generation = this._joinOrStart('background');\n\t\tif (generation.backgroundObserved) return;\n\t\tgeneration.backgroundObserved = true;\n\t\tvoid generation.promise.catch(() => undefined);\n\t}\n\n\tprivate async _runDrain(generation: ActiveDrain): Promise<void> {\n\t\twhile (true) {\n\t\t\tconst work = this._queue.nextEligibleWork(generation.selectedTokens, generation.mode);\n\t\t\tif (work === undefined) {\n\t\t\t\tthis._closeGeneration(generation, { kind: 'result' });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tgeneration.inFlightWork = work;\n\t\t\tconst result = await this._writer.write(work);\n\t\t\tif (result === true) this._queue.acknowledgeSuccess(work);\n\t\t\telse this._queue.acknowledgeFailure(work, result);\n\t\t\tgeneration.inFlightWork = null;\n\t\t\tthis._notifySessionProgress();\n\t\t}\n\t}\n\n\tprivate _closeGeneration(generation: ActiveDrain, termination: DrainTermination): void {\n\t\tif (this._activeDrain !== generation) return;\n\t\tlet settlement: DrainSettlement;\n\t\tswitch (termination.kind) {\n\t\t\tcase 'result': {\n\t\t\t\tconst result = this._queue.generationResult(generation.selectedTokens);\n\t\t\t\tsettlement =\n\t\t\t\t\tresult.failures.length === 0\n\t\t\t\t\t\t? { kind: 'resolved' }\n\t\t\t\t\t\t: { kind: 'rejected', reason: new PersistenceDrainError(result.failures) };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'fault':\n\t\t\t\tsettlement = { kind: 'rejected', reason: termination.fault };\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tassertNever(termination);\n\t\t}\n\n\t\tgeneration.inFlightWork = null;\n\t\tgeneration.settlement = settlement;\n\t\tthis._activeDrain = null;\n\t\tthis._notifySessionProgress();\n\t\tswitch (settlement.kind) {\n\t\t\tcase 'resolved':\n\t\t\t\tgeneration.resolve();\n\t\t\t\treturn;\n\t\t\tcase 'rejected':\n\t\t\t\tgeneration.reject(settlement.reason);\n\t\t\t\tif (settlement.reason instanceof PersistenceDrainError) {\n\t\t\t\t\tthis._observeFailure(generation, settlement.reason);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\tassertNever(settlement);\n\t\t}\n\t}\n\n\tprivate async _awaitSessionQuiescence(sessionId: SessionId): Promise<void> {\n\t\tconst generation = this._joinOrStart('explicit');\n\t\tvoid generation.promise.catch(() => undefined);\n\t\twhile (true) {\n\t\t\tconst quiescence = this._sessionQuiescence(generation, sessionId);\n\t\t\tswitch (quiescence.kind) {\n\t\t\t\tcase 'pending':\n\t\t\t\t\tawait this._waitForSessionProgress(sessionId);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'resolved':\n\t\t\t\t\treturn;\n\t\t\t\tcase 'rejected':\n\t\t\t\t\tthrow quiescence.reason;\n\t\t\t\tdefault:\n\t\t\t\t\treturn assertNever(quiescence);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _sessionQuiescence(generation: ActiveDrain, sessionId: SessionId): SessionQuiescence {\n\t\tif (\n\t\t\tgeneration.settlement?.kind === 'rejected' &&\n\t\t\t!(generation.settlement.reason instanceof PersistenceDrainError)\n\t\t) {\n\t\t\treturn { kind: 'rejected', reason: generation.settlement.reason };\n\t\t}\n\t\tif (generation.inFlightWork?.sessionId === sessionId) return { kind: 'pending' };\n\t\tif (this._queue.hasEligibleWork(generation.selectedTokens, generation.mode, sessionId)) {\n\t\t\treturn { kind: 'pending' };\n\t\t}\n\n\t\tconst failures = this._queue.currentFailures(generation.selectedTokens, sessionId);\n\t\treturn failures.length === 0\n\t\t\t? { kind: 'resolved' }\n\t\t\t: { kind: 'rejected', reason: new PersistenceDrainError(failures) };\n\t}\n\n\tprivate _waitForSessionProgress(sessionId: SessionId): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst waiters = this._sessionProgressWaiters.get(sessionId) ?? new Set<() => void>();\n\t\t\twaiters.add(resolve);\n\t\t\tthis._sessionProgressWaiters.set(sessionId, waiters);\n\t\t});\n\t}\n\n\tprivate _notifySessionProgress(): void {\n\t\tfor (const [sessionId, waiters] of this._sessionProgressWaiters) {\n\t\t\tthis._sessionProgressWaiters.delete(sessionId);\n\t\t\tfor (const resolve of waiters) resolve();\n\t\t}\n\t}\n\n\tprivate _assertSessionAdmissionOpen(sessionId: SessionId): void {\n\t\tif (\n\t\t\tthis._globalResetOwners > 0 ||\n\t\t\tthis._globalQuarantined ||\n\t\t\tthis._sessionBarriers.has(sessionId) ||\n\t\t\tthis._quarantinedSessions.has(sessionId) ||\n\t\t\tthis._evictionQuarantinedSessions.has(sessionId)\n\t\t) {\n\t\t\tthrow new PersistenceSessionAdmissionClosedError(sessionId);\n\t\t}\n\t}\n\n\tprivate _observeFailure(generation: ActiveDrain, error: PersistenceDrainError): void {\n\t\tthis._logger.info('Persistence drain completed with failures', {\n\t\t\tfailed: error.failures.length,\n\t\t\tselected: generation.selectedTokens.size,\n\t\t});\n\t\tthis._eventEmitter?.emit('persistenceError', { operation: 'flushBuffer', error });\n\t}\n}\n"],"names":["PersistenceBuffer","Map","AsyncLocalStorage","Set","Promise","config","PersistenceWorkQueue","NullLogger","PersistenceWriter","sessionId","thoughtId","sessions","emitter","thought","targetThoughtId","branchId","thoughts","edges","summaries","setInterval","clearInterval","generation","reason","PersistenceDrainError","failures","failure","operation","PersistenceSessionAdmissionClosedError","currentOwnership","PersistenceSessionBarrierReentrancyError","operationOwnership","state","result","value","error","undefined","prior","Array","mode","active","resolveGeneration","rejectGeneration","_reason","promise","resolve","reject","fault","work","termination","settlement","assertNever","quiescence","waiters"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core/PersistenceBuffer.js","sources":["../../src/core/PersistenceBuffer.ts"],"sourcesContent":["/**\n * Joinable coordinator for attributable persistence work.\n *\n * @module PersistenceBuffer\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nimport type { PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport type { BranchId, SessionId, ThoughtId } from '../contracts/ids.js';\nimport type { PersistenceWork, PersistenceWorkToken } from '../contracts/persistence-work.js';\nimport type { PersistenceBacklogView } from '../contracts/persistence-backlog.js';\nimport {\n\tPersistenceBacklogFullError,\n\tPersistenceDrainError,\n\tPersistenceSessionAdmissionClosedError,\n\tPersistenceSessionBarrierReentrancyError,\n} from './PersistenceBufferErrors.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { assertNever } from '../utils.js';\nimport type { Summary } from './compression/Summary.js';\nimport type { DurableIdentitySession } from './DurableThoughtIdentityIndex.js';\nimport type { Edge } from './graph/Edge.js';\nimport { PersistenceWorkQueue, type PersistenceSelectionMode } from './PersistenceWorkQueue.js';\nimport { PersistenceWriter, type PersistenceDelay } from './PersistenceWriter.js';\nimport type { ThoughtData } from './thought.js';\n\n/** Event emitter contract for persistence error events. */\nexport interface PersistenceEventEmitter {\n\temit(event: 'persistenceError', payload: { operation: string; error: Error }): boolean;\n}\n\n/** Observable persistence state relevant to safe in-memory session eviction. */\nexport type SessionEvictionState = 'quiescent' | 'pending' | 'failed' | 'barrier';\n\n/** Configuration options for {@link PersistenceBuffer}. */\nexport interface PersistenceBufferConfig {\n\treadonly persistence: PersistenceBackend;\n\treadonly bufferSize: number;\n\treadonly flushInterval: number;\n\treadonly maxRetries: number;\n\t/** Optional emitter for `persistenceError` events. */\n\treadonly eventEmitter?: PersistenceEventEmitter | null;\n\treadonly logger?: Logger;\n\t/** Optional retry scheduler for deterministic coordination and testing. */\n\treadonly delay?: PersistenceDelay;\n\treadonly durableHistorySize?: number;\n\treadonly persistBranches?: boolean;\n\t/**\n\t * Per-session limit on unacknowledged thought and backtrack writes, terminal failures\n\t * included. Enforced by {@link PersistenceBuffer.assertThoughtBacklogAvailable}.\n\t * @default 10000\n\t */\n\treadonly maxPendingThoughtsPerSession?: number;\n}\n\nconst DEFAULT_MAX_PENDING_THOUGHTS_PER_SESSION = 10_000;\n\ntype ActiveDrain = {\n\treadonly promise: Promise<void>;\n\treadonly resolve: () => void;\n\treadonly reject: (reason: unknown) => void;\n\treadonly selectedTokens: Set<PersistenceWorkToken>;\n\tmode: PersistenceSelectionMode;\n\tbackgroundObserved: boolean;\n\tinFlightWork: PersistenceWork | null;\n\tsettlement: DrainSettlement | null;\n};\n\ntype SessionBarrierState = {\n\ttail: Promise<void>;\n\tpendingOwners: number;\n};\n\ntype DrainTermination =\n\t{ readonly kind: 'result' } | { readonly kind: 'fault'; readonly fault: unknown };\n\ntype DrainSettlement =\n\t{ readonly kind: 'resolved' } | { readonly kind: 'rejected'; readonly reason: unknown };\n\ntype SessionQuiescence =\n\t| { readonly kind: 'pending' }\n\t| { readonly kind: 'resolved' }\n\t| { readonly kind: 'rejected'; readonly reason: unknown };\n\n/**\n * Coordinates one globally joinable persistence generation at a time.\n *\n * Accepted work is owned by a queue independent of live session state. Explicit\n * callers can join and upgrade a background generation without starting another writer.\n */\nexport class PersistenceBuffer {\n\tprivate readonly _bufferSize: number;\n\tprivate readonly _flushInterval: number;\n\tprivate readonly _maxPendingThoughtsPerSession: number;\n\tprivate readonly _queue: PersistenceWorkQueue;\n\tprivate readonly _writer: PersistenceWriter;\n\tprivate _eventEmitter: PersistenceEventEmitter | null;\n\tprivate readonly _logger: Logger;\n\n\tprivate _flushTimer: ReturnType<typeof setInterval> | null = null;\n\tprivate _activeDrain: ActiveDrain | null = null;\n\tprivate readonly _sessionBarriers = new Map<SessionId, SessionBarrierState>();\n\tprivate readonly _sessionBarrierOwnership = new AsyncLocalStorage<ReadonlySet<SessionId>>();\n\tprivate readonly _sessionProgressWaiters = new Map<SessionId, Set<() => void>>();\n\tprivate readonly _quarantinedSessions = new Set<SessionId>();\n\tprivate readonly _evictionQuarantinedSessions = new Set<SessionId>();\n\tprivate _globalResetTail: Promise<void> = Promise.resolve();\n\tprivate _globalResetOwners = 0;\n\tprivate _globalQuarantined = false;\n\n\t/**\n\t * Creates a persistence-drain coordinator.\n\t *\n\t * @param config - Persistence dependencies, trigger thresholds, and retry policy.\n\t */\n\tpublic constructor(config: PersistenceBufferConfig) {\n\t\tthis._queue = new PersistenceWorkQueue(config.durableHistorySize, config.persistBranches);\n\t\tthis._bufferSize = config.bufferSize;\n\t\tthis._flushInterval = config.flushInterval;\n\t\tthis._maxPendingThoughtsPerSession =\n\t\t\tconfig.maxPendingThoughtsPerSession ?? DEFAULT_MAX_PENDING_THOUGHTS_PER_SESSION;\n\t\tthis._eventEmitter = config.eventEmitter ?? null;\n\t\tthis._logger = config.logger ?? new NullLogger();\n\t\tthis._writer = new PersistenceWriter({\n\t\t\tpersistence: config.persistence,\n\t\t\tmaxRetries: config.maxRetries,\n\t\t\tdelay: config.delay,\n\t\t});\n\t}\n\n\t/** @returns The underlying flush timer for lifecycle introspection. */\n\tpublic get timer(): ReturnType<typeof setInterval> | null {\n\t\treturn this._flushTimer;\n\t}\n\n\t/** @returns Whether a global drain generation is active. */\n\tpublic get isFlushing(): boolean {\n\t\treturn this._activeDrain !== null;\n\t}\n\n\t/** @returns Number of accepted thought writes not yet acknowledged successful. */\n\tpublic get pendingThoughtCount(): number {\n\t\treturn this._queue.pendingThoughtCount;\n\t}\n\n\tpublic hasThoughtIdentity(sessionId: SessionId, thoughtId: ThoughtId): boolean {\n\t\treturn this._queue.hasThoughtIdentity(sessionId, thoughtId);\n\t}\n\n\tpublic replaceDurableThoughtIdentities(sessions: readonly DurableIdentitySession[]): void {\n\t\tthis._queue.replaceDurableThoughtIdentities(sessions);\n\t}\n\n\t/**\n\t * Sets or clears the persistence error event emitter.\n\t *\n\t * @param emitter - Replacement emitter, or `null` to disable events.\n\t */\n\tpublic setEventEmitter(emitter: PersistenceEventEmitter | null): void {\n\t\tthis._eventEmitter = emitter;\n\t}\n\n\t/**\n\t * Accepts a thought with authoritative session attribution.\n\t *\n\t * Never rejects on backlog: callers enforce the per-session limit before they mutate state\n\t * with {@link assertThoughtBacklogAvailable}.\n\t *\n\t * @param sessionId - Session that owns the accepted thought.\n\t * @param thought - Thought to persist.\n\t */\n\tpublic bufferThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.enqueueThought(sessionId, thought);\n\t\tif (this._queue.pendingThoughtCount >= this._bufferSize) this._triggerBackgroundDrain();\n\t}\n\n\tpublic bufferBacktrack(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.enqueueBacktrack(sessionId, thought, targetThoughtId);\n\t\tif (this._queue.pendingThoughtCount >= this._bufferSize) this._triggerBackgroundDrain();\n\t}\n\n\t/**\n\t * Accepts the latest snapshot for one session-owned branch.\n\t *\n\t * @param sessionId - Session that owns the branch.\n\t * @param branchId - Stable branch coordinate.\n\t * @param thoughts - Branch snapshot copied by the queue.\n\t */\n\tpublic bufferBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.replaceBranch(sessionId, branchId, thoughts);\n\t}\n\n\t/**\n\t * @param sessionId - Session that owns the branch.\n\t * @param branchId - Stable branch coordinate to delete.\n\t */\n\tpublic deleteBranch(sessionId: SessionId, branchId: BranchId): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.deleteBranch(sessionId, branchId);\n\t}\n\n\t/**\n\t * Accepts the latest edge snapshot for one session.\n\t *\n\t * @param sessionId - Session that owns the edges.\n\t * @param edges - Edge snapshot copied by the queue.\n\t */\n\tpublic bufferEdges(sessionId: SessionId, edges: readonly Edge[]): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.replaceEdges(sessionId, edges);\n\t}\n\n\t/**\n\t * Accepts the latest summary snapshot for one session.\n\t *\n\t * @param sessionId - Session that owns the summaries.\n\t * @param summaries - Summary snapshot copied by the queue.\n\t */\n\tpublic bufferSummaries(sessionId: SessionId, summaries: readonly Summary[]): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t\tthis._queue.replaceSummaries(sessionId, summaries);\n\t}\n\n\t/** Rejects synchronously when lifecycle coordination has closed persistence admission. */\n\tpublic assertSessionAdmissionOpen(sessionId: SessionId): void {\n\t\tthis._assertSessionAdmissionOpen(sessionId);\n\t}\n\n\t/**\n\t * Rejects synchronously when the session already holds its limit of unacknowledged thought\n\t * and backtrack writes, terminal failures included.\n\t *\n\t * At the limit this starts or joins an explicit drain without awaiting it, so retained\n\t * failures are retried and a later call succeeds once the backend recovers. Call it before\n\t * any session state changes: {@link bufferThought} and {@link bufferBacktrack} never reject.\n\t *\n\t * @param sessionId - Session whose thought backlog is checked.\n\t * @throws {@link PersistenceBacklogFullError} when the session is at its limit.\n\t */\n\tpublic assertThoughtBacklogAvailable(sessionId: SessionId): void {\n\t\tconst pending = this._queue.pendingThoughtCountForSession(sessionId);\n\t\tif (pending < this._maxPendingThoughtsPerSession) return;\n\t\tvoid this._joinOrStart('explicit').promise.catch(() => undefined);\n\t\tthis._logger.warn('Persistence backlog full, rejecting thought', {\n\t\t\tsessionId,\n\t\t\tpending,\n\t\t\tlimit: this._maxPendingThoughtsPerSession,\n\t\t});\n\t\tthrow new PersistenceBacklogFullError(sessionId, pending, this._maxPendingThoughtsPerSession);\n\t}\n\n\t/** Starts the periodic background-drain timer without keeping the process alive. */\n\tpublic startFlushTimer(): void {\n\t\tif (this._flushTimer !== null) return;\n\t\tthis._flushTimer = setInterval(() => this._triggerBackgroundDrain(), this._flushInterval);\n\t\tif (typeof this._flushTimer === 'object' && 'unref' in this._flushTimer) {\n\t\t\tthis._flushTimer.unref();\n\t\t}\n\t}\n\n\t/** Stops the periodic background-drain timer. */\n\tpublic stopFlushTimer(): void {\n\t\tif (this._flushTimer === null) return;\n\t\tclearInterval(this._flushTimer);\n\t\tthis._flushTimer = null;\n\t}\n\n\t/**\n\t * Starts or joins an explicit global drain generation.\n\t *\n\t * @returns The exact shared promise for the active generation.\n\t */\n\tpublic drain(): Promise<void> {\n\t\treturn this._joinOrStart('explicit').promise;\n\t}\n\n\t/** @returns The exact same promise as {@link drain} for the active generation. */\n\tpublic flush(): Promise<void> {\n\t\treturn this.drain();\n\t}\n\n\t/**\n\t * Joins the global explicit generation and projects its terminal failures to one session.\n\t * This method does not close admission; lifecycle owners must use\n\t * {@link withSessionBarrier} when work must not cross an owner callback.\n\t *\n\t * @param sessionId - Session whose accepted writes form the barrier projection.\n\t * @returns A promise that rejects only for that session's failures or an unknown fault.\n\t */\n\tpublic drainSession(sessionId: SessionId): Promise<void> {\n\t\tconst generation = this._joinOrStart('explicit');\n\t\treturn generation.promise.catch((reason: unknown) => {\n\t\t\tif (!(reason instanceof PersistenceDrainError)) throw reason;\n\t\t\tconst failures = reason.failures.filter((failure) => failure.sessionId === sessionId);\n\t\t\tif (failures.length > 0) throw new PersistenceDrainError(failures);\n\t\t});\n\t}\n\n\t/** Returns queue-derived persistence state for safe session eviction planning. */\n\tpublic sessionEvictionState(sessionId: SessionId): SessionEvictionState {\n\t\tif (this._globalResetOwners > 0 || this._sessionBarriers.has(sessionId)) return 'barrier';\n\t\tif (\n\t\t\tthis._globalQuarantined ||\n\t\t\tthis._queue.hasSessionTerminalFailure(sessionId) ||\n\t\t\tthis._quarantinedSessions.has(sessionId) ||\n\t\t\tthis._evictionQuarantinedSessions.has(sessionId)\n\t\t) {\n\t\t\treturn 'failed';\n\t\t}\n\t\treturn this._queue.hasSessionWork(sessionId) ? 'pending' : 'quiescent';\n\t}\n\n\t/**\n\t * Drains accepted session work before ordinary in-memory eviction cleanup.\n\t *\n\t * Unlike reset barriers, this operation never clears durable state or discards\n\t * accepted work. Failure retains admission quarantine until a later explicit\n\t * invocation successfully drains and completes cleanup.\n\t */\n\tpublic withSessionEvictionBarrier<T>(\n\t\tsessionId: SessionId,\n\t\toperation: () => Promise<T>\n\t): Promise<T> {\n\t\tif (\n\t\t\tthis._globalResetOwners > 0 ||\n\t\t\tthis._globalQuarantined ||\n\t\t\tthis._quarantinedSessions.has(sessionId)\n\t\t) {\n\t\t\treturn Promise.reject(new PersistenceSessionAdmissionClosedError(sessionId));\n\t\t}\n\t\tconst currentOwnership = this._sessionBarrierOwnership.getStore();\n\t\tif (currentOwnership?.has(sessionId) === true) {\n\t\t\treturn Promise.reject(new PersistenceSessionBarrierReentrancyError(sessionId));\n\t\t}\n\t\tconst operationOwnership = new Set(currentOwnership);\n\t\toperationOwnership.add(sessionId);\n\t\tconst state = this._sessionBarriers.get(sessionId) ?? {\n\t\t\ttail: Promise.resolve(),\n\t\t\tpendingOwners: 0,\n\t\t};\n\t\tthis._sessionBarriers.set(sessionId, state);\n\t\tstate.pendingOwners += 1;\n\n\t\tconst result = state.tail.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait this._awaitSessionQuiescence(sessionId);\n\t\t\t\tconst value = await this._sessionBarrierOwnership.run(operationOwnership, operation);\n\t\t\t\tthis._queue.forgetQuiescentSession(sessionId);\n\t\t\t\tthis._evictionQuarantinedSessions.delete(sessionId);\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tthis._evictionQuarantinedSessions.add(sessionId);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tstate.pendingOwners -= 1;\n\t\t\t\tif (state.pendingOwners === 0) this._sessionBarriers.delete(sessionId);\n\t\t\t}\n\t\t});\n\t\tstate.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** Forgets queue coordinates only when the session is fully quiescent. */\n\tpublic forgetQuiescentSession(sessionId: SessionId): boolean {\n\t\treturn this.sessionEvictionState(sessionId) === 'quiescent'\n\t\t\t? this._queue.forgetQuiescentSession(sessionId)\n\t\t\t: false;\n\t}\n\n\t/**\n\t * Runs one lifecycle operation while persistence admission is closed for a session.\n\t *\n\t * Admission closes synchronously when this method is called. Already accepted work for\n\t * the session is settled first; an exhausted session failure rejects without invoking\n\t * `operation`. Concurrent calls for the same session execute in FIFO call order and keep\n\t * admission closed until the final callback settles. Other sessions remain admissible and\n\t * may be owned by a nested callback. Reacquiring the same session from the owning callback's\n\t * async call chain rejects before joining the FIFO because awaiting it would deadlock its owner.\n\t *\n\t * @example\n\t * ```ts\n\t * await buffer.withSessionBarrier(sessionId, async () => {\n\t * await persistence.clearSession(sessionId);\n\t * });\n\t * ```\n\t *\n\t * @param sessionId - Session exclusively owned for the callback duration.\n\t * @param operation - Awaited lifecycle operation run only after prior work settles.\n\t * @returns The callback result after admission has reopened when no owner remains.\n\t * @throws {@link PersistenceSessionBarrierReentrancyError} when the owning async call chain\n\t * attempts to reacquire `sessionId`.\n\t */\n\tpublic withSessionBarrier<T>(sessionId: SessionId, operation: () => Promise<T>): Promise<T> {\n\t\tconst currentOwnership = this._sessionBarrierOwnership.getStore();\n\t\tif (currentOwnership?.has(sessionId) === true) {\n\t\t\treturn Promise.reject(new PersistenceSessionBarrierReentrancyError(sessionId));\n\t\t}\n\t\tconst operationOwnership = new Set(currentOwnership);\n\t\toperationOwnership.add(sessionId);\n\n\t\tconst state = this._sessionBarriers.get(sessionId) ?? {\n\t\t\ttail: Promise.resolve(),\n\t\t\tpendingOwners: 0,\n\t\t};\n\t\tthis._sessionBarriers.set(sessionId, state);\n\t\tstate.pendingOwners += 1;\n\n\t\tconst result = state.tail.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait this._awaitSessionQuiescence(sessionId);\n\t\t\t\treturn await this._sessionBarrierOwnership.run(operationOwnership, operation);\n\t\t\t} finally {\n\t\t\t\tstate.pendingOwners -= 1;\n\t\t\t\tif (state.pendingOwners === 0) this._sessionBarriers.delete(sessionId);\n\t\t\t}\n\t\t});\n\t\tstate.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Runs a scoped reset, retaining admission quarantine on failure.\n\t * A retry may pass retained write failures because successful durable deletion\n\t * invalidates those stale queue entries before admission reopens.\n\t */\n\tpublic withSessionResetBarrier<T>(sessionId: SessionId, operation: () => Promise<T>): Promise<T> {\n\t\tif (this._globalResetOwners > 0 || this._globalQuarantined) {\n\t\t\treturn Promise.reject(new PersistenceSessionAdmissionClosedError(sessionId));\n\t\t}\n\t\tconst currentOwnership = this._sessionBarrierOwnership.getStore();\n\t\tif (currentOwnership?.has(sessionId) === true) {\n\t\t\treturn Promise.reject(new PersistenceSessionBarrierReentrancyError(sessionId));\n\t\t}\n\t\tconst operationOwnership = new Set(currentOwnership);\n\t\toperationOwnership.add(sessionId);\n\t\tconst state = this._sessionBarriers.get(sessionId) ?? {\n\t\t\ttail: Promise.resolve(),\n\t\t\tpendingOwners: 0,\n\t\t};\n\t\tthis._sessionBarriers.set(sessionId, state);\n\t\tstate.pendingOwners += 1;\n\n\t\tconst result = state.tail.then(async () => {\n\t\t\ttry {\n\t\t\t\ttry {\n\t\t\t\t\tawait this._awaitSessionQuiescence(sessionId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!(error instanceof PersistenceDrainError)) throw error;\n\t\t\t\t}\n\t\t\t\tconst value = await this._sessionBarrierOwnership.run(operationOwnership, operation);\n\t\t\t\tthis._queue.discardSession(sessionId);\n\t\t\t\tthis._quarantinedSessions.delete(sessionId);\n\t\t\t\tthis._evictionQuarantinedSessions.delete(sessionId);\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tthis._quarantinedSessions.add(sessionId);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tstate.pendingOwners -= 1;\n\t\t\t\tif (state.pendingOwners === 0) this._sessionBarriers.delete(sessionId);\n\t\t\t}\n\t\t});\n\t\tstate.tail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** Runs a trusted global reset behind a global admission barrier. */\n\tpublic withGlobalResetBarrier<T>(operation: () => Promise<T>): Promise<T> {\n\t\tthis._globalResetOwners += 1;\n\t\tconst prior = this._globalResetTail;\n\t\tconst result = prior.then(async () => {\n\t\t\ttry {\n\t\t\t\tawait Promise.all(Array.from(this._sessionBarriers.values(), (state) => state.tail));\n\t\t\t\ttry {\n\t\t\t\t\tawait this.drain();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!(error instanceof PersistenceDrainError)) throw error;\n\t\t\t\t}\n\t\t\t\tconst value = await operation();\n\t\t\t\tthis._queue.discardAll();\n\t\t\t\tthis._quarantinedSessions.clear();\n\t\t\t\tthis._evictionQuarantinedSessions.clear();\n\t\t\t\tthis._globalQuarantined = false;\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tthis._globalQuarantined = true;\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tthis._globalResetOwners -= 1;\n\t\t\t}\n\t\t});\n\t\tthis._globalResetTail = result.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined\n\t\t);\n\t\treturn result;\n\t}\n\n\t/** @returns A frozen point-in-time view of quarantine and unflushed work for readiness probes. */\n\tpublic getBacklogView(): PersistenceBacklogView {\n\t\tconst quarantinedSessions = new Set<SessionId>([\n\t\t\t...this._quarantinedSessions,\n\t\t\t...this._evictionQuarantinedSessions,\n\t\t]);\n\t\treturn Object.freeze({\n\t\t\tglobalQuarantined: this._globalQuarantined,\n\t\t\tquarantinedSessionCount: quarantinedSessions.size,\n\t\t\tretainedFailureCount: this._queue.currentFailures().length,\n\t\t\tpendingThoughtCount: this._queue.pendingThoughtCount,\n\t\t});\n\t}\n\n\tprivate _joinOrStart(mode: PersistenceSelectionMode): ActiveDrain {\n\t\tconst active = this._activeDrain;\n\t\tif (active !== null) {\n\t\t\tif (mode === 'explicit') active.mode = mode;\n\t\t\treturn active;\n\t\t}\n\n\t\tlet resolveGeneration = (): void => undefined;\n\t\tlet rejectGeneration = (_reason: unknown): void => undefined;\n\t\tconst promise = new Promise<void>((resolve, reject) => {\n\t\t\tresolveGeneration = resolve;\n\t\t\trejectGeneration = reject;\n\t\t});\n\t\tconst generation: ActiveDrain = {\n\t\t\tpromise,\n\t\t\tresolve: resolveGeneration,\n\t\t\treject: rejectGeneration,\n\t\t\tselectedTokens: new Set<PersistenceWorkToken>(),\n\t\t\tmode,\n\t\t\tbackgroundObserved: false,\n\t\t\tinFlightWork: null,\n\t\t\tsettlement: null,\n\t\t};\n\t\tthis._activeDrain = generation;\n\t\tvoid this._runDrain(generation).catch((fault: unknown) => {\n\t\t\tthis._closeGeneration(generation, { kind: 'fault', fault });\n\t\t});\n\t\treturn generation;\n\t}\n\n\tprivate _triggerBackgroundDrain(): void {\n\t\tconst generation = this._joinOrStart('background');\n\t\tif (generation.backgroundObserved) return;\n\t\tgeneration.backgroundObserved = true;\n\t\tvoid generation.promise.catch(() => undefined);\n\t}\n\n\tprivate async _runDrain(generation: ActiveDrain): Promise<void> {\n\t\twhile (true) {\n\t\t\tconst work = this._queue.nextEligibleWork(generation.selectedTokens, generation.mode);\n\t\t\tif (work === undefined) {\n\t\t\t\tthis._closeGeneration(generation, { kind: 'result' });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tgeneration.inFlightWork = work;\n\t\t\tconst result = await this._writer.write(work);\n\t\t\tif (result === true) this._queue.acknowledgeSuccess(work);\n\t\t\telse this._queue.acknowledgeFailure(work, result);\n\t\t\tgeneration.inFlightWork = null;\n\t\t\tthis._notifySessionProgress();\n\t\t}\n\t}\n\n\tprivate _closeGeneration(generation: ActiveDrain, termination: DrainTermination): void {\n\t\tif (this._activeDrain !== generation) return;\n\t\tlet settlement: DrainSettlement;\n\t\tswitch (termination.kind) {\n\t\t\tcase 'result': {\n\t\t\t\tconst result = this._queue.generationResult(generation.selectedTokens);\n\t\t\t\tsettlement =\n\t\t\t\t\tresult.failures.length === 0\n\t\t\t\t\t\t? { kind: 'resolved' }\n\t\t\t\t\t\t: { kind: 'rejected', reason: new PersistenceDrainError(result.failures) };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'fault':\n\t\t\t\tsettlement = { kind: 'rejected', reason: termination.fault };\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tassertNever(termination);\n\t\t}\n\n\t\tgeneration.inFlightWork = null;\n\t\tgeneration.settlement = settlement;\n\t\tthis._activeDrain = null;\n\t\tthis._notifySessionProgress();\n\t\tswitch (settlement.kind) {\n\t\t\tcase 'resolved':\n\t\t\t\tgeneration.resolve();\n\t\t\t\treturn;\n\t\t\tcase 'rejected':\n\t\t\t\tgeneration.reject(settlement.reason);\n\t\t\t\tif (settlement.reason instanceof PersistenceDrainError) {\n\t\t\t\t\tthis._observeFailure(generation, settlement.reason);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\tassertNever(settlement);\n\t\t}\n\t}\n\n\tprivate async _awaitSessionQuiescence(sessionId: SessionId): Promise<void> {\n\t\tconst generation = this._joinOrStart('explicit');\n\t\tvoid generation.promise.catch(() => undefined);\n\t\twhile (true) {\n\t\t\tconst quiescence = this._sessionQuiescence(generation, sessionId);\n\t\t\tswitch (quiescence.kind) {\n\t\t\t\tcase 'pending':\n\t\t\t\t\tawait this._waitForSessionProgress(sessionId);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'resolved':\n\t\t\t\t\treturn;\n\t\t\t\tcase 'rejected':\n\t\t\t\t\tthrow quiescence.reason;\n\t\t\t\tdefault:\n\t\t\t\t\treturn assertNever(quiescence);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _sessionQuiescence(generation: ActiveDrain, sessionId: SessionId): SessionQuiescence {\n\t\tif (\n\t\t\tgeneration.settlement?.kind === 'rejected' &&\n\t\t\t!(generation.settlement.reason instanceof PersistenceDrainError)\n\t\t) {\n\t\t\treturn { kind: 'rejected', reason: generation.settlement.reason };\n\t\t}\n\t\tif (generation.inFlightWork?.sessionId === sessionId) return { kind: 'pending' };\n\t\tif (this._queue.hasEligibleWork(generation.selectedTokens, generation.mode, sessionId)) {\n\t\t\treturn { kind: 'pending' };\n\t\t}\n\n\t\tconst failures = this._queue.currentFailures(generation.selectedTokens, sessionId);\n\t\treturn failures.length === 0\n\t\t\t? { kind: 'resolved' }\n\t\t\t: { kind: 'rejected', reason: new PersistenceDrainError(failures) };\n\t}\n\n\tprivate _waitForSessionProgress(sessionId: SessionId): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst waiters = this._sessionProgressWaiters.get(sessionId) ?? new Set<() => void>();\n\t\t\twaiters.add(resolve);\n\t\t\tthis._sessionProgressWaiters.set(sessionId, waiters);\n\t\t});\n\t}\n\n\tprivate _notifySessionProgress(): void {\n\t\tfor (const [sessionId, waiters] of this._sessionProgressWaiters) {\n\t\t\tthis._sessionProgressWaiters.delete(sessionId);\n\t\t\tfor (const resolve of waiters) resolve();\n\t\t}\n\t}\n\n\tprivate _assertSessionAdmissionOpen(sessionId: SessionId): void {\n\t\tif (\n\t\t\tthis._globalResetOwners > 0 ||\n\t\t\tthis._globalQuarantined ||\n\t\t\tthis._sessionBarriers.has(sessionId) ||\n\t\t\tthis._quarantinedSessions.has(sessionId) ||\n\t\t\tthis._evictionQuarantinedSessions.has(sessionId)\n\t\t) {\n\t\t\tthrow new PersistenceSessionAdmissionClosedError(sessionId);\n\t\t}\n\t}\n\n\tprivate _observeFailure(generation: ActiveDrain, error: PersistenceDrainError): void {\n\t\tthis._logger.info('Persistence drain completed with failures', {\n\t\t\tfailed: error.failures.length,\n\t\t\tselected: generation.selectedTokens.size,\n\t\t});\n\t\tthis._eventEmitter?.emit('persistenceError', { operation: 'flushBuffer', error });\n\t}\n}\n"],"names":["DEFAULT_MAX_PENDING_THOUGHTS_PER_SESSION","PersistenceBuffer","Map","AsyncLocalStorage","Set","Promise","config","PersistenceWorkQueue","NullLogger","PersistenceWriter","sessionId","thoughtId","sessions","emitter","thought","targetThoughtId","branchId","thoughts","edges","summaries","pending","undefined","PersistenceBacklogFullError","setInterval","clearInterval","generation","reason","PersistenceDrainError","failures","failure","operation","PersistenceSessionAdmissionClosedError","currentOwnership","PersistenceSessionBarrierReentrancyError","operationOwnership","state","result","value","error","prior","Array","quarantinedSessions","Object","mode","active","resolveGeneration","rejectGeneration","_reason","promise","resolve","reject","fault","work","termination","settlement","assertNever","quiescence","waiters"],"mappings":"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"}
|
|
@@ -19,4 +19,14 @@ export declare class PersistenceSessionBarrierReentrancyError extends Sequential
|
|
|
19
19
|
readonly sessionId: SessionId;
|
|
20
20
|
constructor(sessionId: SessionId);
|
|
21
21
|
}
|
|
22
|
+
/** Error raised when a session already holds its limit of unacknowledged thought writes. */
|
|
23
|
+
export declare class PersistenceBacklogFullError extends SequentialThinkingError {
|
|
24
|
+
/** Session whose persistence backlog is full. */
|
|
25
|
+
readonly sessionId: SessionId;
|
|
26
|
+
/** Unacknowledged thought and backtrack writes at the time of rejection. */
|
|
27
|
+
readonly pending: number;
|
|
28
|
+
/** Configured per-session limit. */
|
|
29
|
+
readonly limit: number;
|
|
30
|
+
constructor(sessionId: SessionId, pending: number, limit: number);
|
|
31
|
+
}
|
|
22
32
|
//# sourceMappingURL=PersistenceBufferErrors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceBufferErrors.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceBufferErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAe,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEpE,mFAAmF;AACnF,qBAAa,qBAAsB,SAAQ,uBAAuB;IACjE,2DAA2D;IAC3D,SAAgB,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAC;gBAEhD,QAAQ,EAAE,SAAS,sBAAsB,EAAE;CAQvD;AAED,iGAAiG;AACjG,qBAAa,sCAAuC,SAAQ,uBAAuB;IAClF,qDAAqD;IACrD,SAAgB,SAAS,EAAE,SAAS,CAAC;gBAEzB,SAAS,EAAE,SAAS;CAQhC;AAED,2FAA2F;AAC3F,qBAAa,wCAAyC,SAAQ,uBAAuB;IACpF,6DAA6D;IAC7D,SAAgB,SAAS,EAAE,SAAS,CAAC;gBAEzB,SAAS,EAAE,SAAS;CAQhC"}
|
|
1
|
+
{"version":3,"file":"PersistenceBufferErrors.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceBufferErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAe,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEpE,mFAAmF;AACnF,qBAAa,qBAAsB,SAAQ,uBAAuB;IACjE,2DAA2D;IAC3D,SAAgB,QAAQ,EAAE,SAAS,sBAAsB,EAAE,CAAC;gBAEhD,QAAQ,EAAE,SAAS,sBAAsB,EAAE;CAQvD;AAED,iGAAiG;AACjG,qBAAa,sCAAuC,SAAQ,uBAAuB;IAClF,qDAAqD;IACrD,SAAgB,SAAS,EAAE,SAAS,CAAC;gBAEzB,SAAS,EAAE,SAAS;CAQhC;AAED,2FAA2F;AAC3F,qBAAa,wCAAyC,SAAQ,uBAAuB;IACpF,6DAA6D;IAC7D,SAAgB,SAAS,EAAE,SAAS,CAAC;gBAEzB,SAAS,EAAE,SAAS;CAQhC;AAED,4FAA4F;AAC5F,qBAAa,2BAA4B,SAAQ,uBAAuB;IACvE,iDAAiD;IACjD,SAAgB,SAAS,EAAE,SAAS,CAAC;IACrC,4EAA4E;IAC5E,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,oCAAoC;IACpC,SAAgB,KAAK,EAAE,MAAM,CAAC;gBAElB,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAUhE"}
|
|
@@ -25,6 +25,18 @@ class PersistenceSessionBarrierReentrancyError extends SequentialThinkingError {
|
|
|
25
25
|
this.sessionId = sessionId;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
class PersistenceBacklogFullError extends SequentialThinkingError {
|
|
29
|
+
sessionId;
|
|
30
|
+
pending;
|
|
31
|
+
limit;
|
|
32
|
+
constructor(sessionId, pending, limit){
|
|
33
|
+
super(`Persistence backlog for session '${sessionId}' is full: ${pending} of ${limit} thought writes are unacknowledged. Retry after the persistence backend recovers.`, ERROR_CODES.PERSISTENCE_BACKLOG_FULL);
|
|
34
|
+
this.name = 'PersistenceBacklogFullError';
|
|
35
|
+
this.sessionId = sessionId;
|
|
36
|
+
this.pending = pending;
|
|
37
|
+
this.limit = limit;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export { PersistenceBacklogFullError, PersistenceDrainError, PersistenceSessionAdmissionClosedError, PersistenceSessionBarrierReentrancyError };
|
|
29
41
|
|
|
30
42
|
//# sourceMappingURL=PersistenceBufferErrors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/PersistenceBufferErrors.js","sources":["../../src/core/PersistenceBufferErrors.ts"],"sourcesContent":["import type { SessionId } from '../contracts/ids.js';\nimport type { PersistenceWorkFailure } from '../contracts/persistence-work.js';\nimport { ERROR_CODES, SequentialThinkingError } from '../errors.js';\n\n/** Error raised when an explicit persistence drain has terminal write failures. */\nexport class PersistenceDrainError extends SequentialThinkingError {\n\t/** Failures captured when the drain generation settled. */\n\tpublic readonly failures: readonly PersistenceWorkFailure[];\n\n\tconstructor(failures: readonly PersistenceWorkFailure[]) {\n\t\tsuper(\n\t\t\t`Persistence drain failed with ${failures.length} terminal ${failures.length === 1 ? 'failure' : 'failures'}`,\n\t\t\tERROR_CODES.PERSISTENCE_DRAIN\n\t\t);\n\t\tthis.name = 'PersistenceDrainError';\n\t\tthis.failures = Object.freeze([...failures]);\n\t}\n}\n\n/** Error raised when persistence work is submitted while a lifecycle owner holds the session. */\nexport class PersistenceSessionAdmissionClosedError extends SequentialThinkingError {\n\t/** Session whose persistence admission is closed. */\n\tpublic readonly sessionId: SessionId;\n\n\tconstructor(sessionId: SessionId) {\n\t\tsuper(\n\t\t\t`Persistence admission for session '${sessionId}' is closed by a lifecycle barrier`,\n\t\t\tERROR_CODES.PERSISTENCE_SESSION_ADMISSION_CLOSED\n\t\t);\n\t\tthis.name = 'PersistenceSessionAdmissionClosedError';\n\t\tthis.sessionId = sessionId;\n\t}\n}\n\n/** Error raised when an owning async call chain tries to reacquire its session barrier. */\nexport class PersistenceSessionBarrierReentrancyError extends SequentialThinkingError {\n\t/** Session already owned by the current async call chain. */\n\tpublic readonly sessionId: SessionId;\n\n\tconstructor(sessionId: SessionId) {\n\t\tsuper(\n\t\t\t`Persistence lifecycle barrier for session '${sessionId}' is not reentrant`,\n\t\t\tERROR_CODES.PERSISTENCE_SESSION_BARRIER_REENTRANCY\n\t\t);\n\t\tthis.name = 'PersistenceSessionBarrierReentrancyError';\n\t\tthis.sessionId = sessionId;\n\t}\n}\n"],"names":["PersistenceDrainError","SequentialThinkingError","failures","ERROR_CODES","Object","PersistenceSessionAdmissionClosedError","sessionId","PersistenceSessionBarrierReentrancyError"],"mappings":";AAKO,MAAMA,8BAA8BC;IAE1B,SAA4C;IAE5D,YAAYC,QAA2C,CAAE;QACxD,KAAK,CACJ,CAAC,8BAA8B,EAAEA,SAAS,MAAM,CAAC,UAAU,EAAEA,AAAoB,MAApBA,SAAS,MAAM,GAAS,YAAY,YAAY,EAC7GC,YAAY,iBAAiB;QAE9B,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,QAAQ,GAAGC,OAAO,MAAM,CAAC;eAAIF;SAAS;IAC5C;AACD;AAGO,MAAMG,+CAA+CJ;IAE3C,UAAqB;IAErC,YAAYK,SAAoB,CAAE;QACjC,KAAK,CACJ,CAAC,mCAAmC,EAAEA,UAAU,kCAAkC,CAAC,EACnFH,YAAY,oCAAoC;QAEjD,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGG;IAClB;AACD;AAGO,MAAMC,iDAAiDN;IAE7C,UAAqB;IAErC,YAAYK,SAAoB,CAAE;QACjC,KAAK,CACJ,CAAC,2CAA2C,EAAEA,UAAU,kBAAkB,CAAC,EAC3EH,YAAY,sCAAsC;QAEnD,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGG;IAClB;AACD"}
|
|
1
|
+
{"version":3,"file":"core/PersistenceBufferErrors.js","sources":["../../src/core/PersistenceBufferErrors.ts"],"sourcesContent":["import type { SessionId } from '../contracts/ids.js';\nimport type { PersistenceWorkFailure } from '../contracts/persistence-work.js';\nimport { ERROR_CODES, SequentialThinkingError } from '../errors.js';\n\n/** Error raised when an explicit persistence drain has terminal write failures. */\nexport class PersistenceDrainError extends SequentialThinkingError {\n\t/** Failures captured when the drain generation settled. */\n\tpublic readonly failures: readonly PersistenceWorkFailure[];\n\n\tconstructor(failures: readonly PersistenceWorkFailure[]) {\n\t\tsuper(\n\t\t\t`Persistence drain failed with ${failures.length} terminal ${failures.length === 1 ? 'failure' : 'failures'}`,\n\t\t\tERROR_CODES.PERSISTENCE_DRAIN\n\t\t);\n\t\tthis.name = 'PersistenceDrainError';\n\t\tthis.failures = Object.freeze([...failures]);\n\t}\n}\n\n/** Error raised when persistence work is submitted while a lifecycle owner holds the session. */\nexport class PersistenceSessionAdmissionClosedError extends SequentialThinkingError {\n\t/** Session whose persistence admission is closed. */\n\tpublic readonly sessionId: SessionId;\n\n\tconstructor(sessionId: SessionId) {\n\t\tsuper(\n\t\t\t`Persistence admission for session '${sessionId}' is closed by a lifecycle barrier`,\n\t\t\tERROR_CODES.PERSISTENCE_SESSION_ADMISSION_CLOSED\n\t\t);\n\t\tthis.name = 'PersistenceSessionAdmissionClosedError';\n\t\tthis.sessionId = sessionId;\n\t}\n}\n\n/** Error raised when an owning async call chain tries to reacquire its session barrier. */\nexport class PersistenceSessionBarrierReentrancyError extends SequentialThinkingError {\n\t/** Session already owned by the current async call chain. */\n\tpublic readonly sessionId: SessionId;\n\n\tconstructor(sessionId: SessionId) {\n\t\tsuper(\n\t\t\t`Persistence lifecycle barrier for session '${sessionId}' is not reentrant`,\n\t\t\tERROR_CODES.PERSISTENCE_SESSION_BARRIER_REENTRANCY\n\t\t);\n\t\tthis.name = 'PersistenceSessionBarrierReentrancyError';\n\t\tthis.sessionId = sessionId;\n\t}\n}\n\n/** Error raised when a session already holds its limit of unacknowledged thought writes. */\nexport class PersistenceBacklogFullError extends SequentialThinkingError {\n\t/** Session whose persistence backlog is full. */\n\tpublic readonly sessionId: SessionId;\n\t/** Unacknowledged thought and backtrack writes at the time of rejection. */\n\tpublic readonly pending: number;\n\t/** Configured per-session limit. */\n\tpublic readonly limit: number;\n\n\tconstructor(sessionId: SessionId, pending: number, limit: number) {\n\t\tsuper(\n\t\t\t`Persistence backlog for session '${sessionId}' is full: ${pending} of ${limit} thought writes are unacknowledged. Retry after the persistence backend recovers.`,\n\t\t\tERROR_CODES.PERSISTENCE_BACKLOG_FULL\n\t\t);\n\t\tthis.name = 'PersistenceBacklogFullError';\n\t\tthis.sessionId = sessionId;\n\t\tthis.pending = pending;\n\t\tthis.limit = limit;\n\t}\n}\n"],"names":["PersistenceDrainError","SequentialThinkingError","failures","ERROR_CODES","Object","PersistenceSessionAdmissionClosedError","sessionId","PersistenceSessionBarrierReentrancyError","PersistenceBacklogFullError","pending","limit"],"mappings":";AAKO,MAAMA,8BAA8BC;IAE1B,SAA4C;IAE5D,YAAYC,QAA2C,CAAE;QACxD,KAAK,CACJ,CAAC,8BAA8B,EAAEA,SAAS,MAAM,CAAC,UAAU,EAAEA,AAAoB,MAApBA,SAAS,MAAM,GAAS,YAAY,YAAY,EAC7GC,YAAY,iBAAiB;QAE9B,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,QAAQ,GAAGC,OAAO,MAAM,CAAC;eAAIF;SAAS;IAC5C;AACD;AAGO,MAAMG,+CAA+CJ;IAE3C,UAAqB;IAErC,YAAYK,SAAoB,CAAE;QACjC,KAAK,CACJ,CAAC,mCAAmC,EAAEA,UAAU,kCAAkC,CAAC,EACnFH,YAAY,oCAAoC;QAEjD,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGG;IAClB;AACD;AAGO,MAAMC,iDAAiDN;IAE7C,UAAqB;IAErC,YAAYK,SAAoB,CAAE;QACjC,KAAK,CACJ,CAAC,2CAA2C,EAAEA,UAAU,kBAAkB,CAAC,EAC3EH,YAAY,sCAAsC;QAEnD,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGG;IAClB;AACD;AAGO,MAAME,oCAAoCP;IAEhC,UAAqB;IAErB,QAAgB;IAEhB,MAAc;IAE9B,YAAYK,SAAoB,EAAEG,OAAe,EAAEC,KAAa,CAAE;QACjE,KAAK,CACJ,CAAC,iCAAiC,EAAEJ,UAAU,WAAW,EAAEG,QAAQ,IAAI,EAAEC,MAAM,iFAAiF,CAAC,EACjKP,YAAY,wBAAwB;QAErC,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGG;QACjB,IAAI,CAAC,OAAO,GAAGG;QACf,IAAI,CAAC,KAAK,GAAGC;IACd;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceRestore.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceRestore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"PersistenceRestore.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceRestore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGX,kBAAkB,EAClB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAaxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,OAAO,EAAE,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC9C,CAAC;AA+DF,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC,0BAA0B,CAAC,CAkBrC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { asSessionId } from "../contracts/ids.js";
|
|
2
2
|
import { PersistenceCompatibilityError, PersistenceUnavailableError } from "../errors.js";
|
|
3
|
-
import { assertBranchScope, assertEdgeScopes, assertPersistableThoughtCollections, assertSummaryScopes, assertThoughtScope, assertUniqueRecordIds, parsePersistenceBranchId } from "../persistence/PersistenceScope.js";
|
|
3
|
+
import { assertBranchScope, assertEdgeScopes, assertPersistableThoughtCollections, assertSummaryScopes, assertThoughtScope, assertUniqueRecordIds, compareCodePoint, parsePersistenceBranchId } from "../persistence/PersistenceScope.js";
|
|
4
4
|
import { EdgeStore } from "./graph/EdgeStore.js";
|
|
5
5
|
import { repairRetainedBacktracks } from "../persistence/BacktrackPersistence.js";
|
|
6
6
|
function validateThoughts(sessionId, history, branches) {
|
|
@@ -18,25 +18,25 @@ function validateThoughts(sessionId, history, branches) {
|
|
|
18
18
|
];
|
|
19
19
|
assertPersistableThoughtCollections(collections, `restore:${sessionId}`);
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
const history = await persistence.loadHistoryForSession(sessionId);
|
|
23
|
-
const listedBranches = await persistence.listBranchesForSession(sessionId);
|
|
21
|
+
function stageBranches(sessionId, records) {
|
|
24
22
|
const branches = [];
|
|
25
23
|
const seenBranches = new Set();
|
|
26
|
-
for (const
|
|
27
|
-
const branchId = parsePersistenceBranchId(
|
|
24
|
+
for (const record of records){
|
|
25
|
+
const branchId = parsePersistenceBranchId(record.branchId, `restore:${sessionId}:branches`);
|
|
28
26
|
if (seenBranches.has(branchId)) throw new PersistenceCompatibilityError(`restore:${sessionId}:branches`, `duplicate branch id '${branchId}'`);
|
|
29
27
|
seenBranches.add(branchId);
|
|
30
|
-
const thoughts = await persistence.loadBranchForSession(sessionId, branchId);
|
|
31
|
-
if (void 0 === thoughts) throw new PersistenceCompatibilityError(`restore:${sessionId}:branches:${branchId}`, 'listed branch is missing');
|
|
32
28
|
branches.push(Object.freeze({
|
|
33
29
|
branchId,
|
|
34
30
|
thoughts: Object.freeze([
|
|
35
|
-
...thoughts
|
|
31
|
+
...record.thoughts
|
|
36
32
|
])
|
|
37
33
|
}));
|
|
38
34
|
}
|
|
39
|
-
|
|
35
|
+
return branches.sort((left, right)=>compareCodePoint(left.branchId, right.branchId));
|
|
36
|
+
}
|
|
37
|
+
function stageSession(sessionId, record) {
|
|
38
|
+
const branches = stageBranches(sessionId, record.branches);
|
|
39
|
+
const repaired = repairRetainedBacktracks(sessionId, record.history, branches);
|
|
40
40
|
const repairedBranches = repaired.branches.map((branch)=>Object.freeze({
|
|
41
41
|
branchId: branch.branchId,
|
|
42
42
|
thoughts: Object.freeze([
|
|
@@ -44,14 +44,12 @@ async function stageSession(persistence, sessionId) {
|
|
|
44
44
|
])
|
|
45
45
|
}));
|
|
46
46
|
validateThoughts(sessionId, repaired.history, repairedBranches);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
assertUniqueRecordIds(edges, `restore:${sessionId}:edges`, 'edge');
|
|
47
|
+
assertEdgeScopes(sessionId, record.edges);
|
|
48
|
+
assertUniqueRecordIds(record.edges, `restore:${sessionId}:edges`, 'edge');
|
|
50
49
|
const validationStore = new EdgeStore();
|
|
51
|
-
for (const restoredEdge of edges)validationStore.addEdge(restoredEdge);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
assertUniqueRecordIds(summaries, `restore:${sessionId}:summaries`, 'summary');
|
|
50
|
+
for (const restoredEdge of record.edges)validationStore.addEdge(restoredEdge);
|
|
51
|
+
assertSummaryScopes(sessionId, record.summaries);
|
|
52
|
+
assertUniqueRecordIds(record.summaries, `restore:${sessionId}:summaries`, 'summary');
|
|
55
53
|
return Object.freeze({
|
|
56
54
|
sessionId,
|
|
57
55
|
history: Object.freeze([
|
|
@@ -59,27 +57,24 @@ async function stageSession(persistence, sessionId) {
|
|
|
59
57
|
]),
|
|
60
58
|
branches: Object.freeze(repairedBranches),
|
|
61
59
|
edges: Object.freeze([
|
|
62
|
-
...edges
|
|
60
|
+
...record.edges
|
|
63
61
|
]),
|
|
64
62
|
summaries: Object.freeze([
|
|
65
|
-
...summaries
|
|
63
|
+
...record.summaries
|
|
66
64
|
])
|
|
67
65
|
});
|
|
68
66
|
}
|
|
69
67
|
async function stagePersistenceRestore(backend) {
|
|
70
68
|
if (!await backend.healthy()) throw new PersistenceUnavailableError();
|
|
71
|
-
const
|
|
72
|
-
const sessionIds = [];
|
|
73
|
-
const seen = new Set();
|
|
74
|
-
for (const listedSessionId of listedSessions){
|
|
75
|
-
const sessionId = asSessionId(listedSessionId);
|
|
76
|
-
if (!seen.has(sessionId)) {
|
|
77
|
-
seen.add(sessionId);
|
|
78
|
-
sessionIds.push(sessionId);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
69
|
+
const read = await backend.loadAllSessionsForRestore();
|
|
81
70
|
const sessions = [];
|
|
82
|
-
|
|
71
|
+
const seenSessions = new Set();
|
|
72
|
+
for (const record of read.sessions){
|
|
73
|
+
const sessionId = asSessionId(record.sessionId);
|
|
74
|
+
if (seenSessions.has(sessionId)) throw new PersistenceCompatibilityError('restore:sessions', `duplicate session id '${sessionId}'`);
|
|
75
|
+
seenSessions.add(sessionId);
|
|
76
|
+
sessions.push(stageSession(sessionId, record));
|
|
77
|
+
}
|
|
83
78
|
return Object.freeze({
|
|
84
79
|
sessions: Object.freeze(sessions)
|
|
85
80
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/PersistenceRestore.js","sources":["../../src/core/PersistenceRestore.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"core/PersistenceRestore.js","sources":["../../src/core/PersistenceRestore.ts"],"sourcesContent":["import type {\n\tPersistedBranchRecord,\n\tPersistedSessionRecord,\n\tPersistenceBackend,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId } from '../contracts/ids.js';\nimport type { Summary } from './compression/Summary.js';\nimport { PersistenceCompatibilityError, PersistenceUnavailableError } from '../errors.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tassertUniqueRecordIds,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from '../persistence/PersistenceScope.js';\nimport type { Edge } from './graph/Edge.js';\nimport { EdgeStore } from './graph/EdgeStore.js';\nimport type { ThoughtData } from './thought.js';\nimport { repairRetainedBacktracks } from '../persistence/BacktrackPersistence.js';\n\nexport type RestoredBranch = {\n\treadonly branchId: BranchId;\n\treadonly thoughts: readonly ThoughtData[];\n};\n\nexport type RestoredSession = {\n\treadonly sessionId: SessionId;\n\treadonly history: readonly ThoughtData[];\n\treadonly branches: readonly RestoredBranch[];\n\treadonly edges: readonly Edge[];\n\treadonly summaries: readonly Summary[];\n};\n\nexport type PersistenceRestoreSnapshot = {\n\treadonly sessions: readonly RestoredSession[];\n};\n\nfunction validateThoughts(\n\tsessionId: SessionId,\n\thistory: readonly ThoughtData[],\n\tbranches: readonly RestoredBranch[]\n): void {\n\tfor (const thought of history) assertThoughtScope('saveThoughtForSession', sessionId, thought);\n\tfor (const branch of branches) {\n\t\tassertBranchScope('saveBranchForSession', sessionId, branch.branchId, branch.thoughts);\n\t}\n\tconst collections: PersistedThoughtCollection[] = [\n\t\t{ sessionId, thoughts: history },\n\t\t...branches.map((branch) => ({ sessionId, thoughts: branch.thoughts })),\n\t];\n\tassertPersistableThoughtCollections(collections, `restore:${sessionId}`);\n}\n\nfunction stageBranches(\n\tsessionId: SessionId,\n\trecords: readonly PersistedBranchRecord[]\n): RestoredBranch[] {\n\tconst branches: RestoredBranch[] = [];\n\tconst seenBranches = new Set<BranchId>();\n\tfor (const record of records) {\n\t\tconst branchId = parsePersistenceBranchId(record.branchId, `restore:${sessionId}:branches`);\n\t\tif (seenBranches.has(branchId)) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t`restore:${sessionId}:branches`,\n\t\t\t\t`duplicate branch id '${branchId}'`\n\t\t\t);\n\t\t}\n\t\tseenBranches.add(branchId);\n\t\tbranches.push(Object.freeze({ branchId, thoughts: Object.freeze([...record.thoughts]) }));\n\t}\n\treturn branches.sort((left, right) => compareCodePoint(left.branchId, right.branchId));\n}\n\nfunction stageSession(sessionId: SessionId, record: PersistedSessionRecord): RestoredSession {\n\tconst branches = stageBranches(sessionId, record.branches);\n\tconst repaired = repairRetainedBacktracks(sessionId, record.history, branches);\n\tconst repairedBranches = repaired.branches.map((branch) =>\n\t\tObject.freeze({ branchId: branch.branchId, thoughts: Object.freeze([...branch.thoughts]) })\n\t);\n\tvalidateThoughts(sessionId, repaired.history, repairedBranches);\n\n\tassertEdgeScopes(sessionId, record.edges);\n\tassertUniqueRecordIds(record.edges, `restore:${sessionId}:edges`, 'edge');\n\tconst validationStore = new EdgeStore();\n\tfor (const restoredEdge of record.edges) validationStore.addEdge(restoredEdge);\n\n\tassertSummaryScopes(sessionId, record.summaries);\n\tassertUniqueRecordIds(record.summaries, `restore:${sessionId}:summaries`, 'summary');\n\n\treturn Object.freeze({\n\t\tsessionId,\n\t\thistory: Object.freeze([...repaired.history]),\n\t\tbranches: Object.freeze(repairedBranches),\n\t\tedges: Object.freeze([...record.edges]),\n\t\tsummaries: Object.freeze([...record.summaries]),\n\t});\n}\n\nexport async function stagePersistenceRestore(\n\tbackend: PersistenceBackend\n): Promise<PersistenceRestoreSnapshot> {\n\tif (!(await backend.healthy())) throw new PersistenceUnavailableError();\n\n\tconst read = await backend.loadAllSessionsForRestore();\n\tconst sessions: RestoredSession[] = [];\n\tconst seenSessions = new Set<SessionId>();\n\tfor (const record of read.sessions) {\n\t\tconst sessionId = asSessionId(record.sessionId);\n\t\tif (seenSessions.has(sessionId)) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t'restore:sessions',\n\t\t\t\t`duplicate session id '${sessionId}'`\n\t\t\t);\n\t\t}\n\t\tseenSessions.add(sessionId);\n\t\tsessions.push(stageSession(sessionId, record));\n\t}\n\treturn Object.freeze({ sessions: Object.freeze(sessions) });\n}\n"],"names":["validateThoughts","sessionId","history","branches","thought","assertThoughtScope","branch","assertBranchScope","collections","assertPersistableThoughtCollections","stageBranches","records","seenBranches","Set","record","branchId","parsePersistenceBranchId","PersistenceCompatibilityError","Object","left","right","compareCodePoint","stageSession","repaired","repairRetainedBacktracks","repairedBranches","assertEdgeScopes","assertUniqueRecordIds","validationStore","EdgeStore","restoredEdge","assertSummaryScopes","stagePersistenceRestore","backend","PersistenceUnavailableError","read","sessions","seenSessions","asSessionId"],"mappings":"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"}
|
|
@@ -34,6 +34,7 @@ type WorkOf<K extends WorkKind> = Extract<PersistenceWork, {
|
|
|
34
34
|
export declare class PersistenceWorkQueue {
|
|
35
35
|
private readonly _thoughts;
|
|
36
36
|
private readonly _thoughtIdentities;
|
|
37
|
+
private readonly _pendingThoughtsBySession;
|
|
37
38
|
private readonly _durableThoughtIdentities;
|
|
38
39
|
private readonly _persistBranches;
|
|
39
40
|
private readonly _branches;
|
|
@@ -135,6 +136,12 @@ export declare class PersistenceWorkQueue {
|
|
|
135
136
|
generationResult(selectedTokens?: ReadonlySet<PersistenceWorkToken>, sessionId?: SessionId): PersistenceGenerationResult;
|
|
136
137
|
/** @returns Number of accepted thought writes not yet acknowledged successful. */
|
|
137
138
|
get pendingThoughtCount(): number;
|
|
139
|
+
/**
|
|
140
|
+
* @param sessionId - Session whose unacknowledged writes are counted.
|
|
141
|
+
* @returns Unacknowledged thought and backtrack entries for the session, terminal failures
|
|
142
|
+
* included. Coalesced branch, edge and summary entries are not counted.
|
|
143
|
+
*/
|
|
144
|
+
pendingThoughtCountForSession(sessionId: SessionId): number;
|
|
138
145
|
/** @returns Number of all current thought and coalesced auxiliary entries. */
|
|
139
146
|
get pendingWorkCount(): number;
|
|
140
147
|
/** @returns Whether any accepted work remains for a session across all work kinds. */
|
|
@@ -154,6 +161,8 @@ export declare class PersistenceWorkQueue {
|
|
|
154
161
|
private _accept;
|
|
155
162
|
private _freezeClone;
|
|
156
163
|
private _deepFreeze;
|
|
164
|
+
private _incrementPendingThoughts;
|
|
165
|
+
private _decrementPendingThoughts;
|
|
157
166
|
private _addThoughtIdentity;
|
|
158
167
|
private _removeThoughtIdentity;
|
|
159
168
|
private _entries;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceWorkQueue.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceWorkQueue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACX,2BAA2B,EAC3B,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE1E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAEN,KAAK,sBAAsB,EAE3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,gFAAgF;AAChF,MAAM,MAAM,wBAAwB,GAAG,UAAU,GAAG,YAAY,CAAC;AAEjE,KAAK,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AACxC,KAAK,MAAM,CAAC,CAAC,SAAS,QAAQ,IAAI,OAAO,CAAC,eAAe,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAC;AAoBjF;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,oBAAoB;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4C;IACtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAgD;IACnF,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA8B;IACxE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoD;IAC9E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsC;IAEjE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+C;IAC/E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgC;IACjE,OAAO,CAAC,aAAa,CAAK;gBAEP,kBAAkB,SAAS,EAAE,eAAe,UAAO;IAOtE;;;;;;OAMG;IACI,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"PersistenceWorkQueue.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceWorkQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { DurableThoughtIdentityIndex, normalizeDurableHistoryRetention } from ".
|
|
|
3
3
|
class PersistenceWorkQueue {
|
|
4
4
|
_thoughts = [];
|
|
5
5
|
_thoughtIdentities = new Map();
|
|
6
|
+
_pendingThoughtsBySession = new Map();
|
|
6
7
|
_durableThoughtIdentities;
|
|
7
8
|
_persistBranches;
|
|
8
9
|
_branches = new Map();
|
|
@@ -29,6 +30,7 @@ class PersistenceWorkQueue {
|
|
|
29
30
|
work,
|
|
30
31
|
terminalFailure: void 0
|
|
31
32
|
});
|
|
33
|
+
this._incrementPendingThoughts(sessionId);
|
|
32
34
|
if (void 0 !== thought.id) this._addThoughtIdentity(sessionId, thought.id);
|
|
33
35
|
return work;
|
|
34
36
|
}
|
|
@@ -46,6 +48,7 @@ class PersistenceWorkQueue {
|
|
|
46
48
|
work,
|
|
47
49
|
terminalFailure: void 0
|
|
48
50
|
});
|
|
51
|
+
this._incrementPendingThoughts(sessionId);
|
|
49
52
|
if (void 0 !== thought.id) this._addThoughtIdentity(sessionId, thought.id);
|
|
50
53
|
return work;
|
|
51
54
|
}
|
|
@@ -158,6 +161,7 @@ class PersistenceWorkQueue {
|
|
|
158
161
|
const index = this._thoughts.findIndex((candidate)=>candidate === entry);
|
|
159
162
|
if (index >= 0) {
|
|
160
163
|
this._thoughts.splice(index, 1);
|
|
164
|
+
this._decrementPendingThoughts(work.sessionId);
|
|
161
165
|
if (void 0 !== work.thought.id) this._removeThoughtIdentity(work.sessionId, work.thought.id);
|
|
162
166
|
this._durableThoughtIdentities.appendThought(work.sessionId, work.thought);
|
|
163
167
|
}
|
|
@@ -168,6 +172,7 @@ class PersistenceWorkQueue {
|
|
|
168
172
|
const index = this._thoughts.findIndex((candidate)=>candidate === entry);
|
|
169
173
|
if (index >= 0) {
|
|
170
174
|
this._thoughts.splice(index, 1);
|
|
175
|
+
this._decrementPendingThoughts(work.sessionId);
|
|
171
176
|
if (void 0 !== work.thought.id) this._removeThoughtIdentity(work.sessionId, work.thought.id);
|
|
172
177
|
this._durableThoughtIdentities.appendThought(work.sessionId, work.thought);
|
|
173
178
|
}
|
|
@@ -210,6 +215,9 @@ class PersistenceWorkQueue {
|
|
|
210
215
|
get pendingThoughtCount() {
|
|
211
216
|
return this._thoughts.length;
|
|
212
217
|
}
|
|
218
|
+
pendingThoughtCountForSession(sessionId) {
|
|
219
|
+
return this._pendingThoughtsBySession.get(sessionId) ?? 0;
|
|
220
|
+
}
|
|
213
221
|
get pendingWorkCount() {
|
|
214
222
|
let branchCount = 0;
|
|
215
223
|
for (const branches of this._branches.values())branchCount += branches.size;
|
|
@@ -231,6 +239,7 @@ class PersistenceWorkQueue {
|
|
|
231
239
|
}
|
|
232
240
|
discardSession(sessionId) {
|
|
233
241
|
for(let index = this._thoughts.length - 1; index >= 0; index -= 1)if (this._thoughts[index]?.work.sessionId === sessionId) this._thoughts.splice(index, 1);
|
|
242
|
+
this._pendingThoughtsBySession.delete(sessionId);
|
|
234
243
|
this._thoughtIdentities.delete(sessionId);
|
|
235
244
|
this._durableThoughtIdentities.clearSession(sessionId);
|
|
236
245
|
this._branches.delete(sessionId);
|
|
@@ -242,6 +251,7 @@ class PersistenceWorkQueue {
|
|
|
242
251
|
}
|
|
243
252
|
discardAll() {
|
|
244
253
|
this._thoughts.length = 0;
|
|
254
|
+
this._pendingThoughtsBySession.clear();
|
|
245
255
|
this._thoughtIdentities.clear();
|
|
246
256
|
this._durableThoughtIdentities.clearAll();
|
|
247
257
|
this._branches.clear();
|
|
@@ -270,6 +280,14 @@ class PersistenceWorkQueue {
|
|
|
270
280
|
}
|
|
271
281
|
return value;
|
|
272
282
|
}
|
|
283
|
+
_incrementPendingThoughts(sessionId) {
|
|
284
|
+
this._pendingThoughtsBySession.set(sessionId, this.pendingThoughtCountForSession(sessionId) + 1);
|
|
285
|
+
}
|
|
286
|
+
_decrementPendingThoughts(sessionId) {
|
|
287
|
+
const remaining = this.pendingThoughtCountForSession(sessionId) - 1;
|
|
288
|
+
if (remaining > 0) this._pendingThoughtsBySession.set(sessionId, remaining);
|
|
289
|
+
else this._pendingThoughtsBySession.delete(sessionId);
|
|
290
|
+
}
|
|
273
291
|
_addThoughtIdentity(sessionId, thoughtId) {
|
|
274
292
|
const identities = this._thoughtIdentities.get(sessionId) ?? new Map();
|
|
275
293
|
identities.set(thoughtId, (identities.get(thoughtId) ?? 0) + 1);
|