@iworkforces/tracelattice 2.0.8 → 2.1.1

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.
Files changed (174) hide show
  1. package/README.md +88 -64
  2. package/dist/ServerConfig.d.ts +1 -1
  3. package/dist/ServerConfig.js.map +1 -1
  4. package/dist/cli.js +18 -73
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/ConfigLoader.d.ts +29 -26
  7. package/dist/config/ConfigLoader.d.ts.map +1 -1
  8. package/dist/config/ConfigLoader.js +40 -36
  9. package/dist/config/ConfigLoader.js.map +1 -1
  10. package/dist/contracts/PersistenceBackend.d.ts +7 -108
  11. package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
  12. package/dist/contracts/PersistenceBackend.js +1 -6
  13. package/dist/contracts/calibrator.d.ts +6 -6
  14. package/dist/contracts/calibrator.d.ts.map +1 -1
  15. package/dist/contracts/ids.d.ts +1 -8
  16. package/dist/contracts/ids.d.ts.map +1 -1
  17. package/dist/contracts/ids.js +2 -3
  18. package/dist/contracts/ids.js.map +1 -1
  19. package/dist/contracts/interfaces.d.ts +4 -6
  20. package/dist/contracts/interfaces.d.ts.map +1 -1
  21. package/dist/contracts/persistence-work.d.ts +2 -3
  22. package/dist/contracts/persistence-work.d.ts.map +1 -1
  23. package/dist/core/HistoryManager.d.ts +12 -16
  24. package/dist/core/HistoryManager.d.ts.map +1 -1
  25. package/dist/core/HistoryManager.js +19 -40
  26. package/dist/core/HistoryManager.js.map +1 -1
  27. package/dist/core/IHistoryManager.d.ts +22 -30
  28. package/dist/core/IHistoryManager.d.ts.map +1 -1
  29. package/dist/core/InputNormalizer.d.ts +7 -24
  30. package/dist/core/InputNormalizer.d.ts.map +1 -1
  31. package/dist/core/InputNormalizer.js +3 -9
  32. package/dist/core/InputNormalizer.js.map +1 -1
  33. package/dist/core/PersistenceBuffer.d.ts +3 -20
  34. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  35. package/dist/core/PersistenceBuffer.js +1 -4
  36. package/dist/core/PersistenceBuffer.js.map +1 -1
  37. package/dist/core/PersistenceRestore.d.ts.map +1 -1
  38. package/dist/core/PersistenceRestore.js +4 -10
  39. package/dist/core/PersistenceRestore.js.map +1 -1
  40. package/dist/core/PersistenceWriter.d.ts.map +1 -1
  41. package/dist/core/PersistenceWriter.js +3 -12
  42. package/dist/core/PersistenceWriter.js.map +1 -1
  43. package/dist/core/SessionErrors.d.ts +0 -11
  44. package/dist/core/SessionErrors.d.ts.map +1 -1
  45. package/dist/core/SessionErrors.js +1 -14
  46. package/dist/core/SessionErrors.js.map +1 -1
  47. package/dist/core/SessionLock.d.ts +4 -5
  48. package/dist/core/SessionLock.d.ts.map +1 -1
  49. package/dist/core/SessionLock.js +5 -10
  50. package/dist/core/SessionLock.js.map +1 -1
  51. package/dist/core/SessionManager.d.ts +0 -2
  52. package/dist/core/SessionManager.d.ts.map +1 -1
  53. package/dist/core/SessionManager.js +3 -5
  54. package/dist/core/SessionManager.js.map +1 -1
  55. package/dist/core/SessionResetCoordinator.d.ts +10 -7
  56. package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
  57. package/dist/core/SessionResetCoordinator.js +10 -28
  58. package/dist/core/SessionResetCoordinator.js.map +1 -1
  59. package/dist/core/ThoughtEvaluator.d.ts +5 -5
  60. package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
  61. package/dist/core/ThoughtEvaluator.js +4 -40
  62. package/dist/core/ThoughtEvaluator.js.map +1 -1
  63. package/dist/core/ThoughtProcessor.d.ts +10 -3
  64. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  65. package/dist/core/ThoughtProcessor.js +34 -38
  66. package/dist/core/ThoughtProcessor.js.map +1 -1
  67. package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
  68. package/dist/core/VerificationOutcomeAdmission.js +5 -7
  69. package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
  70. package/dist/core/evaluator/Calibrator.d.ts +1 -1
  71. package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
  72. package/dist/core/evaluator/Calibrator.js +2 -5
  73. package/dist/core/evaluator/Calibrator.js.map +1 -1
  74. package/dist/core/evaluator/internals.d.ts +0 -4
  75. package/dist/core/evaluator/internals.d.ts.map +1 -1
  76. package/dist/core/evaluator/internals.js +1 -3
  77. package/dist/core/evaluator/internals.js.map +1 -1
  78. package/dist/core/graph/Edge.d.ts +1 -1
  79. package/dist/core/graph/EdgeEmitter.d.ts +2 -4
  80. package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
  81. package/dist/core/graph/EdgeEmitter.js +2 -4
  82. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  83. package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
  84. package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
  85. package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
  86. package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
  87. package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
  88. package/dist/core/thought.d.ts +2 -1
  89. package/dist/core/thought.d.ts.map +1 -1
  90. package/dist/errors.d.ts +4 -20
  91. package/dist/errors.d.ts.map +1 -1
  92. package/dist/errors.js +2 -28
  93. package/dist/errors.js.map +1 -1
  94. package/dist/lib.d.ts +13 -20
  95. package/dist/lib.d.ts.map +1 -1
  96. package/dist/lib.js +4 -7
  97. package/dist/lib.js.map +1 -1
  98. package/dist/logger/NullLogger.d.ts +9 -11
  99. package/dist/logger/NullLogger.d.ts.map +1 -1
  100. package/dist/logger/NullLogger.js.map +1 -1
  101. package/dist/persistence/FilePersistence.d.ts +3 -12
  102. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  103. package/dist/persistence/FilePersistence.js +9 -61
  104. package/dist/persistence/FilePersistence.js.map +1 -1
  105. package/dist/persistence/FileSnapshotV2.d.ts +2 -2
  106. package/dist/persistence/FileSnapshotV2.js +2 -2
  107. package/dist/persistence/FileSnapshotV2.js.map +1 -1
  108. package/dist/persistence/FileWriter.d.ts +1 -0
  109. package/dist/persistence/FileWriter.d.ts.map +1 -1
  110. package/dist/persistence/FileWriter.js +3 -3
  111. package/dist/persistence/FileWriter.js.map +1 -1
  112. package/dist/persistence/MemoryPersistence.d.ts +5 -15
  113. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  114. package/dist/persistence/MemoryPersistence.js +6 -40
  115. package/dist/persistence/MemoryPersistence.js.map +1 -1
  116. package/dist/persistence/PersistenceCodec.js +1 -3
  117. package/dist/persistence/PersistenceCodec.js.map +1 -1
  118. package/dist/persistence/PersistenceErrors.d.ts +0 -6
  119. package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
  120. package/dist/persistence/PersistenceErrors.js +1 -9
  121. package/dist/persistence/PersistenceErrors.js.map +1 -1
  122. package/dist/persistence/PersistenceScope.d.ts.map +1 -1
  123. package/dist/persistence/PersistenceScope.js +2 -2
  124. package/dist/persistence/PersistenceScope.js.map +1 -1
  125. package/dist/persistence/SqlitePersistence.d.ts +3 -10
  126. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  127. package/dist/persistence/SqlitePersistence.js +2 -26
  128. package/dist/persistence/SqlitePersistence.js.map +1 -1
  129. package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
  130. package/dist/persistence/SqliteSchemaV2.js +3 -12
  131. package/dist/persistence/SqliteSchemaV2.js.map +1 -1
  132. package/dist/pool/ConnectionPool.d.ts +3 -12
  133. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  134. package/dist/pool/ConnectionPool.js +5 -8
  135. package/dist/pool/ConnectionPool.js.map +1 -1
  136. package/dist/pool/IConnectionPool.d.ts +3 -9
  137. package/dist/pool/IConnectionPool.d.ts.map +1 -1
  138. package/dist/registry/SkillRegistry.d.ts +1 -7
  139. package/dist/registry/SkillRegistry.d.ts.map +1 -1
  140. package/dist/registry/SkillRegistry.js +0 -15
  141. package/dist/registry/SkillRegistry.js.map +1 -1
  142. package/dist/registry/ToolRegistry.d.ts +1 -9
  143. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  144. package/dist/registry/ToolRegistry.js +0 -21
  145. package/dist/registry/ToolRegistry.js.map +1 -1
  146. package/dist/schema.d.ts +2 -1
  147. package/dist/schema.d.ts.map +1 -1
  148. package/dist/schema.js +3 -3
  149. package/dist/schema.js.map +1 -1
  150. package/dist/transport/BaseTransport.d.ts +0 -9
  151. package/dist/transport/BaseTransport.d.ts.map +1 -1
  152. package/dist/transport/BaseTransport.js +0 -11
  153. package/dist/transport/BaseTransport.js.map +1 -1
  154. package/dist/watchers/SkillWatcher.d.ts.map +1 -1
  155. package/dist/watchers/SkillWatcher.js +1 -1
  156. package/dist/watchers/SkillWatcher.js.map +1 -1
  157. package/package.json +1 -1
  158. package/dist/contracts/PersistenceBackend.js.map +0 -1
  159. package/dist/persistence/FileLegacyImport.d.ts +0 -2
  160. package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
  161. package/dist/persistence/FileLegacyImport.js +0 -183
  162. package/dist/persistence/FileLegacyImport.js.map +0 -1
  163. package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
  164. package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
  165. package/dist/persistence/SessionScopedPersistence.js +0 -9
  166. package/dist/persistence/SessionScopedPersistence.js.map +0 -1
  167. package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
  168. package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
  169. package/dist/persistence/SqliteLegacyImport.js +0 -136
  170. package/dist/persistence/SqliteLegacyImport.js.map +0 -1
  171. package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
  172. package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
  173. package/dist/persistence/SqliteLegacySchema.js +0 -72
  174. package/dist/persistence/SqliteLegacySchema.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"core/InputNormalizer.js","sources":["../../src/core/InputNormalizer.ts"],"sourcesContent":["/**\n * Input normalization for common LLM field name mistakes.\n *\n * This module provides normalization logic to handle common mistakes\n * that LLMs make when generating field names, such as using singular\n * instead of plural forms (e.g., `recommended_tool` vs `recommended_tools`).\n *\n * It also fills in sensible defaults for missing fields in `previous_steps`,\n * which LLMs naturally provide as partial/skeletal data (historical context).\n *\n * @module processor\n */\n\nimport { ValidationError } from '../errors.js';\nimport {\n\tsanitizeString,\n\tsanitizeRationale,\n\tsanitizeStepField,\n\tsanitizeSuggestedInputs,\n} from '../sanitize.js';\nimport type { ThoughtData } from './thought.js';\nimport { SESSION_ID_PATTERN, MAX_SESSION_ID_LENGTH } from './ids.js';\nimport { asBranchId, asSessionId, generateThoughtId, type BranchId } from '../contracts/ids.js';\n\n/**\n * Default values for missing partial recommendation fields.\n *\n * Shared between tool and skill recommendations (identical defaults).\n */\nconst DEFAULT_RECOMMENDATION_CONFIDENCE = 0.5;\nconst DEFAULT_RECOMMENDATION_PRIORITY = 999;\nconst DEFAULT_RECOMMENDATION_RATIONALE = '';\nconst DEFAULT_STEP_OUTCOME = '';\n\n/**\n * Recursively sanitizes all string values within an unknown structure.\n * Walks into plain objects and arrays to reach deeply nested strings.\n * Non-plain objects (Date, RegExp, etc.) are returned as-is.\n *\n * @param value - The value to sanitize recursively\n * @returns The sanitized value with all nested strings cleaned\n *\n * @example\n * ```typescript\n * sanitizeRecursive('<script>x</script>'); // 'x'\n * sanitizeRecursive({ a: { b: '<iframe>y' } }); // { a: { b: 'y' } }\n * sanitizeRecursive(['a\\x00b', 42]); // ['ab', 42]\n * ```\n */\nexport function sanitizeRecursive(value: unknown): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn value;\n\t}\n\tif (typeof value === 'string') {\n\t\treturn sanitizeString(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => sanitizeRecursive(item));\n\t}\n\tif (typeof value === 'object') {\n\t\t// Only recurse into plain objects — skip Date, RegExp, Map, Set, etc.\n\t\tconst proto = Object.getPrototypeOf(value);\n\t\tif (proto !== Object.prototype && proto !== null) {\n\t\t\treturn value;\n\t\t}\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n\t\t\tresult[key] = sanitizeRecursive(val);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\n/**\n * Valid branch ID pattern: alphanumeric, hyphens, underscores only.\n * Prevents path traversal attacks by rejecting special characters like / . \\ etc.\n */\nconst BRANCH_ID_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;\n\n/**\n * Sanitizes and validates a branch ID to prevent path traversal attacks.\n *\n * @param branchId - The branch ID to sanitize\n * @returns The sanitized branch ID\n * @throws ValidationError if the branch ID contains invalid characters\n *\n * @example\n * ```typescript\n * sanitizeBranchId('my-branch_01'); // 'my-branch_01'\n * sanitizeBranchId('../etc/passwd'); // throws ValidationError\n * ```\n */\nexport function sanitizeBranchId(branchId: string): BranchId {\n\t// Validate format\n\tif (!BRANCH_ID_PATTERN.test(branchId)) {\n\t\tthrow new ValidationError(\n\t\t\t'branch_id',\n\t\t\t'Invalid format - must be 1-64 alphanumeric characters, hyphens, or underscores only'\n\t\t);\n\t}\n\treturn asBranchId(branchId);\n}\n\n/**\n * Sanitizes and validates a session ID.\n *\n * @param sessionId - The session ID to sanitize\n * @returns The sanitized session ID, or undefined if invalid after sanitization\n *\n * @example\n * ```typescript\n * sanitizeSessionId('analysis-task-42'); // 'analysis-task-42'\n * sanitizeSessionId('bad session!'); // undefined (stripped)\n * ```\n */\nexport function sanitizeSessionId(sessionId: string): string | undefined {\n\t// First sanitize control characters\n\tconst cleaned = sanitizeString(sessionId);\n\t// Validate format after sanitization\n\tif (cleaned.length > MAX_SESSION_ID_LENGTH || !SESSION_ID_PATTERN.test(cleaned)) {\n\t\treturn undefined;\n\t}\n\treturn cleaned;\n}\n\n/**\n * Normalizes a recommendation object (tool or skill) with default values.\n *\n * Fills in sensible defaults for missing optional fields:\n * - `confidence`: 0.5\n * - `priority`: 999\n * - `rationale`: empty string\n *\n * @param rec - The recommendation object to normalize\n * @returns The normalized recommendation with defaults filled in\n *\n * @example\n * ```typescript\n * const input = { tool_name: 'Read', rationale: 'Read the file' };\n * const normalized = normalizeRecommendation(input);\n * // { tool_name: 'Read', rationale: 'Read the file', confidence: 0.5, priority: 999 }\n * ```\n */\nfunction normalizeRecommendation(rec: Record<string, unknown>): Record<string, unknown> {\n\tconst normalized: Record<string, unknown> = { ...rec };\n\n\t// Fill in default confidence if missing\n\tif (!('confidence' in normalized) || normalized.confidence === undefined) {\n\t\tnormalized.confidence = DEFAULT_RECOMMENDATION_CONFIDENCE;\n\t}\n\n\t// Fill in default priority if missing\n\tif (!('priority' in normalized) || normalized.priority === undefined) {\n\t\tnormalized.priority = DEFAULT_RECOMMENDATION_PRIORITY;\n\t}\n\n\t// Fill in default rationale if missing\n\t// Fill in default rationale if missing, otherwise sanitize urgency phrases + cap length\n\tif (!('rationale' in normalized) || normalized.rationale === undefined) {\n\t\tnormalized.rationale = DEFAULT_RECOMMENDATION_RATIONALE;\n\t} else if (typeof normalized.rationale === 'string') {\n\t\tnormalized.rationale = sanitizeRationale(normalized.rationale);\n\t}\n\t// Sanitize suggested_inputs: enforce flat primitives, key cap, value-length cap\n\tif (\n\t\tnormalized.suggested_inputs &&\n\t\ttypeof normalized.suggested_inputs === 'object' &&\n\t\t!Array.isArray(normalized.suggested_inputs)\n\t) {\n\t\tnormalized.suggested_inputs = sanitizeSuggestedInputs(\n\t\t\tnormalized.suggested_inputs as Record<string, unknown>\n\t\t);\n\t}\n\n\treturn normalized;\n}\n/**\n * Normalizes step recommendation objects.\n *\n * Handles common field name mistakes:\n * - `recommended_tool` (singular) → `recommended_tools` (plural)\n * - `recommended_skill` (singular) → `recommended_skills` (plural)\n *\n * Also normalizes tool recommendations within the step to fill in defaults.\n *\n * @param step - The step recommendation to normalize\n * @param lenient - Whether to use lenient mode (fill in defaults for missing fields)\n * @returns The normalized step recommendation\n *\n * @example\n * ```typescript\n * // Strict mode (for current_step)\n * const input = {\n * step_description: 'Analyze data',\n * recommended_tool: [{ tool_name: 'Read', confidence: 0.9, rationale: 'test', priority: 1 }],\n * expected_outcome: 'Data analyzed'\n * };\n * const normalized = normalizeStepRecommendation(input, false);\n * // normalized.recommended_tools exists (plural form)\n *\n * // Lenient mode (for previous_steps)\n * const partialInput = {\n * step_description: 'Read file',\n * recommended_tools: [{ tool_name: 'Read', rationale: 'Read file' }]\n * };\n * const normalized = normalizeStepRecommendation(partialInput, true);\n * // confidence: 0.5, priority: 999, expected_outcome: '' filled in\n * ```\n */\nfunction normalizeStepRecommendation(\n\tstep: Record<string, unknown>,\n\tlenient: boolean\n): Record<string, unknown> {\n\tconst normalized: Record<string, unknown> = { ...step };\n\n\t// Transform `recommended_tool` (singular) → `recommended_tools` (plural)\n\tif ('recommended_tool' in normalized && !('recommended_tools' in normalized)) {\n\t\tnormalized.recommended_tools = normalized.recommended_tool;\n\t\tdelete normalized.recommended_tool;\n\t}\n\n\t// Transform `recommended_skill` (singular) → `recommended_skills` (plural)\n\tif ('recommended_skill' in normalized && !('recommended_skills' in normalized)) {\n\t\tnormalized.recommended_skills = normalized.recommended_skill;\n\t\tdelete normalized.recommended_skill;\n\t}\n\n\t// Normalize recommended_tools array if present\n\tif (Array.isArray(normalized.recommended_tools)) {\n\t\tnormalized.recommended_tools = normalized.recommended_tools.map((tool) =>\n\t\t\ttypeof tool === 'object' && tool !== null\n\t\t\t\t? normalizeRecommendation(tool as Record<string, unknown>)\n\t\t\t\t: tool\n\t\t);\n\t}\n\n\t// Normalize recommended_skills array if present\n\tif (Array.isArray(normalized.recommended_skills)) {\n\t\tnormalized.recommended_skills = normalized.recommended_skills.map((skill) =>\n\t\t\ttypeof skill === 'object' && skill !== null\n\t\t\t\t? normalizeRecommendation(skill as Record<string, unknown>)\n\t\t\t\t: skill\n\t\t);\n\t}\n\t// Sanitize step-level string fields for prompt injection prevention\n\tif (typeof normalized.step_description === 'string') {\n\t\tnormalized.step_description = sanitizeStepField(normalized.step_description);\n\t}\n\tif (typeof normalized.expected_outcome === 'string') {\n\t\tnormalized.expected_outcome = sanitizeStepField(normalized.expected_outcome);\n\t}\n\tif (Array.isArray(normalized.next_step_conditions)) {\n\t\tnormalized.next_step_conditions = normalized.next_step_conditions.map((cond: unknown) =>\n\t\t\ttypeof cond === 'string' ? sanitizeStepField(cond) : cond\n\t\t);\n\t}\n\t// In lenient mode, fill in default expected_outcome if missing\n\tif (lenient && !('expected_outcome' in normalized)) {\n\t\tnormalized.expected_outcome = DEFAULT_STEP_OUTCOME;\n\t}\n\n\treturn normalized;\n}\n\n/**\n * Normalizes reasoning-specific fields on a thought input object.\n * Always applies reasoning normalization — reasoning is the default pipeline.\n * Applies the following normalization rules:\n * - Defaults `thought_type` to `'regular'` if not provided\n * - Clamps `quality_score` to [0, 1] range\n * - Clamps `confidence` to [0, 1] range\n * - Sanitizes `hypothesis_id` using `sanitizeBranchId` pattern\n * - Filters `synthesis_sources` to positive integers only\n * - Filters `merge_from_thoughts` to positive integers only\n * - Sanitizes each entry in `merge_branch_ids`\n * - Defaults `reasoning_depth` to `'moderate'` for hypothesis/verification types\n *\n * @param input - The mutable normalized input object to apply reasoning defaults to\n *\n * @example\n * ```typescript\n * const input: Record<string, unknown> = { thought_type: 'hypothesis', quality_score: 1.5 };\n * normalizeReasoningFields(input);\n * // input.quality_score === 1, input.reasoning_depth === 'moderate'\n * ```\n */\nexport function normalizeReasoningFields(input: Record<string, unknown>): void {\n\t// Always apply reasoning field normalization — reasoning is the default pipeline\n\t// Default thought_type to 'regular'\n\n\tif (!('thought_type' in input) || input.thought_type === undefined) {\n\t\tinput.thought_type = 'regular';\n\t}\n\n\t// Clamp quality_score to [0, 1]\n\tif (typeof input.quality_score === 'number') {\n\t\tinput.quality_score = Math.max(0, Math.min(1, input.quality_score));\n\t}\n\n\t// Clamp confidence to [0, 1]\n\tif (typeof input.confidence === 'number') {\n\t\tinput.confidence = Math.max(0, Math.min(1, input.confidence));\n\t}\n\n\t// Sanitize hypothesis_id (same rules as branch_id)\n\tif (typeof input.hypothesis_id === 'string') {\n\t\tinput.hypothesis_id = sanitizeBranchId(input.hypothesis_id);\n\t}\n\n\t// Filter synthesis_sources to positive integers only\n\tif (Array.isArray(input.synthesis_sources)) {\n\t\tinput.synthesis_sources = input.synthesis_sources.filter(\n\t\t\t(v: unknown) => typeof v === 'number' && Number.isInteger(v) && v > 0\n\t\t);\n\t}\n\n\t// Filter merge_from_thoughts to positive integers only\n\tif (Array.isArray(input.merge_from_thoughts)) {\n\t\tinput.merge_from_thoughts = input.merge_from_thoughts.filter(\n\t\t\t(v: unknown) => typeof v === 'number' && Number.isInteger(v) && v > 0\n\t\t);\n\t}\n\n\t// Sanitize merge_branch_ids entries\n\tif (Array.isArray(input.merge_branch_ids)) {\n\t\tinput.merge_branch_ids = input.merge_branch_ids.map((id: unknown) => {\n\t\t\tif (typeof id === 'string') {\n\t\t\t\treturn sanitizeBranchId(id);\n\t\t\t}\n\t\t\treturn id;\n\t\t});\n\t}\n\n\t// Default reasoning_depth to 'moderate' for hypothesis/verification types\n\tif (\n\t\t(input.thought_type === 'hypothesis' || input.thought_type === 'verification') &&\n\t\t!('reasoning_depth' in input)\n\t) {\n\t\tinput.reasoning_depth = 'moderate';\n\t}\n}\n\n/**\n * Normalizes thought input data by fixing common LLM field name mistakes.\n *\n * This function handles cases where LLMs incorrectly use singular forms\n * of field names that should be plural. It applies normalization to both\n * `current_step` and `previous_steps` fields.\n *\n * The normalization is applied BEFORE schema validation, allowing the\n * strict Valibot schema to remain correct while still being tolerant\n * of common LLM mistakes.\n *\n * @param input - The raw thought input data to normalize\n * @returns Normalized thought data with correct field names\n *\n * @remarks\n * **Normalization Rules:**\n * - `recommended_tool` (singular) → `recommended_tools` (plural)\n * - `recommended_skill` (singular) → `recommended_skills` (plural)\n * - Applied to `current_step` if present (strict mode)\n * - Applied to all items in `previous_steps` if present (lenient mode with defaults)\n *\n * **Design Rationale:**\n * LLMs sometimes use singular field names even when the schema explicitly\n * defines plural forms. Rather than forcing the LLM to be perfect (which\n * leads to cryptic validation errors), we normalize the input to handle\n * these common mistakes gracefully.\n *\n * Additionally, LLMs naturally provide complete data for `current_step`\n * but only partial/skeletal data for `previous_steps` (historical context).\n * The lenient mode for `previous_steps` fills in sensible defaults:\n * - `confidence`: 0.5 for missing tool recommendation confidence\n * - `priority`: 999 for missing tool recommendation priority\n * - `rationale`: empty string for missing tool recommendation rationale\n * - `expected_outcome`: empty string for missing step expected outcome\n *\n * @example\n * ```typescript\n * const input = {\n * thought: 'I need to analyze the data',\n * thought_number: 1,\n * total_thoughts: 3,\n * next_thought_needed: true,\n * current_step: {\n * step_description: 'Read the data file',\n * recommended_tool: [{ tool_name: 'Read', confidence: 0.9, rationale: 'test', priority: 1 }],\n * expected_outcome: 'Data loaded'\n * },\n * previous_steps: [{\n * step_description: 'Previous step',\n * recommended_tools: [{ tool_name: 'Grep', rationale: 'Search code' }]\n * }]\n * };\n *\n * const normalized = normalizeInput(input);\n * // current_step: recommended_tools exists (plural form)\n * // previous_steps[0]: confidence=0.5, priority=999, expected_outcome='' filled in\n * ```\n */\nexport function normalizeInput(input: unknown): ThoughtData {\n\tif (typeof input !== 'object' || input === null) {\n\t\treturn input as ThoughtData;\n\t}\n\n\tconst normalized = { ...input } as Record<string, unknown>;\n\n\t// Normalize current_step if present (strict mode - no defaults)\n\tif (normalized.current_step && typeof normalized.current_step === 'object') {\n\t\tnormalized.current_step = normalizeStepRecommendation(\n\t\t\tnormalized.current_step as Record<string, unknown>,\n\t\t\tfalse // strict mode\n\t\t);\n\t}\n\n\t// Normalize all items in previous_steps if present (lenient mode - with defaults)\n\tif (Array.isArray(normalized.previous_steps) && normalized.previous_steps.length > 0) {\n\t\tnormalized.previous_steps = normalized.previous_steps.map((step) =>\n\t\t\ttypeof step === 'object' && step !== null\n\t\t\t\t? normalizeStepRecommendation(step as Record<string, unknown>, true) // lenient mode\n\t\t\t\t: step\n\t\t);\n\t}\n\n\t// Sanitize branch_id to prevent path traversal attacks\n\tif (typeof normalized.branch_id === 'string') {\n\t\tnormalized.branch_id = sanitizeBranchId(normalized.branch_id);\n\t}\n\n\t// Explicit identity is validated, never sanitized into another namespace.\n\tif (typeof normalized.session_id === 'string') {\n\t\tnormalized.session_id = asSessionId(normalized.session_id);\n\t}\n\n\tif (typeof normalized.register_branch_id === 'string') {\n\t\tnormalized.register_branch_id = sanitizeBranchId(normalized.register_branch_id);\n\t}\n\n\t// Auto-generate id if not provided (for DAG node identity)\n\tif (!normalized.id || typeof normalized.id !== 'string') {\n\t\tnormalized.id = generateThoughtId();\n\t}\n\n\t// Normalize reasoning fields\n\tnormalizeReasoningFields(normalized);\n\n\t// Sanitize meta_observation for prompt injection prevention\n\tif (typeof normalized.meta_observation === 'string') {\n\t\tnormalized.meta_observation = sanitizeStepField(normalized.meta_observation);\n\t}\n\n\t// Sanitize all free-text string fields recursively (dangerous HTML tags + null bytes)\n\t// This was moved from schema transforms because v.transform() cannot be converted to JSON Schema\n\tconst sanitized = sanitizeRecursive(normalized);\n\n\treturn sanitized as ThoughtData;\n}\n"],"names":["DEFAULT_RECOMMENDATION_CONFIDENCE","DEFAULT_RECOMMENDATION_PRIORITY","DEFAULT_RECOMMENDATION_RATIONALE","DEFAULT_STEP_OUTCOME","sanitizeRecursive","value","sanitizeString","Array","item","proto","Object","result","key","val","BRANCH_ID_PATTERN","sanitizeBranchId","branchId","ValidationError","asBranchId","sanitizeSessionId","sessionId","cleaned","MAX_SESSION_ID_LENGTH","SESSION_ID_PATTERN","normalizeRecommendation","rec","normalized","undefined","sanitizeRationale","sanitizeSuggestedInputs","normalizeStepRecommendation","step","lenient","tool","skill","sanitizeStepField","cond","normalizeReasoningFields","input","Math","v","Number","id","normalizeInput","asSessionId","generateThoughtId","sanitized"],"mappings":";;;;AA6BA,MAAMA,oCAAoC;AAC1C,MAAMC,kCAAkC;AACxC,MAAMC,mCAAmC;AACzC,MAAMC,uBAAuB;AAiBtB,SAASC,kBAAkBC,KAAc;IAC/C,IAAIA,QAAAA,OACH,OAAOA;IAER,IAAI,AAAiB,YAAjB,OAAOA,OACV,OAAOC,eAAeD;IAEvB,IAAIE,MAAM,OAAO,CAACF,QACjB,OAAOA,MAAM,GAAG,CAAC,CAACG,OAASJ,kBAAkBI;IAE9C,IAAI,AAAiB,YAAjB,OAAOH,OAAoB;QAE9B,MAAMI,QAAQC,OAAO,cAAc,CAACL;QACpC,IAAII,UAAUC,OAAO,SAAS,IAAID,AAAU,SAAVA,OACjC,OAAOJ;QAER,MAAMM,SAAkC,CAAC;QACzC,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIH,OAAO,OAAO,CAACL,OACvCM,MAAM,CAACC,IAAI,GAAGR,kBAAkBS;QAEjC,OAAOF;IACR;IACA,OAAON;AACR;AAMA,MAAMS,oBAAoB;AAenB,SAASC,iBAAiBC,QAAgB;IAEhD,IAAI,CAACF,kBAAkB,IAAI,CAACE,WAC3B,MAAM,IAAIC,gBACT,aACA;IAGF,OAAOC,WAAWF;AACnB;AAcO,SAASG,kBAAkBC,SAAiB;IAElD,MAAMC,UAAUf,eAAec;IAE/B,IAAIC,QAAQ,MAAM,GAAGC,yBAAyB,CAACC,mBAAmB,IAAI,CAACF,UACtE;IAED,OAAOA;AACR;AAoBA,SAASG,wBAAwBC,GAA4B;IAC5D,MAAMC,aAAsC;QAAE,GAAGD,GAAG;IAAC;IAGrD,IAAI,CAAE,iBAAgBC,UAAS,KAAMA,AAA0BC,WAA1BD,WAAW,UAAU,EACzDA,WAAW,UAAU,GAAG1B;IAIzB,IAAI,CAAE,eAAc0B,UAAS,KAAMA,AAAwBC,WAAxBD,WAAW,QAAQ,EACrDA,WAAW,QAAQ,GAAGzB;IAKvB,IAAI,AAAE,eAAeyB,cAAeA,AAAyBC,WAAzBD,WAAW,SAAS,EAEjD;QAAA,IAAI,AAAgC,YAAhC,OAAOA,WAAW,SAAS,EACrCA,WAAW,SAAS,GAAGE,kBAAkBF,WAAW,SAAS;IAC9D,OAHCA,WAAW,SAAS,GAAGxB;IAKxB,IACCwB,WAAW,gBAAgB,IAC3B,AAAuC,YAAvC,OAAOA,WAAW,gBAAgB,IAClC,CAACnB,MAAM,OAAO,CAACmB,WAAW,gBAAgB,GAE1CA,WAAW,gBAAgB,GAAGG,wBAC7BH,WAAW,gBAAgB;IAI7B,OAAOA;AACR;AAkCA,SAASI,4BACRC,IAA6B,EAC7BC,OAAgB;IAEhB,MAAMN,aAAsC;QAAE,GAAGK,IAAI;IAAC;IAGtD,IAAI,sBAAsBL,cAAc,CAAE,wBAAuBA,UAAS,GAAI;QAC7EA,WAAW,iBAAiB,GAAGA,WAAW,gBAAgB;QAC1D,OAAOA,WAAW,gBAAgB;IACnC;IAGA,IAAI,uBAAuBA,cAAc,CAAE,yBAAwBA,UAAS,GAAI;QAC/EA,WAAW,kBAAkB,GAAGA,WAAW,iBAAiB;QAC5D,OAAOA,WAAW,iBAAiB;IACpC;IAGA,IAAInB,MAAM,OAAO,CAACmB,WAAW,iBAAiB,GAC7CA,WAAW,iBAAiB,GAAGA,WAAW,iBAAiB,CAAC,GAAG,CAAC,CAACO,OAChE,AAAgB,YAAhB,OAAOA,QAAqBA,AAAS,SAATA,OACzBT,wBAAwBS,QACxBA;IAKL,IAAI1B,MAAM,OAAO,CAACmB,WAAW,kBAAkB,GAC9CA,WAAW,kBAAkB,GAAGA,WAAW,kBAAkB,CAAC,GAAG,CAAC,CAACQ,QAClE,AAAiB,YAAjB,OAAOA,SAAsBA,AAAU,SAAVA,QAC1BV,wBAAwBU,SACxBA;IAIL,IAAI,AAAuC,YAAvC,OAAOR,WAAW,gBAAgB,EACrCA,WAAW,gBAAgB,GAAGS,kBAAkBT,WAAW,gBAAgB;IAE5E,IAAI,AAAuC,YAAvC,OAAOA,WAAW,gBAAgB,EACrCA,WAAW,gBAAgB,GAAGS,kBAAkBT,WAAW,gBAAgB;IAE5E,IAAInB,MAAM,OAAO,CAACmB,WAAW,oBAAoB,GAChDA,WAAW,oBAAoB,GAAGA,WAAW,oBAAoB,CAAC,GAAG,CAAC,CAACU,OACtE,AAAgB,YAAhB,OAAOA,OAAoBD,kBAAkBC,QAAQA;IAIvD,IAAIJ,WAAW,CAAE,uBAAsBN,UAAS,GAC/CA,WAAW,gBAAgB,GAAGvB;IAG/B,OAAOuB;AACR;AAwBO,SAASW,yBAAyBC,KAA8B;IAItE,IAAI,CAAE,mBAAkBA,KAAI,KAAMA,AAAuBX,WAAvBW,MAAM,YAAY,EACnDA,MAAM,YAAY,GAAG;IAItB,IAAI,AAA+B,YAA/B,OAAOA,MAAM,aAAa,EAC7BA,MAAM,aAAa,GAAGC,KAAK,GAAG,CAAC,GAAGA,KAAK,GAAG,CAAC,GAAGD,MAAM,aAAa;IAIlE,IAAI,AAA4B,YAA5B,OAAOA,MAAM,UAAU,EAC1BA,MAAM,UAAU,GAAGC,KAAK,GAAG,CAAC,GAAGA,KAAK,GAAG,CAAC,GAAGD,MAAM,UAAU;IAI5D,IAAI,AAA+B,YAA/B,OAAOA,MAAM,aAAa,EAC7BA,MAAM,aAAa,GAAGvB,iBAAiBuB,MAAM,aAAa;IAI3D,IAAI/B,MAAM,OAAO,CAAC+B,MAAM,iBAAiB,GACxCA,MAAM,iBAAiB,GAAGA,MAAM,iBAAiB,CAAC,MAAM,CACvD,CAACE,IAAe,AAAa,YAAb,OAAOA,KAAkBC,OAAO,SAAS,CAACD,MAAMA,IAAI;IAKtE,IAAIjC,MAAM,OAAO,CAAC+B,MAAM,mBAAmB,GAC1CA,MAAM,mBAAmB,GAAGA,MAAM,mBAAmB,CAAC,MAAM,CAC3D,CAACE,IAAe,AAAa,YAAb,OAAOA,KAAkBC,OAAO,SAAS,CAACD,MAAMA,IAAI;IAKtE,IAAIjC,MAAM,OAAO,CAAC+B,MAAM,gBAAgB,GACvCA,MAAM,gBAAgB,GAAGA,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAACI;QACpD,IAAI,AAAc,YAAd,OAAOA,IACV,OAAO3B,iBAAiB2B;QAEzB,OAAOA;IACR;IAID,IACEJ,AAAAA,CAAAA,AAAuB,iBAAvBA,MAAM,YAAY,IAAqBA,AAAuB,mBAAvBA,MAAM,YAAY,AAAkB,KAC5E,CAAE,sBAAqBA,KAAI,GAE3BA,MAAM,eAAe,GAAG;AAE1B;AA4DO,SAASK,eAAeL,KAAc;IAC5C,IAAI,AAAiB,YAAjB,OAAOA,SAAsBA,AAAU,SAAVA,OAChC,OAAOA;IAGR,MAAMZ,aAAa;QAAE,GAAGY,KAAK;IAAC;IAG9B,IAAIZ,WAAW,YAAY,IAAI,AAAmC,YAAnC,OAAOA,WAAW,YAAY,EAC5DA,WAAW,YAAY,GAAGI,4BACzBJ,WAAW,YAAY,EACvB;IAKF,IAAInB,MAAM,OAAO,CAACmB,WAAW,cAAc,KAAKA,WAAW,cAAc,CAAC,MAAM,GAAG,GAClFA,WAAW,cAAc,GAAGA,WAAW,cAAc,CAAC,GAAG,CAAC,CAACK,OAC1D,AAAgB,YAAhB,OAAOA,QAAqBA,AAAS,SAATA,OACzBD,4BAA4BC,MAAiC,QAC7DA;IAKL,IAAI,AAAgC,YAAhC,OAAOL,WAAW,SAAS,EAC9BA,WAAW,SAAS,GAAGX,iBAAiBW,WAAW,SAAS;IAI7D,IAAI,AAAiC,YAAjC,OAAOA,WAAW,UAAU,EAC/BA,WAAW,UAAU,GAAGkB,YAAYlB,WAAW,UAAU;IAG1D,IAAI,AAAyC,YAAzC,OAAOA,WAAW,kBAAkB,EACvCA,WAAW,kBAAkB,GAAGX,iBAAiBW,WAAW,kBAAkB;IAI/E,IAAI,CAACA,WAAW,EAAE,IAAI,AAAyB,YAAzB,OAAOA,WAAW,EAAE,EACzCA,WAAW,EAAE,GAAGmB;IAIjBR,yBAAyBX;IAGzB,IAAI,AAAuC,YAAvC,OAAOA,WAAW,gBAAgB,EACrCA,WAAW,gBAAgB,GAAGS,kBAAkBT,WAAW,gBAAgB;IAK5E,MAAMoB,YAAY1C,kBAAkBsB;IAEpC,OAAOoB;AACR"}
1
+ {"version":3,"file":"core/InputNormalizer.js","sources":["../../src/core/InputNormalizer.ts"],"sourcesContent":["/**\n * Input normalization for the documented sequential-thinking contract.\n *\n * This module fills in sensible defaults for missing fields in `previous_steps`,\n * which LLMs naturally provide as partial/skeletal data (historical context).\n *\n * @module processor\n */\n\nimport { ValidationError } from '../errors.js';\nimport {\n\tsanitizeString,\n\tsanitizeRationale,\n\tsanitizeStepField,\n\tsanitizeSuggestedInputs,\n} from '../sanitize.js';\nimport type { ThoughtData } from './thought.js';\nimport { SESSION_ID_PATTERN, MAX_SESSION_ID_LENGTH } from './ids.js';\nimport { asBranchId, asSessionId, generateThoughtId, type BranchId } from '../contracts/ids.js';\n\n/**\n * Default values for missing partial recommendation fields.\n *\n * Shared between tool and skill recommendations (identical defaults).\n */\nconst DEFAULT_RECOMMENDATION_CONFIDENCE = 0.5;\nconst DEFAULT_RECOMMENDATION_PRIORITY = 999;\nconst DEFAULT_RECOMMENDATION_RATIONALE = '';\nconst DEFAULT_STEP_OUTCOME = '';\n\n/**\n * Recursively sanitizes all string values within an unknown structure.\n * Walks into plain objects and arrays to reach deeply nested strings.\n * Non-plain objects (Date, RegExp, etc.) are returned as-is.\n *\n * @param value - The value to sanitize recursively\n * @returns The sanitized value with all nested strings cleaned\n *\n * @example\n * ```typescript\n * sanitizeRecursive('<script>x</script>'); // 'x'\n * sanitizeRecursive({ a: { b: '<iframe>y' } }); // { a: { b: 'y' } }\n * sanitizeRecursive(['a\\x00b', 42]); // ['ab', 42]\n * ```\n */\nexport function sanitizeRecursive(value: unknown): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn value;\n\t}\n\tif (typeof value === 'string') {\n\t\treturn sanitizeString(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map((item) => sanitizeRecursive(item));\n\t}\n\tif (typeof value === 'object') {\n\t\t// Only recurse into plain objects — skip Date, RegExp, Map, Set, etc.\n\t\tconst proto = Object.getPrototypeOf(value);\n\t\tif (proto !== Object.prototype && proto !== null) {\n\t\t\treturn value;\n\t\t}\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n\t\t\tresult[key] = sanitizeRecursive(val);\n\t\t}\n\t\treturn result;\n\t}\n\treturn value;\n}\n\n/**\n * Valid branch ID pattern: alphanumeric, hyphens, underscores only.\n * Prevents path traversal attacks by rejecting special characters like / . \\ etc.\n */\nconst BRANCH_ID_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;\n\n/**\n * Sanitizes and validates a branch ID to prevent path traversal attacks.\n *\n * @param branchId - The branch ID to sanitize\n * @returns The sanitized branch ID\n * @throws ValidationError if the branch ID contains invalid characters\n *\n * @example\n * ```typescript\n * sanitizeBranchId('my-branch_01'); // 'my-branch_01'\n * sanitizeBranchId('../etc/passwd'); // throws ValidationError\n * ```\n */\nexport function sanitizeBranchId(branchId: string): BranchId {\n\t// Validate format\n\tif (!BRANCH_ID_PATTERN.test(branchId)) {\n\t\tthrow new ValidationError(\n\t\t\t'branch_id',\n\t\t\t'Invalid format - must be 1-64 alphanumeric characters, hyphens, or underscores only'\n\t\t);\n\t}\n\treturn asBranchId(branchId);\n}\n\n/**\n * Sanitizes and validates a session ID.\n *\n * @param sessionId - The session ID to sanitize\n * @returns The sanitized session ID, or undefined if invalid after sanitization\n *\n * @example\n * ```typescript\n * sanitizeSessionId('analysis-task-42'); // 'analysis-task-42'\n * sanitizeSessionId('bad session!'); // undefined (stripped)\n * ```\n */\nexport function sanitizeSessionId(sessionId: string): string | undefined {\n\t// First sanitize control characters\n\tconst cleaned = sanitizeString(sessionId);\n\t// Validate format after sanitization\n\tif (cleaned.length > MAX_SESSION_ID_LENGTH || !SESSION_ID_PATTERN.test(cleaned)) {\n\t\treturn undefined;\n\t}\n\treturn cleaned;\n}\n\n/**\n * Normalizes a recommendation object (tool or skill) with default values.\n *\n * Fills in sensible defaults for missing optional fields:\n * - `confidence`: 0.5\n * - `priority`: 999\n * - `rationale`: empty string\n *\n * @param rec - The recommendation object to normalize\n * @returns The normalized recommendation with defaults filled in\n *\n * @example\n * ```typescript\n * const input = { tool_name: 'Read', rationale: 'Read the file' };\n * const normalized = normalizeRecommendation(input);\n * // { tool_name: 'Read', rationale: 'Read the file', confidence: 0.5, priority: 999 }\n * ```\n */\nfunction normalizeRecommendation(rec: Record<string, unknown>): Record<string, unknown> {\n\tconst normalized: Record<string, unknown> = { ...rec };\n\n\t// Fill in default confidence if missing\n\tif (!('confidence' in normalized) || normalized.confidence === undefined) {\n\t\tnormalized.confidence = DEFAULT_RECOMMENDATION_CONFIDENCE;\n\t}\n\n\t// Fill in default priority if missing\n\tif (!('priority' in normalized) || normalized.priority === undefined) {\n\t\tnormalized.priority = DEFAULT_RECOMMENDATION_PRIORITY;\n\t}\n\n\t// Fill in default rationale if missing\n\t// Fill in default rationale if missing, otherwise sanitize urgency phrases + cap length\n\tif (!('rationale' in normalized) || normalized.rationale === undefined) {\n\t\tnormalized.rationale = DEFAULT_RECOMMENDATION_RATIONALE;\n\t} else if (typeof normalized.rationale === 'string') {\n\t\tnormalized.rationale = sanitizeRationale(normalized.rationale);\n\t}\n\t// Sanitize suggested_inputs: enforce flat primitives, key cap, value-length cap\n\tif (\n\t\tnormalized.suggested_inputs &&\n\t\ttypeof normalized.suggested_inputs === 'object' &&\n\t\t!Array.isArray(normalized.suggested_inputs)\n\t) {\n\t\tnormalized.suggested_inputs = sanitizeSuggestedInputs(\n\t\t\tnormalized.suggested_inputs as Record<string, unknown>\n\t\t);\n\t}\n\n\treturn normalized;\n}\n/**\n * Normalizes step recommendation objects.\n *\n * Normalizes tool and skill recommendations within the step to fill in defaults.\n *\n * @param step - The step recommendation to normalize\n * @param lenient - Whether to use lenient mode (fill in defaults for missing fields)\n * @returns The normalized step recommendation\n *\n * @example\n * ```typescript\n * // Strict mode (for current_step)\n * const input = {\n * step_description: 'Analyze data',\n * recommended_tools: [{ tool_name: 'Read', confidence: 0.9, rationale: 'test', priority: 1 }],\n * expected_outcome: 'Data analyzed'\n * };\n * const normalized = normalizeStepRecommendation(input, false);\n *\n * // Lenient mode (for previous_steps)\n * const partialInput = {\n * step_description: 'Read file',\n * recommended_tools: [{ tool_name: 'Read', rationale: 'Read file' }]\n * };\n * const normalized = normalizeStepRecommendation(partialInput, true);\n * // confidence: 0.5, priority: 999, expected_outcome: '' filled in\n * ```\n */\nfunction normalizeStepRecommendation(\n\tstep: Record<string, unknown>,\n\tlenient: boolean\n): Record<string, unknown> {\n\tconst normalized: Record<string, unknown> = { ...step };\n\n\t// Normalize recommended_tools array if present\n\tif (Array.isArray(normalized.recommended_tools)) {\n\t\tnormalized.recommended_tools = normalized.recommended_tools.map((tool) =>\n\t\t\ttypeof tool === 'object' && tool !== null\n\t\t\t\t? normalizeRecommendation(tool as Record<string, unknown>)\n\t\t\t\t: tool\n\t\t);\n\t}\n\n\t// Normalize recommended_skills array if present\n\tif (Array.isArray(normalized.recommended_skills)) {\n\t\tnormalized.recommended_skills = normalized.recommended_skills.map((skill) =>\n\t\t\ttypeof skill === 'object' && skill !== null\n\t\t\t\t? normalizeRecommendation(skill as Record<string, unknown>)\n\t\t\t\t: skill\n\t\t);\n\t}\n\t// Sanitize step-level string fields for prompt injection prevention\n\tif (typeof normalized.step_description === 'string') {\n\t\tnormalized.step_description = sanitizeStepField(normalized.step_description);\n\t}\n\tif (typeof normalized.expected_outcome === 'string') {\n\t\tnormalized.expected_outcome = sanitizeStepField(normalized.expected_outcome);\n\t}\n\tif (Array.isArray(normalized.next_step_conditions)) {\n\t\tnormalized.next_step_conditions = normalized.next_step_conditions.map((cond: unknown) =>\n\t\t\ttypeof cond === 'string' ? sanitizeStepField(cond) : cond\n\t\t);\n\t}\n\t// In lenient mode, fill in default expected_outcome if missing\n\tif (lenient && !('expected_outcome' in normalized)) {\n\t\tnormalized.expected_outcome = DEFAULT_STEP_OUTCOME;\n\t}\n\n\treturn normalized;\n}\n\n/**\n * Normalizes reasoning-specific fields on a thought input object.\n * Always applies reasoning normalization — reasoning is the default pipeline.\n * Applies the following normalization rules:\n * - Defaults `thought_type` to `'regular'` if not provided\n * - Clamps `quality_score` to [0, 1] range\n * - Clamps `confidence` to [0, 1] range\n * - Sanitizes `hypothesis_id` using `sanitizeBranchId` pattern\n * - Filters `synthesis_sources` to positive integers only\n * - Filters `merge_from_thoughts` to positive integers only\n * - Sanitizes each entry in `merge_branch_ids`\n * - Defaults `reasoning_depth` to `'moderate'` for hypothesis/verification types\n *\n * @param input - The mutable normalized input object to apply reasoning defaults to\n *\n * @example\n * ```typescript\n * const input: Record<string, unknown> = { thought_type: 'hypothesis', quality_score: 1.5 };\n * normalizeReasoningFields(input);\n * // input.quality_score === 1, input.reasoning_depth === 'moderate'\n * ```\n */\nexport function normalizeReasoningFields(input: Record<string, unknown>): void {\n\t// Always apply reasoning field normalization — reasoning is the default pipeline\n\t// Default thought_type to 'regular'\n\n\tif (!('thought_type' in input) || input.thought_type === undefined) {\n\t\tinput.thought_type = 'regular';\n\t}\n\n\t// Clamp quality_score to [0, 1]\n\tif (typeof input.quality_score === 'number') {\n\t\tinput.quality_score = Math.max(0, Math.min(1, input.quality_score));\n\t}\n\n\t// Clamp confidence to [0, 1]\n\tif (typeof input.confidence === 'number') {\n\t\tinput.confidence = Math.max(0, Math.min(1, input.confidence));\n\t}\n\n\t// Sanitize hypothesis_id (same rules as branch_id)\n\tif (typeof input.hypothesis_id === 'string') {\n\t\tinput.hypothesis_id = sanitizeBranchId(input.hypothesis_id);\n\t}\n\n\t// Filter synthesis_sources to positive integers only\n\tif (Array.isArray(input.synthesis_sources)) {\n\t\tinput.synthesis_sources = input.synthesis_sources.filter(\n\t\t\t(v: unknown) => typeof v === 'number' && Number.isInteger(v) && v > 0\n\t\t);\n\t}\n\n\t// Filter merge_from_thoughts to positive integers only\n\tif (Array.isArray(input.merge_from_thoughts)) {\n\t\tinput.merge_from_thoughts = input.merge_from_thoughts.filter(\n\t\t\t(v: unknown) => typeof v === 'number' && Number.isInteger(v) && v > 0\n\t\t);\n\t}\n\n\t// Sanitize merge_branch_ids entries\n\tif (Array.isArray(input.merge_branch_ids)) {\n\t\tinput.merge_branch_ids = input.merge_branch_ids.map((id: unknown) => {\n\t\t\tif (typeof id === 'string') {\n\t\t\t\treturn sanitizeBranchId(id);\n\t\t\t}\n\t\t\treturn id;\n\t\t});\n\t}\n\n\t// Default reasoning_depth to 'moderate' for hypothesis/verification types\n\tif (\n\t\t(input.thought_type === 'hypothesis' || input.thought_type === 'verification') &&\n\t\t!('reasoning_depth' in input)\n\t) {\n\t\tinput.reasoning_depth = 'moderate';\n\t}\n}\n\n/**\n * Normalizes thought input data before schema validation.\n *\n * The normalization is applied BEFORE schema validation, allowing the\n * strict Valibot schema to remain the contract authority.\n *\n * @param input - The raw thought input data to normalize\n * @returns Normalized thought data with correct field names\n *\n * @remarks\n * **Normalization Rules:**\n * - Applied to `current_step` if present (strict mode)\n * - Applied to all items in `previous_steps` if present (lenient mode with defaults)\n *\n * LLMs naturally provide complete data for `current_step`\n * but only partial/skeletal data for `previous_steps` (historical context).\n * The lenient mode for `previous_steps` fills in sensible defaults:\n * - `confidence`: 0.5 for missing tool recommendation confidence\n * - `priority`: 999 for missing tool recommendation priority\n * - `rationale`: empty string for missing tool recommendation rationale\n * - `expected_outcome`: empty string for missing step expected outcome\n *\n * @example\n * ```typescript\n * const input = {\n * thought: 'I need to analyze the data',\n * thought_number: 1,\n * total_thoughts: 3,\n * session_id: 'data-analysis',\n * next_thought_needed: true,\n * current_step: {\n * step_description: 'Read the data file',\n * recommended_tools: [{ tool_name: 'Read', confidence: 0.9, rationale: 'test', priority: 1 }],\n * expected_outcome: 'Data loaded'\n * },\n * previous_steps: [{\n * step_description: 'Previous step',\n * recommended_tools: [{ tool_name: 'Grep', rationale: 'Search code' }]\n * }]\n * };\n *\n * const normalized = normalizeInput(input);\n * // previous_steps[0]: confidence=0.5, priority=999, expected_outcome='' filled in\n * ```\n */\nexport function normalizeInput(input: unknown): ThoughtData {\n\tif (typeof input !== 'object' || input === null) {\n\t\treturn input as ThoughtData;\n\t}\n\n\tconst normalized = { ...input } as Record<string, unknown>;\n\n\tif (normalized.session_id === undefined) {\n\t\tthrow new ValidationError('session_id', 'is required');\n\t}\n\tif (typeof normalized.session_id !== 'string') {\n\t\tthrow new ValidationError('session_id', 'must be a non-empty string');\n\t}\n\tnormalized.session_id = asSessionId(normalized.session_id);\n\n\t// Normalize current_step if present (strict mode - no defaults)\n\tif (normalized.current_step && typeof normalized.current_step === 'object') {\n\t\tnormalized.current_step = normalizeStepRecommendation(\n\t\t\tnormalized.current_step as Record<string, unknown>,\n\t\t\tfalse // strict mode\n\t\t);\n\t}\n\n\t// Normalize all items in previous_steps if present (lenient mode - with defaults)\n\tif (Array.isArray(normalized.previous_steps) && normalized.previous_steps.length > 0) {\n\t\tnormalized.previous_steps = normalized.previous_steps.map((step) =>\n\t\t\ttypeof step === 'object' && step !== null\n\t\t\t\t? normalizeStepRecommendation(step as Record<string, unknown>, true) // lenient mode\n\t\t\t\t: step\n\t\t);\n\t}\n\n\t// Sanitize branch_id to prevent path traversal attacks\n\tif (typeof normalized.branch_id === 'string') {\n\t\tnormalized.branch_id = sanitizeBranchId(normalized.branch_id);\n\t}\n\n\tif (typeof normalized.register_branch_id === 'string') {\n\t\tnormalized.register_branch_id = sanitizeBranchId(normalized.register_branch_id);\n\t}\n\n\t// Auto-generate id if not provided (for DAG node identity)\n\tif (!normalized.id || typeof normalized.id !== 'string') {\n\t\tnormalized.id = generateThoughtId();\n\t}\n\n\t// Normalize reasoning fields\n\tnormalizeReasoningFields(normalized);\n\n\t// Sanitize meta_observation for prompt injection prevention\n\tif (typeof normalized.meta_observation === 'string') {\n\t\tnormalized.meta_observation = sanitizeStepField(normalized.meta_observation);\n\t}\n\n\t// Sanitize all free-text string fields recursively (dangerous HTML tags + null bytes)\n\t// This was moved from schema transforms because v.transform() cannot be converted to JSON Schema\n\tconst sanitized = sanitizeRecursive(normalized);\n\n\treturn sanitized as ThoughtData;\n}\n"],"names":["DEFAULT_RECOMMENDATION_CONFIDENCE","DEFAULT_RECOMMENDATION_PRIORITY","DEFAULT_RECOMMENDATION_RATIONALE","DEFAULT_STEP_OUTCOME","sanitizeRecursive","value","sanitizeString","Array","item","proto","Object","result","key","val","BRANCH_ID_PATTERN","sanitizeBranchId","branchId","ValidationError","asBranchId","sanitizeSessionId","sessionId","cleaned","MAX_SESSION_ID_LENGTH","SESSION_ID_PATTERN","normalizeRecommendation","rec","normalized","undefined","sanitizeRationale","sanitizeSuggestedInputs","normalizeStepRecommendation","step","lenient","tool","skill","sanitizeStepField","cond","normalizeReasoningFields","input","Math","v","Number","id","normalizeInput","asSessionId","generateThoughtId","sanitized"],"mappings":";;;;AAyBA,MAAMA,oCAAoC;AAC1C,MAAMC,kCAAkC;AACxC,MAAMC,mCAAmC;AACzC,MAAMC,uBAAuB;AAiBtB,SAASC,kBAAkBC,KAAc;IAC/C,IAAIA,QAAAA,OACH,OAAOA;IAER,IAAI,AAAiB,YAAjB,OAAOA,OACV,OAAOC,eAAeD;IAEvB,IAAIE,MAAM,OAAO,CAACF,QACjB,OAAOA,MAAM,GAAG,CAAC,CAACG,OAASJ,kBAAkBI;IAE9C,IAAI,AAAiB,YAAjB,OAAOH,OAAoB;QAE9B,MAAMI,QAAQC,OAAO,cAAc,CAACL;QACpC,IAAII,UAAUC,OAAO,SAAS,IAAID,AAAU,SAAVA,OACjC,OAAOJ;QAER,MAAMM,SAAkC,CAAC;QACzC,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIH,OAAO,OAAO,CAACL,OACvCM,MAAM,CAACC,IAAI,GAAGR,kBAAkBS;QAEjC,OAAOF;IACR;IACA,OAAON;AACR;AAMA,MAAMS,oBAAoB;AAenB,SAASC,iBAAiBC,QAAgB;IAEhD,IAAI,CAACF,kBAAkB,IAAI,CAACE,WAC3B,MAAM,IAAIC,gBACT,aACA;IAGF,OAAOC,WAAWF;AACnB;AAcO,SAASG,kBAAkBC,SAAiB;IAElD,MAAMC,UAAUf,eAAec;IAE/B,IAAIC,QAAQ,MAAM,GAAGC,yBAAyB,CAACC,mBAAmB,IAAI,CAACF,UACtE;IAED,OAAOA;AACR;AAoBA,SAASG,wBAAwBC,GAA4B;IAC5D,MAAMC,aAAsC;QAAE,GAAGD,GAAG;IAAC;IAGrD,IAAI,CAAE,iBAAgBC,UAAS,KAAMA,AAA0BC,WAA1BD,WAAW,UAAU,EACzDA,WAAW,UAAU,GAAG1B;IAIzB,IAAI,CAAE,eAAc0B,UAAS,KAAMA,AAAwBC,WAAxBD,WAAW,QAAQ,EACrDA,WAAW,QAAQ,GAAGzB;IAKvB,IAAI,AAAE,eAAeyB,cAAeA,AAAyBC,WAAzBD,WAAW,SAAS,EAEjD;QAAA,IAAI,AAAgC,YAAhC,OAAOA,WAAW,SAAS,EACrCA,WAAW,SAAS,GAAGE,kBAAkBF,WAAW,SAAS;IAC9D,OAHCA,WAAW,SAAS,GAAGxB;IAKxB,IACCwB,WAAW,gBAAgB,IAC3B,AAAuC,YAAvC,OAAOA,WAAW,gBAAgB,IAClC,CAACnB,MAAM,OAAO,CAACmB,WAAW,gBAAgB,GAE1CA,WAAW,gBAAgB,GAAGG,wBAC7BH,WAAW,gBAAgB;IAI7B,OAAOA;AACR;AA6BA,SAASI,4BACRC,IAA6B,EAC7BC,OAAgB;IAEhB,MAAMN,aAAsC;QAAE,GAAGK,IAAI;IAAC;IAGtD,IAAIxB,MAAM,OAAO,CAACmB,WAAW,iBAAiB,GAC7CA,WAAW,iBAAiB,GAAGA,WAAW,iBAAiB,CAAC,GAAG,CAAC,CAACO,OAChE,AAAgB,YAAhB,OAAOA,QAAqBA,AAAS,SAATA,OACzBT,wBAAwBS,QACxBA;IAKL,IAAI1B,MAAM,OAAO,CAACmB,WAAW,kBAAkB,GAC9CA,WAAW,kBAAkB,GAAGA,WAAW,kBAAkB,CAAC,GAAG,CAAC,CAACQ,QAClE,AAAiB,YAAjB,OAAOA,SAAsBA,AAAU,SAAVA,QAC1BV,wBAAwBU,SACxBA;IAIL,IAAI,AAAuC,YAAvC,OAAOR,WAAW,gBAAgB,EACrCA,WAAW,gBAAgB,GAAGS,kBAAkBT,WAAW,gBAAgB;IAE5E,IAAI,AAAuC,YAAvC,OAAOA,WAAW,gBAAgB,EACrCA,WAAW,gBAAgB,GAAGS,kBAAkBT,WAAW,gBAAgB;IAE5E,IAAInB,MAAM,OAAO,CAACmB,WAAW,oBAAoB,GAChDA,WAAW,oBAAoB,GAAGA,WAAW,oBAAoB,CAAC,GAAG,CAAC,CAACU,OACtE,AAAgB,YAAhB,OAAOA,OAAoBD,kBAAkBC,QAAQA;IAIvD,IAAIJ,WAAW,CAAE,uBAAsBN,UAAS,GAC/CA,WAAW,gBAAgB,GAAGvB;IAG/B,OAAOuB;AACR;AAwBO,SAASW,yBAAyBC,KAA8B;IAItE,IAAI,CAAE,mBAAkBA,KAAI,KAAMA,AAAuBX,WAAvBW,MAAM,YAAY,EACnDA,MAAM,YAAY,GAAG;IAItB,IAAI,AAA+B,YAA/B,OAAOA,MAAM,aAAa,EAC7BA,MAAM,aAAa,GAAGC,KAAK,GAAG,CAAC,GAAGA,KAAK,GAAG,CAAC,GAAGD,MAAM,aAAa;IAIlE,IAAI,AAA4B,YAA5B,OAAOA,MAAM,UAAU,EAC1BA,MAAM,UAAU,GAAGC,KAAK,GAAG,CAAC,GAAGA,KAAK,GAAG,CAAC,GAAGD,MAAM,UAAU;IAI5D,IAAI,AAA+B,YAA/B,OAAOA,MAAM,aAAa,EAC7BA,MAAM,aAAa,GAAGvB,iBAAiBuB,MAAM,aAAa;IAI3D,IAAI/B,MAAM,OAAO,CAAC+B,MAAM,iBAAiB,GACxCA,MAAM,iBAAiB,GAAGA,MAAM,iBAAiB,CAAC,MAAM,CACvD,CAACE,IAAe,AAAa,YAAb,OAAOA,KAAkBC,OAAO,SAAS,CAACD,MAAMA,IAAI;IAKtE,IAAIjC,MAAM,OAAO,CAAC+B,MAAM,mBAAmB,GAC1CA,MAAM,mBAAmB,GAAGA,MAAM,mBAAmB,CAAC,MAAM,CAC3D,CAACE,IAAe,AAAa,YAAb,OAAOA,KAAkBC,OAAO,SAAS,CAACD,MAAMA,IAAI;IAKtE,IAAIjC,MAAM,OAAO,CAAC+B,MAAM,gBAAgB,GACvCA,MAAM,gBAAgB,GAAGA,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAACI;QACpD,IAAI,AAAc,YAAd,OAAOA,IACV,OAAO3B,iBAAiB2B;QAEzB,OAAOA;IACR;IAID,IACEJ,AAAAA,CAAAA,AAAuB,iBAAvBA,MAAM,YAAY,IAAqBA,AAAuB,mBAAvBA,MAAM,YAAY,AAAkB,KAC5E,CAAE,sBAAqBA,KAAI,GAE3BA,MAAM,eAAe,GAAG;AAE1B;AA+CO,SAASK,eAAeL,KAAc;IAC5C,IAAI,AAAiB,YAAjB,OAAOA,SAAsBA,AAAU,SAAVA,OAChC,OAAOA;IAGR,MAAMZ,aAAa;QAAE,GAAGY,KAAK;IAAC;IAE9B,IAAIZ,AAA0BC,WAA1BD,WAAW,UAAU,EACxB,MAAM,IAAIT,gBAAgB,cAAc;IAEzC,IAAI,AAAiC,YAAjC,OAAOS,WAAW,UAAU,EAC/B,MAAM,IAAIT,gBAAgB,cAAc;IAEzCS,WAAW,UAAU,GAAGkB,YAAYlB,WAAW,UAAU;IAGzD,IAAIA,WAAW,YAAY,IAAI,AAAmC,YAAnC,OAAOA,WAAW,YAAY,EAC5DA,WAAW,YAAY,GAAGI,4BACzBJ,WAAW,YAAY,EACvB;IAKF,IAAInB,MAAM,OAAO,CAACmB,WAAW,cAAc,KAAKA,WAAW,cAAc,CAAC,MAAM,GAAG,GAClFA,WAAW,cAAc,GAAGA,WAAW,cAAc,CAAC,GAAG,CAAC,CAACK,OAC1D,AAAgB,YAAhB,OAAOA,QAAqBA,AAAS,SAATA,OACzBD,4BAA4BC,MAAiC,QAC7DA;IAKL,IAAI,AAAgC,YAAhC,OAAOL,WAAW,SAAS,EAC9BA,WAAW,SAAS,GAAGX,iBAAiBW,WAAW,SAAS;IAG7D,IAAI,AAAyC,YAAzC,OAAOA,WAAW,kBAAkB,EACvCA,WAAW,kBAAkB,GAAGX,iBAAiBW,WAAW,kBAAkB;IAI/E,IAAI,CAACA,WAAW,EAAE,IAAI,AAAyB,YAAzB,OAAOA,WAAW,EAAE,EACzCA,WAAW,EAAE,GAAGmB;IAIjBR,yBAAyBX;IAGzB,IAAI,AAAuC,YAAvC,OAAOA,WAAW,gBAAgB,EACrCA,WAAW,gBAAgB,GAAGS,kBAAkBT,WAAW,gBAAgB;IAK5E,MAAMoB,YAAY1C,kBAAkBsB;IAEpC,OAAOoB;AACR"}
@@ -4,17 +4,12 @@
4
4
  * @module PersistenceBuffer
5
5
  */
6
6
  import type { PersistenceBackend } from '../contracts/PersistenceBackend.js';
7
- import type { IEdgeStore } from '../contracts/interfaces.js';
8
7
  import type { BranchId, SessionId } from '../contracts/ids.js';
9
8
  import type { Logger } from '../logger/StructuredLogger.js';
10
9
  import type { Summary } from './compression/Summary.js';
11
10
  import type { Edge } from './graph/Edge.js';
12
11
  import { type PersistenceDelay } from './PersistenceWriter.js';
13
12
  import type { ThoughtData } from './thought.js';
14
- /** Minimal compatibility view for legacy callers that own a `writeBuffer`. */
15
- export interface BufferedSession {
16
- writeBuffer: ThoughtData[];
17
- }
18
13
  /** Event emitter contract for persistence error events. */
19
14
  export interface PersistenceEventEmitter {
20
15
  emit(event: 'persistenceError', payload: {
@@ -25,18 +20,11 @@ export interface PersistenceEventEmitter {
25
20
  /** Observable persistence state relevant to safe in-memory session eviction. */
26
21
  export type SessionEvictionState = 'quiescent' | 'pending' | 'failed' | 'barrier';
27
22
  /** Configuration options for {@link PersistenceBuffer}. */
28
- export interface PersistenceBufferConfig<S extends BufferedSession> {
23
+ export interface PersistenceBufferConfig {
29
24
  readonly persistence: PersistenceBackend;
30
25
  readonly bufferSize: number;
31
26
  readonly flushInterval: number;
32
27
  readonly maxRetries: number;
33
- readonly defaultSessionId: SessionId;
34
- /** Compatibility-only session source retained until producer wiring is migrated. */
35
- readonly getSessions: () => Map<SessionId, S>;
36
- /** Compatibility-only default session retained until producer wiring is migrated. */
37
- readonly getDefaultSession: () => S;
38
- /** Compatibility-only edge source retained until producers register snapshots. */
39
- readonly edgeStore?: IEdgeStore;
40
28
  /** Optional emitter for `persistenceError` events. */
41
29
  readonly eventEmitter?: PersistenceEventEmitter | null;
42
30
  readonly logger?: Logger;
@@ -49,10 +37,9 @@ export interface PersistenceBufferConfig<S extends BufferedSession> {
49
37
  * Accepted work is owned by a queue independent of live session state. Explicit
50
38
  * callers can join and upgrade a background generation without starting another writer.
51
39
  */
52
- export declare class PersistenceBuffer<S extends BufferedSession> {
40
+ export declare class PersistenceBuffer {
53
41
  private readonly _bufferSize;
54
42
  private readonly _flushInterval;
55
- private readonly _defaultSessionId;
56
43
  private readonly _queue;
57
44
  private readonly _writer;
58
45
  private _eventEmitter;
@@ -72,7 +59,7 @@ export declare class PersistenceBuffer<S extends BufferedSession> {
72
59
  *
73
60
  * @param config - Persistence dependencies, trigger thresholds, and retry policy.
74
61
  */
75
- constructor(config: PersistenceBufferConfig<S>);
62
+ constructor(config: PersistenceBufferConfig);
76
63
  /** @returns The underlying flush timer for lifecycle introspection. */
77
64
  get timer(): ReturnType<typeof setInterval> | null;
78
65
  /** @returns Whether a global drain generation is active. */
@@ -88,14 +75,10 @@ export declare class PersistenceBuffer<S extends BufferedSession> {
88
75
  /**
89
76
  * Accepts a thought with authoritative session attribution.
90
77
  *
91
- * The legacy session overload derives attribution from `thought.session_id` and
92
- * falls back to the configured default session without using the live write buffer.
93
- *
94
78
  * @param sessionId - Session that owns the accepted thought.
95
79
  * @param thought - Thought to persist.
96
80
  */
97
81
  bufferThought(sessionId: SessionId, thought: ThoughtData): void;
98
- bufferThought(session: BufferedSession, thought: ThoughtData): void;
99
82
  /**
100
83
  * Accepts the latest snapshot for one session-owned branch.
101
84
  *
@@ -1 +1 @@
1
- {"version":3,"file":"PersistenceBuffer.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceBuffer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PersistenceBuffer.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceBuffer.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,6 @@ import { PersistenceWriter } from "./PersistenceWriter.js";
7
7
  class PersistenceBuffer {
8
8
  _bufferSize;
9
9
  _flushInterval;
10
- _defaultSessionId;
11
10
  _queue = new PersistenceWorkQueue();
12
11
  _writer;
13
12
  _eventEmitter;
@@ -25,7 +24,6 @@ class PersistenceBuffer {
25
24
  constructor(config){
26
25
  this._bufferSize = config.bufferSize;
27
26
  this._flushInterval = config.flushInterval;
28
- this._defaultSessionId = config.defaultSessionId;
29
27
  this._eventEmitter = config.eventEmitter ?? null;
30
28
  this._logger = config.logger ?? new NullLogger();
31
29
  this._writer = new PersistenceWriter({
@@ -46,8 +44,7 @@ class PersistenceBuffer {
46
44
  setEventEmitter(emitter) {
47
45
  this._eventEmitter = emitter;
48
46
  }
49
- bufferThought(source, thought) {
50
- const sessionId = 'string' == typeof source ? source : thought.session_id ?? this._defaultSessionId;
47
+ bufferThought(sessionId, thought) {
51
48
  this._assertSessionAdmissionOpen(sessionId);
52
49
  if (this._queue.pendingThoughtCount >= this._bufferSize && this.isFlushing) this._logger.info('Write buffer full and flush in progress, applying backpressure', {
53
50
  bufferSize: this._queue.pendingThoughtCount,
@@ -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 { IEdgeStore } from '../contracts/interfaces.js';\nimport type { BranchId, SessionId } 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 { 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/** Minimal compatibility view for legacy callers that own a `writeBuffer`. */\nexport interface BufferedSession {\n\twriteBuffer: ThoughtData[];\n}\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<S extends BufferedSession> {\n\treadonly persistence: PersistenceBackend;\n\treadonly bufferSize: number;\n\treadonly flushInterval: number;\n\treadonly maxRetries: number;\n\treadonly defaultSessionId: SessionId;\n\t/** Compatibility-only session source retained until producer wiring is migrated. */\n\treadonly getSessions: () => Map<SessionId, S>;\n\t/** Compatibility-only default session retained until producer wiring is migrated. */\n\treadonly getDefaultSession: () => S;\n\t/** Compatibility-only edge source retained until producers register snapshots. */\n\treadonly edgeStore?: IEdgeStore;\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}\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<S extends BufferedSession> {\n\tprivate readonly _bufferSize: number;\n\tprivate readonly _flushInterval: number;\n\tprivate readonly _defaultSessionId: SessionId;\n\tprivate readonly _queue = new 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<S>) {\n\t\tthis._bufferSize = config.bufferSize;\n\t\tthis._flushInterval = config.flushInterval;\n\t\tthis._defaultSessionId = config.defaultSessionId;\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\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 * The legacy session overload derives attribution from `thought.session_id` and\n\t * falls back to the configured default session without using the live write buffer.\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\tpublic bufferThought(session: BufferedSession, thought: ThoughtData): void;\n\tpublic bufferThought(source: SessionId | BufferedSession, thought: ThoughtData): void {\n\t\tconst sessionId =\n\t\t\ttypeof source === 'string' ? source : (thought.session_id ?? this._defaultSessionId);\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\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","PersistenceWorkQueue","Map","AsyncLocalStorage","Set","Promise","config","NullLogger","PersistenceWriter","emitter","source","thought","sessionId","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 } 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 { 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}\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 = new 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._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\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\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","PersistenceWorkQueue","Map","AsyncLocalStorage","Set","Promise","config","NullLogger","PersistenceWriter","emitter","sessionId","thought","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 +1 @@
1
- {"version":3,"file":"PersistenceRestore.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceRestore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAElB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAkC,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACpG,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;AAEhD,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;AA2EF,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC,0BAA0B,CAAC,CAiBrC"}
1
+ {"version":3,"file":"PersistenceRestore.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceRestore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAYxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,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;AAiEF,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC,0BAA0B,CAAC,CAgBrC"}
@@ -1,6 +1,5 @@
1
- import { GLOBAL_SESSION_ID, asSessionId } from "../contracts/ids.js";
1
+ import { asSessionId } from "../contracts/ids.js";
2
2
  import { PersistenceCompatibilityError, PersistenceUnavailableError } from "../errors.js";
3
- import { requireSessionScopedPersistence } from "../persistence/SessionScopedPersistence.js";
4
3
  import { assertBranchScope, assertEdgeScopes, assertPersistableThoughtCollections, assertSummaryScopes, assertThoughtScope, assertUniqueRecordIds, parsePersistenceBranchId } from "../persistence/PersistenceScope.js";
5
4
  import { EdgeStore } from "./graph/EdgeStore.js";
6
5
  function validateThoughts(sessionId, history, branches) {
@@ -16,10 +15,6 @@ function validateThoughts(sessionId, history, branches) {
16
15
  thoughts: branch.thoughts
17
16
  }))
18
17
  ];
19
- if (sessionId === GLOBAL_SESSION_ID) return void assertPersistableThoughtCollections(collections.map((collection)=>({
20
- sessionId,
21
- thoughts: collection.thoughts.filter((thought)=>void 0 !== thought.id)
22
- })), `restore:${sessionId}`);
23
18
  assertPersistableThoughtCollections(collections, `restore:${sessionId}`);
24
19
  }
25
20
  async function stageSession(persistence, sessionId) {
@@ -64,9 +59,8 @@ async function stageSession(persistence, sessionId) {
64
59
  });
65
60
  }
66
61
  async function stagePersistenceRestore(backend) {
67
- const persistence = requireSessionScopedPersistence(backend, 'listSessions');
68
- if (!await persistence.healthy()) throw new PersistenceUnavailableError();
69
- const listedSessions = await persistence.listSessions();
62
+ if (!await backend.healthy()) throw new PersistenceUnavailableError();
63
+ const listedSessions = await backend.listSessions();
70
64
  const sessionIds = [];
71
65
  const seen = new Set();
72
66
  for (const listedSessionId of listedSessions){
@@ -77,7 +71,7 @@ async function stagePersistenceRestore(backend) {
77
71
  }
78
72
  }
79
73
  const sessions = [];
80
- for (const sessionId of sessionIds)sessions.push(await stageSession(persistence, sessionId));
74
+ for (const sessionId of sessionIds)sessions.push(await stageSession(backend, sessionId));
81
75
  return Object.freeze({
82
76
  sessions: Object.freeze(sessions)
83
77
  });
@@ -1 +1 @@
1
- {"version":3,"file":"core/PersistenceRestore.js","sources":["../../src/core/PersistenceRestore.ts"],"sourcesContent":["import type {\n\tPersistenceBackend,\n\tSessionScopedPersistenceBackend,\n} from '../contracts/PersistenceBackend.js';\nimport { GLOBAL_SESSION_ID, asSessionId, type BranchId, type SessionId } from '../contracts/ids.js';\nimport type { Summary } from './compression/Summary.js';\nimport { PersistenceCompatibilityError, PersistenceUnavailableError } from '../errors.js';\nimport { requireSessionScopedPersistence } from '../persistence/SessionScopedPersistence.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tassertUniqueRecordIds,\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';\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\tif (sessionId === GLOBAL_SESSION_ID) {\n\t\tassertPersistableThoughtCollections(\n\t\t\tcollections.map((collection) => ({\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: collection.thoughts.filter((thought) => thought.id !== undefined),\n\t\t\t})),\n\t\t\t`restore:${sessionId}`\n\t\t);\n\t\treturn;\n\t}\n\tassertPersistableThoughtCollections(collections, `restore:${sessionId}`);\n}\n\nasync function stageSession(\n\tpersistence: SessionScopedPersistenceBackend,\n\tsessionId: SessionId\n): Promise<RestoredSession> {\n\tconst history = await persistence.loadHistoryForSession(sessionId);\n\tconst listedBranches = await persistence.listBranchesForSession(sessionId);\n\tconst branches: RestoredBranch[] = [];\n\tconst seenBranches = new Set<BranchId>();\n\tfor (const listedBranchId of listedBranches) {\n\t\tconst branchId = parsePersistenceBranchId(listedBranchId, `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\tconst thoughts = await persistence.loadBranchForSession(sessionId, branchId);\n\t\tif (thoughts === undefined) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t`restore:${sessionId}:branches:${branchId}`,\n\t\t\t\t'listed branch is missing'\n\t\t\t);\n\t\t}\n\t\tbranches.push(Object.freeze({ branchId, thoughts: Object.freeze([...thoughts]) }));\n\t}\n\tvalidateThoughts(sessionId, history, branches);\n\n\tconst edges = await persistence.loadEdges(sessionId);\n\tassertEdgeScopes(sessionId, edges);\n\tassertUniqueRecordIds(edges, `restore:${sessionId}:edges`, 'edge');\n\tconst validationStore = new EdgeStore();\n\tfor (const restoredEdge of edges) validationStore.addEdge(restoredEdge);\n\n\tconst summaries = await persistence.loadSummaries(sessionId);\n\tassertSummaryScopes(sessionId, summaries);\n\tassertUniqueRecordIds(summaries, `restore:${sessionId}:summaries`, 'summary');\n\n\treturn Object.freeze({\n\t\tsessionId,\n\t\thistory: Object.freeze([...history]),\n\t\tbranches: Object.freeze(branches),\n\t\tedges: Object.freeze([...edges]),\n\t\tsummaries: Object.freeze([...summaries]),\n\t});\n}\n\nexport async function stagePersistenceRestore(\n\tbackend: PersistenceBackend\n): Promise<PersistenceRestoreSnapshot> {\n\tconst persistence = requireSessionScopedPersistence(backend, 'listSessions');\n\tif (!(await persistence.healthy())) throw new PersistenceUnavailableError();\n\n\tconst listedSessions = await persistence.listSessions();\n\tconst sessionIds: SessionId[] = [];\n\tconst seen = new Set<SessionId>();\n\tfor (const listedSessionId of listedSessions) {\n\t\tconst sessionId = asSessionId(listedSessionId);\n\t\tif (seen.has(sessionId)) continue;\n\t\tseen.add(sessionId);\n\t\tsessionIds.push(sessionId);\n\t}\n\n\tconst sessions: RestoredSession[] = [];\n\tfor (const sessionId of sessionIds) sessions.push(await stageSession(persistence, sessionId));\n\treturn Object.freeze({ sessions: Object.freeze(sessions) });\n}\n"],"names":["validateThoughts","sessionId","history","branches","thought","assertThoughtScope","branch","assertBranchScope","collections","GLOBAL_SESSION_ID","assertPersistableThoughtCollections","collection","undefined","stageSession","persistence","listedBranches","seenBranches","Set","listedBranchId","branchId","parsePersistenceBranchId","PersistenceCompatibilityError","thoughts","Object","edges","assertEdgeScopes","assertUniqueRecordIds","validationStore","EdgeStore","restoredEdge","summaries","assertSummaryScopes","stagePersistenceRestore","backend","requireSessionScopedPersistence","PersistenceUnavailableError","listedSessions","sessionIds","seen","listedSessionId","asSessionId","sessions"],"mappings":"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"}
1
+ {"version":3,"file":"core/PersistenceRestore.js","sources":["../../src/core/PersistenceRestore.ts"],"sourcesContent":["import type { PersistenceBackend } 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\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';\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\nasync function stageSession(\n\tpersistence: PersistenceBackend,\n\tsessionId: SessionId\n): Promise<RestoredSession> {\n\tconst history = await persistence.loadHistoryForSession(sessionId);\n\tconst listedBranches = await persistence.listBranchesForSession(sessionId);\n\tconst branches: RestoredBranch[] = [];\n\tconst seenBranches = new Set<BranchId>();\n\tfor (const listedBranchId of listedBranches) {\n\t\tconst branchId = parsePersistenceBranchId(listedBranchId, `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\tconst thoughts = await persistence.loadBranchForSession(sessionId, branchId);\n\t\tif (thoughts === undefined) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t`restore:${sessionId}:branches:${branchId}`,\n\t\t\t\t'listed branch is missing'\n\t\t\t);\n\t\t}\n\t\tbranches.push(Object.freeze({ branchId, thoughts: Object.freeze([...thoughts]) }));\n\t}\n\tvalidateThoughts(sessionId, history, branches);\n\n\tconst edges = await persistence.loadEdges(sessionId);\n\tassertEdgeScopes(sessionId, edges);\n\tassertUniqueRecordIds(edges, `restore:${sessionId}:edges`, 'edge');\n\tconst validationStore = new EdgeStore();\n\tfor (const restoredEdge of edges) validationStore.addEdge(restoredEdge);\n\n\tconst summaries = await persistence.loadSummaries(sessionId);\n\tassertSummaryScopes(sessionId, summaries);\n\tassertUniqueRecordIds(summaries, `restore:${sessionId}:summaries`, 'summary');\n\n\treturn Object.freeze({\n\t\tsessionId,\n\t\thistory: Object.freeze([...history]),\n\t\tbranches: Object.freeze(branches),\n\t\tedges: Object.freeze([...edges]),\n\t\tsummaries: Object.freeze([...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 listedSessions = await backend.listSessions();\n\tconst sessionIds: SessionId[] = [];\n\tconst seen = new Set<SessionId>();\n\tfor (const listedSessionId of listedSessions) {\n\t\tconst sessionId = asSessionId(listedSessionId);\n\t\tif (seen.has(sessionId)) continue;\n\t\tseen.add(sessionId);\n\t\tsessionIds.push(sessionId);\n\t}\n\n\tconst sessions: RestoredSession[] = [];\n\tfor (const sessionId of sessionIds) sessions.push(await stageSession(backend, sessionId));\n\treturn Object.freeze({ sessions: Object.freeze(sessions) });\n}\n"],"names":["validateThoughts","sessionId","history","branches","thought","assertThoughtScope","branch","assertBranchScope","collections","assertPersistableThoughtCollections","stageSession","persistence","listedBranches","seenBranches","Set","listedBranchId","branchId","parsePersistenceBranchId","PersistenceCompatibilityError","thoughts","undefined","Object","edges","assertEdgeScopes","assertUniqueRecordIds","validationStore","EdgeStore","restoredEdge","summaries","assertSummaryScopes","stagePersistenceRestore","backend","PersistenceUnavailableError","listedSessions","sessionIds","seen","listedSessionId","asSessionId","sessions"],"mappings":";;;;AAmCA,SAASA,iBACRC,SAAoB,EACpBC,OAA+B,EAC/BC,QAAmC;IAEnC,KAAK,MAAMC,WAAWF,QAASG,mBAAmB,yBAAyBJ,WAAWG;IACtF,KAAK,MAAME,UAAUH,SACpBI,kBAAkB,wBAAwBN,WAAWK,OAAO,QAAQ,EAAEA,OAAO,QAAQ;IAEtF,MAAME,cAA4C;QACjD;YAAEP;YAAW,UAAUC;QAAQ;WAC5BC,SAAS,GAAG,CAAC,CAACG,SAAY;gBAAEL;gBAAW,UAAUK,OAAO,QAAQ;YAAC;KACpE;IACDG,oCAAoCD,aAAa,CAAC,QAAQ,EAAEP,WAAW;AACxE;AAEA,eAAeS,aACdC,WAA+B,EAC/BV,SAAoB;IAEpB,MAAMC,UAAU,MAAMS,YAAY,qBAAqB,CAACV;IACxD,MAAMW,iBAAiB,MAAMD,YAAY,sBAAsB,CAACV;IAChE,MAAME,WAA6B,EAAE;IACrC,MAAMU,eAAe,IAAIC;IACzB,KAAK,MAAMC,kBAAkBH,eAAgB;QAC5C,MAAMI,WAAWC,yBAAyBF,gBAAgB,CAAC,QAAQ,EAAEd,UAAU,SAAS,CAAC;QACzF,IAAIY,aAAa,GAAG,CAACG,WACpB,MAAM,IAAIE,8BACT,CAAC,QAAQ,EAAEjB,UAAU,SAAS,CAAC,EAC/B,CAAC,qBAAqB,EAAEe,SAAS,CAAC,CAAC;QAGrCH,aAAa,GAAG,CAACG;QACjB,MAAMG,WAAW,MAAMR,YAAY,oBAAoB,CAACV,WAAWe;QACnE,IAAIG,AAAaC,WAAbD,UACH,MAAM,IAAID,8BACT,CAAC,QAAQ,EAAEjB,UAAU,UAAU,EAAEe,UAAU,EAC3C;QAGFb,SAAS,IAAI,CAACkB,OAAO,MAAM,CAAC;YAAEL;YAAU,UAAUK,OAAO,MAAM,CAAC;mBAAIF;aAAS;QAAE;IAChF;IACAnB,iBAAiBC,WAAWC,SAASC;IAErC,MAAMmB,QAAQ,MAAMX,YAAY,SAAS,CAACV;IAC1CsB,iBAAiBtB,WAAWqB;IAC5BE,sBAAsBF,OAAO,CAAC,QAAQ,EAAErB,UAAU,MAAM,CAAC,EAAE;IAC3D,MAAMwB,kBAAkB,IAAIC;IAC5B,KAAK,MAAMC,gBAAgBL,MAAOG,gBAAgB,OAAO,CAACE;IAE1D,MAAMC,YAAY,MAAMjB,YAAY,aAAa,CAACV;IAClD4B,oBAAoB5B,WAAW2B;IAC/BJ,sBAAsBI,WAAW,CAAC,QAAQ,EAAE3B,UAAU,UAAU,CAAC,EAAE;IAEnE,OAAOoB,OAAO,MAAM,CAAC;QACpBpB;QACA,SAASoB,OAAO,MAAM,CAAC;eAAInB;SAAQ;QACnC,UAAUmB,OAAO,MAAM,CAAClB;QACxB,OAAOkB,OAAO,MAAM,CAAC;eAAIC;SAAM;QAC/B,WAAWD,OAAO,MAAM,CAAC;eAAIO;SAAU;IACxC;AACD;AAEO,eAAeE,wBACrBC,OAA2B;IAE3B,IAAI,CAAE,MAAMA,QAAQ,OAAO,IAAK,MAAM,IAAIC;IAE1C,MAAMC,iBAAiB,MAAMF,QAAQ,YAAY;IACjD,MAAMG,aAA0B,EAAE;IAClC,MAAMC,OAAO,IAAIrB;IACjB,KAAK,MAAMsB,mBAAmBH,eAAgB;QAC7C,MAAMhC,YAAYoC,YAAYD;QAC9B,KAAID,KAAK,GAAG,CAAClC;YACbkC,KAAK,GAAG,CAAClC;YACTiC,WAAW,IAAI,CAACjC;;IACjB;IAEA,MAAMqC,WAA8B,EAAE;IACtC,KAAK,MAAMrC,aAAaiC,WAAYI,SAAS,IAAI,CAAC,MAAM5B,aAAaqB,SAAS9B;IAC9E,OAAOoB,OAAO,MAAM,CAAC;QAAE,UAAUA,OAAO,MAAM,CAACiB;IAAU;AAC1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"PersistenceWriter.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceWriter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAOhG,yDAAyD;AACzD,MAAM,MAAM,gBAAgB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvE,6EAA6E;AAC7E,MAAM,MAAM,uBAAuB,GAAG;IACrC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAClC,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,sBAAsB,GAAG,IAAI,GAAG,sBAAsB,CAAC;AAMnE;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAE1C;;;;;OAKG;gBACgB,MAAM,EAAE,uBAAuB;IAWlD;;;;;OAKG;IACU,KAAK,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAmB1E,OAAO,CAAC,WAAW;YAIL,SAAS;IAmCvB,OAAO,CAAC,QAAQ;CA2ChB"}
1
+ {"version":3,"file":"PersistenceWriter.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceWriter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAKhG,yDAAyD;AACzD,MAAM,MAAM,gBAAgB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvE,6EAA6E;AAC7E,MAAM,MAAM,uBAAuB,GAAG;IACrC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAClC,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,sBAAsB,GAAG,IAAI,GAAG,sBAAsB,CAAC;AAMnE;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAE1C;;;;;OAKG;gBACgB,MAAM,EAAE,uBAAuB;IAWlD;;;;;OAKG;IACU,KAAK,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAmB1E,OAAO,CAAC,WAAW;YAIL,SAAS;IAkBvB,OAAO,CAAC,QAAQ;CA2ChB"}
@@ -1,5 +1,3 @@
1
- import { GLOBAL_SESSION_ID } from "../contracts/ids.js";
2
- import { requireSessionScopedPersistence } from "../persistence/SessionScopedPersistence.js";
3
1
  import { assertNever } from "../utils.js";
4
2
  const DEFAULT_RETRY_DELAYS = [
5
3
  100,
@@ -42,17 +40,10 @@ class PersistenceWriter {
42
40
  async _dispatch(work) {
43
41
  switch(work.kind){
44
42
  case 'thought':
45
- if (work.sessionId === GLOBAL_SESSION_ID) return this._persistence.saveThought(work.thought);
46
- return requireSessionScopedPersistence(this._persistence, 'saveThoughtForSession').saveThoughtForSession(work.sessionId, work.thought);
43
+ return this._persistence.saveThoughtForSession(work.sessionId, work.thought);
47
44
  case 'branch':
48
- if ('delete' === work.operation) {
49
- const persistence = requireSessionScopedPersistence(this._persistence, work.sessionId === GLOBAL_SESSION_ID ? 'deleteBranch' : 'deleteBranchForSession');
50
- return work.sessionId === GLOBAL_SESSION_ID ? persistence.deleteBranch(work.key) : persistence.deleteBranchForSession(work.sessionId, work.key);
51
- }
52
- if (work.sessionId === GLOBAL_SESSION_ID) return this._persistence.saveBranch(work.key, [
53
- ...work.snapshot
54
- ]);
55
- return requireSessionScopedPersistence(this._persistence, 'saveBranchForSession').saveBranchForSession(work.sessionId, work.key, work.snapshot);
45
+ if ('delete' === work.operation) return this._persistence.deleteBranchForSession(work.sessionId, work.key);
46
+ return this._persistence.saveBranchForSession(work.sessionId, work.key, work.snapshot);
56
47
  case 'edge':
57
48
  return this._persistence.saveEdges(work.sessionId, work.snapshot);
58
49
  case 'summary':
@@ -1 +1 @@
1
- {"version":3,"file":"core/PersistenceWriter.js","sources":["../../src/core/PersistenceWriter.ts"],"sourcesContent":["/**\n * Bounded persistence dispatch for one accepted work item.\n *\n * @module PersistenceWriter\n */\n\nimport type { PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport type { PersistenceWork, PersistenceWorkFailure } from '../contracts/persistence-work.js';\nimport { GLOBAL_SESSION_ID } from '../contracts/ids.js';\nimport { requireSessionScopedPersistence } from '../persistence/SessionScopedPersistence.js';\nimport { assertNever } from '../utils.js';\n\nconst DEFAULT_RETRY_DELAYS = [100, 500, 2000] as const;\n\n/** Async scheduler used between persistence attempts. */\nexport type PersistenceDelay = (milliseconds: number) => Promise<void>;\n\n/** Immutable dependencies and retry policy for {@link PersistenceWriter}. */\nexport type PersistenceWriterConfig = {\n\treadonly persistence: PersistenceBackend;\n\treadonly maxRetries: number;\n\treadonly retryDelays?: readonly number[];\n\treadonly delay?: PersistenceDelay;\n};\n\n/** Allocation-free success sentinel or an attributable terminal failure. */\nexport type PersistenceWriteResult = true | PersistenceWorkFailure;\n\nfunction defaultDelay(milliseconds: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\n/**\n * Writes one sealed persistence item with a bounded retry policy.\n *\n * The writer owns no queue or generation state. Each call preserves the work\n * coordinates and delegates retention or error aggregation to its caller.\n *\n * @example\n * ```ts\n * const writer = new PersistenceWriter({ persistence, maxRetries: 0 });\n * const result = await writer.write(work);\n * if (result !== true) failures.push(result);\n * ```\n */\nexport class PersistenceWriter {\n\tprivate readonly _persistence: PersistenceBackend;\n\tprivate readonly _maxRetries: number;\n\tprivate readonly _retryDelays: readonly number[];\n\tprivate readonly _delay: PersistenceDelay;\n\n\t/**\n\t * Creates a bounded writer.\n\t *\n\t * @param config - Persistence dependency, retry bound, cadence, and delay scheduler.\n\t * @throws {RangeError} When `maxRetries` is not a non-negative safe integer.\n\t */\n\tpublic constructor(config: PersistenceWriterConfig) {\n\t\tif (!Number.isSafeInteger(config.maxRetries) || config.maxRetries < 0) {\n\t\t\tthrow new RangeError('maxRetries must be a non-negative safe integer');\n\t\t}\n\n\t\tthis._persistence = config.persistence;\n\t\tthis._maxRetries = config.maxRetries;\n\t\tthis._retryDelays = [...(config.retryDelays ?? DEFAULT_RETRY_DELAYS)];\n\t\tthis._delay = config.delay ?? defaultDelay;\n\t}\n\n\t/**\n\t * Writes one item once initially and at most `maxRetries` additional times.\n\t *\n\t * @param work - Sealed persistence item selected by the coordinator.\n\t * @returns `true` on success, or the exact attributable failure after exhaustion.\n\t */\n\tpublic async write(work: PersistenceWork): Promise<PersistenceWriteResult> {\n\t\tlet finalCause: unknown;\n\n\t\tfor (let attemptIndex = 0; attemptIndex <= this._maxRetries; attemptIndex++) {\n\t\t\tif (attemptIndex > 0) {\n\t\t\t\tawait this._delay(this._retryDelay(attemptIndex - 1));\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait this._dispatch(work);\n\t\t\t\treturn true;\n\t\t\t} catch (cause) {\n\t\t\t\tfinalCause = cause;\n\t\t\t}\n\t\t}\n\n\t\treturn this._failure(work, this._maxRetries + 1, finalCause);\n\t}\n\n\tprivate _retryDelay(retryIndex: number): number {\n\t\treturn this._retryDelays[retryIndex] ?? this._retryDelays.at(-1) ?? 0;\n\t}\n\n\tprivate async _dispatch(work: PersistenceWork): Promise<void> {\n\t\tswitch (work.kind) {\n\t\t\tcase 'thought':\n\t\t\t\tif (work.sessionId === GLOBAL_SESSION_ID) {\n\t\t\t\t\treturn this._persistence.saveThought(work.thought);\n\t\t\t\t}\n\t\t\t\treturn requireSessionScopedPersistence(\n\t\t\t\t\tthis._persistence,\n\t\t\t\t\t'saveThoughtForSession'\n\t\t\t\t).saveThoughtForSession(work.sessionId, work.thought);\n\t\t\tcase 'branch':\n\t\t\t\tif (work.operation === 'delete') {\n\t\t\t\t\tconst persistence = requireSessionScopedPersistence(\n\t\t\t\t\t\tthis._persistence,\n\t\t\t\t\t\twork.sessionId === GLOBAL_SESSION_ID ? 'deleteBranch' : 'deleteBranchForSession'\n\t\t\t\t\t);\n\t\t\t\t\treturn work.sessionId === GLOBAL_SESSION_ID\n\t\t\t\t\t\t? persistence.deleteBranch(work.key)\n\t\t\t\t\t\t: persistence.deleteBranchForSession(work.sessionId, work.key);\n\t\t\t\t}\n\t\t\t\tif (work.sessionId === GLOBAL_SESSION_ID)\n\t\t\t\t\treturn this._persistence.saveBranch(work.key, [...work.snapshot]);\n\t\t\t\treturn requireSessionScopedPersistence(\n\t\t\t\t\tthis._persistence,\n\t\t\t\t\t'saveBranchForSession'\n\t\t\t\t).saveBranchForSession(work.sessionId, work.key, work.snapshot);\n\t\t\tcase 'edge':\n\t\t\t\treturn this._persistence.saveEdges(work.sessionId, work.snapshot);\n\t\t\tcase 'summary':\n\t\t\t\treturn this._persistence.saveSummaries(work.sessionId, work.snapshot);\n\t\t\tdefault:\n\t\t\t\treturn assertNever(work);\n\t\t}\n\t}\n\n\tprivate _failure(\n\t\twork: PersistenceWork,\n\t\tattempts: number,\n\t\tcause: unknown\n\t): PersistenceWorkFailure {\n\t\tswitch (work.kind) {\n\t\t\tcase 'thought':\n\t\t\t\treturn { kind: work.kind, token: work.token, sessionId: work.sessionId, attempts, cause };\n\t\t\tcase 'branch':\n\t\t\t\treturn {\n\t\t\t\t\tkind: work.kind,\n\t\t\t\t\toperation: work.operation,\n\t\t\t\t\ttoken: work.token,\n\t\t\t\t\tsessionId: work.sessionId,\n\t\t\t\t\tkey: work.key,\n\t\t\t\t\tversion: work.version,\n\t\t\t\t\tattempts,\n\t\t\t\t\tcause,\n\t\t\t\t};\n\t\t\tcase 'edge':\n\t\t\t\treturn {\n\t\t\t\t\tkind: work.kind,\n\t\t\t\t\ttoken: work.token,\n\t\t\t\t\tsessionId: work.sessionId,\n\t\t\t\t\tkey: work.key,\n\t\t\t\t\tversion: work.version,\n\t\t\t\t\tattempts,\n\t\t\t\t\tcause,\n\t\t\t\t};\n\t\t\tcase 'summary':\n\t\t\t\treturn {\n\t\t\t\t\tkind: work.kind,\n\t\t\t\t\ttoken: work.token,\n\t\t\t\t\tsessionId: work.sessionId,\n\t\t\t\t\tkey: work.key,\n\t\t\t\t\tversion: work.version,\n\t\t\t\t\tattempts,\n\t\t\t\t\tcause,\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\treturn assertNever(work);\n\t\t}\n\t}\n}\n"],"names":["DEFAULT_RETRY_DELAYS","defaultDelay","milliseconds","Promise","resolve","setTimeout","PersistenceWriter","config","Number","RangeError","work","finalCause","attemptIndex","cause","retryIndex","GLOBAL_SESSION_ID","requireSessionScopedPersistence","persistence","assertNever","attempts"],"mappings":"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"}
1
+ {"version":3,"file":"core/PersistenceWriter.js","sources":["../../src/core/PersistenceWriter.ts"],"sourcesContent":["/**\n * Bounded persistence dispatch for one accepted work item.\n *\n * @module PersistenceWriter\n */\n\nimport type { PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport type { PersistenceWork, PersistenceWorkFailure } from '../contracts/persistence-work.js';\nimport { assertNever } from '../utils.js';\n\nconst DEFAULT_RETRY_DELAYS = [100, 500, 2000] as const;\n\n/** Async scheduler used between persistence attempts. */\nexport type PersistenceDelay = (milliseconds: number) => Promise<void>;\n\n/** Immutable dependencies and retry policy for {@link PersistenceWriter}. */\nexport type PersistenceWriterConfig = {\n\treadonly persistence: PersistenceBackend;\n\treadonly maxRetries: number;\n\treadonly retryDelays?: readonly number[];\n\treadonly delay?: PersistenceDelay;\n};\n\n/** Allocation-free success sentinel or an attributable terminal failure. */\nexport type PersistenceWriteResult = true | PersistenceWorkFailure;\n\nfunction defaultDelay(milliseconds: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\n/**\n * Writes one sealed persistence item with a bounded retry policy.\n *\n * The writer owns no queue or generation state. Each call preserves the work\n * coordinates and delegates retention or error aggregation to its caller.\n *\n * @example\n * ```ts\n * const writer = new PersistenceWriter({ persistence, maxRetries: 0 });\n * const result = await writer.write(work);\n * if (result !== true) failures.push(result);\n * ```\n */\nexport class PersistenceWriter {\n\tprivate readonly _persistence: PersistenceBackend;\n\tprivate readonly _maxRetries: number;\n\tprivate readonly _retryDelays: readonly number[];\n\tprivate readonly _delay: PersistenceDelay;\n\n\t/**\n\t * Creates a bounded writer.\n\t *\n\t * @param config - Persistence dependency, retry bound, cadence, and delay scheduler.\n\t * @throws {RangeError} When `maxRetries` is not a non-negative safe integer.\n\t */\n\tpublic constructor(config: PersistenceWriterConfig) {\n\t\tif (!Number.isSafeInteger(config.maxRetries) || config.maxRetries < 0) {\n\t\t\tthrow new RangeError('maxRetries must be a non-negative safe integer');\n\t\t}\n\n\t\tthis._persistence = config.persistence;\n\t\tthis._maxRetries = config.maxRetries;\n\t\tthis._retryDelays = [...(config.retryDelays ?? DEFAULT_RETRY_DELAYS)];\n\t\tthis._delay = config.delay ?? defaultDelay;\n\t}\n\n\t/**\n\t * Writes one item once initially and at most `maxRetries` additional times.\n\t *\n\t * @param work - Sealed persistence item selected by the coordinator.\n\t * @returns `true` on success, or the exact attributable failure after exhaustion.\n\t */\n\tpublic async write(work: PersistenceWork): Promise<PersistenceWriteResult> {\n\t\tlet finalCause: unknown;\n\n\t\tfor (let attemptIndex = 0; attemptIndex <= this._maxRetries; attemptIndex++) {\n\t\t\tif (attemptIndex > 0) {\n\t\t\t\tawait this._delay(this._retryDelay(attemptIndex - 1));\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait this._dispatch(work);\n\t\t\t\treturn true;\n\t\t\t} catch (cause) {\n\t\t\t\tfinalCause = cause;\n\t\t\t}\n\t\t}\n\n\t\treturn this._failure(work, this._maxRetries + 1, finalCause);\n\t}\n\n\tprivate _retryDelay(retryIndex: number): number {\n\t\treturn this._retryDelays[retryIndex] ?? this._retryDelays.at(-1) ?? 0;\n\t}\n\n\tprivate async _dispatch(work: PersistenceWork): Promise<void> {\n\t\tswitch (work.kind) {\n\t\t\tcase 'thought':\n\t\t\t\treturn this._persistence.saveThoughtForSession(work.sessionId, work.thought);\n\t\t\tcase 'branch':\n\t\t\t\tif (work.operation === 'delete') {\n\t\t\t\t\treturn this._persistence.deleteBranchForSession(work.sessionId, work.key);\n\t\t\t\t}\n\t\t\t\treturn this._persistence.saveBranchForSession(work.sessionId, work.key, work.snapshot);\n\t\t\tcase 'edge':\n\t\t\t\treturn this._persistence.saveEdges(work.sessionId, work.snapshot);\n\t\t\tcase 'summary':\n\t\t\t\treturn this._persistence.saveSummaries(work.sessionId, work.snapshot);\n\t\t\tdefault:\n\t\t\t\treturn assertNever(work);\n\t\t}\n\t}\n\n\tprivate _failure(\n\t\twork: PersistenceWork,\n\t\tattempts: number,\n\t\tcause: unknown\n\t): PersistenceWorkFailure {\n\t\tswitch (work.kind) {\n\t\t\tcase 'thought':\n\t\t\t\treturn { kind: work.kind, token: work.token, sessionId: work.sessionId, attempts, cause };\n\t\t\tcase 'branch':\n\t\t\t\treturn {\n\t\t\t\t\tkind: work.kind,\n\t\t\t\t\toperation: work.operation,\n\t\t\t\t\ttoken: work.token,\n\t\t\t\t\tsessionId: work.sessionId,\n\t\t\t\t\tkey: work.key,\n\t\t\t\t\tversion: work.version,\n\t\t\t\t\tattempts,\n\t\t\t\t\tcause,\n\t\t\t\t};\n\t\t\tcase 'edge':\n\t\t\t\treturn {\n\t\t\t\t\tkind: work.kind,\n\t\t\t\t\ttoken: work.token,\n\t\t\t\t\tsessionId: work.sessionId,\n\t\t\t\t\tkey: work.key,\n\t\t\t\t\tversion: work.version,\n\t\t\t\t\tattempts,\n\t\t\t\t\tcause,\n\t\t\t\t};\n\t\t\tcase 'summary':\n\t\t\t\treturn {\n\t\t\t\t\tkind: work.kind,\n\t\t\t\t\ttoken: work.token,\n\t\t\t\t\tsessionId: work.sessionId,\n\t\t\t\t\tkey: work.key,\n\t\t\t\t\tversion: work.version,\n\t\t\t\t\tattempts,\n\t\t\t\t\tcause,\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\treturn assertNever(work);\n\t\t}\n\t}\n}\n"],"names":["DEFAULT_RETRY_DELAYS","defaultDelay","milliseconds","Promise","resolve","setTimeout","PersistenceWriter","config","Number","RangeError","work","finalCause","attemptIndex","cause","retryIndex","assertNever","attempts"],"mappings":"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"}
@@ -23,15 +23,4 @@ export declare class SessionAccessDeniedError extends SequentialThinkingError {
23
23
  readonly actualOwner: string | undefined;
24
24
  constructor(sessionId: SessionId, expectedOwner: string, actualOwner?: string);
25
25
  }
26
- /** Scope requested through the legacy synchronous clear API. */
27
- export type AsyncResetScope = 'session' | 'all';
28
- /** Condition that makes the legacy synchronous clear API unsafe. */
29
- export type AsyncResetReason = 'persistent' | 'active';
30
- /** Error raised when state requires the awaitable reset API. */
31
- export declare class AsyncResetRequiredError extends SequentialThinkingError {
32
- readonly scope: AsyncResetScope;
33
- readonly sessionId: SessionId | undefined;
34
- readonly reason: AsyncResetReason;
35
- constructor(scope: AsyncResetScope, sessionId?: SessionId, reason?: AsyncResetReason);
36
- }
37
26
  //# sourceMappingURL=SessionErrors.d.ts.map