@soleri/core 9.2.0 → 9.3.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 (316) hide show
  1. package/data/flows/build.flow.yaml +8 -9
  2. package/data/flows/deliver.flow.yaml +9 -10
  3. package/data/flows/design.flow.yaml +3 -4
  4. package/data/flows/enhance.flow.yaml +5 -6
  5. package/data/flows/explore.flow.yaml +3 -4
  6. package/data/flows/fix.flow.yaml +5 -6
  7. package/data/flows/plan.flow.yaml +4 -5
  8. package/data/flows/review.flow.yaml +3 -4
  9. package/dist/curator/curator.d.ts.map +1 -1
  10. package/dist/curator/curator.js +98 -22
  11. package/dist/curator/curator.js.map +1 -1
  12. package/dist/engine/bin/soleri-engine.js.map +1 -1
  13. package/dist/engine/module-manifest.d.ts +2 -0
  14. package/dist/engine/module-manifest.d.ts.map +1 -1
  15. package/dist/engine/module-manifest.js +136 -1
  16. package/dist/engine/module-manifest.js.map +1 -1
  17. package/dist/engine/register-engine.d.ts.map +1 -1
  18. package/dist/engine/register-engine.js +25 -1
  19. package/dist/engine/register-engine.js.map +1 -1
  20. package/dist/flows/gate-evaluator.js.map +1 -1
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/operator/operator-profile.d.ts.map +1 -1
  26. package/dist/operator/operator-profile.js +11 -5
  27. package/dist/operator/operator-profile.js.map +1 -1
  28. package/dist/operator/operator-signals.d.ts.map +1 -1
  29. package/dist/operator/operator-signals.js.map +1 -1
  30. package/dist/planning/evidence-collector.js.map +1 -1
  31. package/dist/planning/gap-passes.d.ts.map +1 -1
  32. package/dist/planning/gap-passes.js +23 -6
  33. package/dist/planning/gap-passes.js.map +1 -1
  34. package/dist/planning/gap-patterns.d.ts.map +1 -1
  35. package/dist/planning/gap-patterns.js +57 -11
  36. package/dist/planning/gap-patterns.js.map +1 -1
  37. package/dist/planning/github-projection.d.ts.map +1 -1
  38. package/dist/planning/github-projection.js +39 -20
  39. package/dist/planning/github-projection.js.map +1 -1
  40. package/dist/planning/impact-analyzer.d.ts.map +1 -1
  41. package/dist/planning/impact-analyzer.js +20 -18
  42. package/dist/planning/impact-analyzer.js.map +1 -1
  43. package/dist/planning/plan-lifecycle.d.ts.map +1 -1
  44. package/dist/planning/plan-lifecycle.js +22 -9
  45. package/dist/planning/plan-lifecycle.js.map +1 -1
  46. package/dist/planning/planner.d.ts.map +1 -1
  47. package/dist/planning/planner.js +60 -17
  48. package/dist/planning/planner.js.map +1 -1
  49. package/dist/planning/rationalization-detector.d.ts.map +1 -1
  50. package/dist/planning/rationalization-detector.js.map +1 -1
  51. package/dist/planning/reconciliation-engine.d.ts.map +1 -1
  52. package/dist/planning/reconciliation-engine.js.map +1 -1
  53. package/dist/planning/task-complexity-assessor.d.ts +42 -0
  54. package/dist/planning/task-complexity-assessor.d.ts.map +1 -0
  55. package/dist/planning/task-complexity-assessor.js +132 -0
  56. package/dist/planning/task-complexity-assessor.js.map +1 -0
  57. package/dist/planning/task-verifier.d.ts.map +1 -1
  58. package/dist/planning/task-verifier.js +14 -6
  59. package/dist/planning/task-verifier.js.map +1 -1
  60. package/dist/runtime/admin-ops.d.ts.map +1 -1
  61. package/dist/runtime/admin-ops.js +18 -0
  62. package/dist/runtime/admin-ops.js.map +1 -1
  63. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  64. package/dist/runtime/admin-setup-ops.js +2 -1
  65. package/dist/runtime/admin-setup-ops.js.map +1 -1
  66. package/dist/runtime/branching-ops.d.ts +12 -0
  67. package/dist/runtime/branching-ops.d.ts.map +1 -0
  68. package/dist/runtime/branching-ops.js +100 -0
  69. package/dist/runtime/branching-ops.js.map +1 -0
  70. package/dist/runtime/context-health.d.ts.map +1 -1
  71. package/dist/runtime/context-health.js.map +1 -1
  72. package/dist/runtime/facades/branching-facade.d.ts +7 -0
  73. package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
  74. package/dist/runtime/facades/branching-facade.js +8 -0
  75. package/dist/runtime/facades/branching-facade.js.map +1 -0
  76. package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -1
  77. package/dist/runtime/facades/chat-service-ops.js +3 -1
  78. package/dist/runtime/facades/chat-service-ops.js.map +1 -1
  79. package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -1
  80. package/dist/runtime/facades/chat-transport-ops.js.map +1 -1
  81. package/dist/runtime/facades/index.d.ts.map +1 -1
  82. package/dist/runtime/facades/index.js +42 -0
  83. package/dist/runtime/facades/index.js.map +1 -1
  84. package/dist/runtime/facades/intake-facade.d.ts +9 -0
  85. package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
  86. package/dist/runtime/facades/intake-facade.js +11 -0
  87. package/dist/runtime/facades/intake-facade.js.map +1 -0
  88. package/dist/runtime/facades/links-facade.d.ts +9 -0
  89. package/dist/runtime/facades/links-facade.d.ts.map +1 -0
  90. package/dist/runtime/facades/links-facade.js +10 -0
  91. package/dist/runtime/facades/links-facade.js.map +1 -0
  92. package/dist/runtime/facades/operator-facade.d.ts.map +1 -1
  93. package/dist/runtime/facades/operator-facade.js.map +1 -1
  94. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  95. package/dist/runtime/facades/plan-facade.js +4 -1
  96. package/dist/runtime/facades/plan-facade.js.map +1 -1
  97. package/dist/runtime/facades/tier-facade.d.ts +7 -0
  98. package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
  99. package/dist/runtime/facades/tier-facade.js +8 -0
  100. package/dist/runtime/facades/tier-facade.js.map +1 -0
  101. package/dist/runtime/facades/vault-facade.d.ts +9 -1
  102. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  103. package/dist/runtime/facades/vault-facade.js +44 -187
  104. package/dist/runtime/facades/vault-facade.js.map +1 -1
  105. package/dist/runtime/github-integration.d.ts.map +1 -1
  106. package/dist/runtime/github-integration.js +11 -4
  107. package/dist/runtime/github-integration.js.map +1 -1
  108. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  109. package/dist/runtime/orchestrate-ops.js +75 -42
  110. package/dist/runtime/orchestrate-ops.js.map +1 -1
  111. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  112. package/dist/runtime/planning-extra-ops.js.map +1 -1
  113. package/dist/runtime/runtime.d.ts.map +1 -1
  114. package/dist/runtime/runtime.js +3 -1
  115. package/dist/runtime/runtime.js.map +1 -1
  116. package/dist/runtime/session-briefing.d.ts.map +1 -1
  117. package/dist/runtime/session-briefing.js +5 -1
  118. package/dist/runtime/session-briefing.js.map +1 -1
  119. package/dist/runtime/tier-ops.d.ts +13 -0
  120. package/dist/runtime/tier-ops.d.ts.map +1 -0
  121. package/dist/runtime/tier-ops.js +110 -0
  122. package/dist/runtime/tier-ops.js.map +1 -0
  123. package/dist/skills/sync-skills.d.ts.map +1 -1
  124. package/dist/skills/sync-skills.js +1 -1
  125. package/dist/skills/sync-skills.js.map +1 -1
  126. package/dist/vault/linking.d.ts.map +1 -1
  127. package/dist/vault/linking.js +41 -5
  128. package/dist/vault/linking.js.map +1 -1
  129. package/dist/vault/vault-entries.d.ts.map +1 -1
  130. package/dist/vault/vault-entries.js +68 -26
  131. package/dist/vault/vault-entries.js.map +1 -1
  132. package/dist/vault/vault-maintenance.d.ts.map +1 -1
  133. package/dist/vault/vault-maintenance.js +6 -2
  134. package/dist/vault/vault-maintenance.js.map +1 -1
  135. package/dist/vault/vault-markdown-sync.d.ts.map +1 -1
  136. package/dist/vault/vault-markdown-sync.js.map +1 -1
  137. package/dist/vault/vault-memories.d.ts.map +1 -1
  138. package/dist/vault/vault-memories.js +3 -1
  139. package/dist/vault/vault-memories.js.map +1 -1
  140. package/dist/vault/vault-schema.js +36 -10
  141. package/dist/vault/vault-schema.js.map +1 -1
  142. package/dist/vault/vault.d.ts.map +1 -1
  143. package/dist/vault/vault.js +5 -1
  144. package/dist/vault/vault.js.map +1 -1
  145. package/package.json +7 -7
  146. package/src/agency/agency-manager.test.ts +60 -40
  147. package/src/agency/default-rules.test.ts +17 -9
  148. package/src/capabilities/registry.test.ts +2 -12
  149. package/src/chat/agent-loop.test.ts +33 -43
  150. package/src/chat/mcp-bridge.test.ts +7 -2
  151. package/src/claudemd/inject.test.ts +2 -12
  152. package/src/context/context-engine.test.ts +96 -51
  153. package/src/control/intent-router.test.ts +3 -3
  154. package/src/curator/classifier.test.ts +14 -8
  155. package/src/curator/contradiction-detector.test.ts +30 -5
  156. package/src/curator/curator.ts +278 -56
  157. package/src/curator/duplicate-detector.test.ts +77 -15
  158. package/src/curator/quality-gate.test.ts +71 -31
  159. package/src/curator/tag-manager.test.ts +12 -4
  160. package/src/domain-packs/knowledge-installer.test.ts +2 -10
  161. package/src/domain-packs/token-resolver.test.ts +1 -3
  162. package/src/domain-packs/types.test.ts +16 -2
  163. package/src/enforcement/registry.test.ts +2 -8
  164. package/src/engine/bin/soleri-engine.ts +3 -1
  165. package/src/engine/module-manifest.test.ts +48 -4
  166. package/src/engine/module-manifest.ts +138 -1
  167. package/src/engine/register-engine.test.ts +6 -1
  168. package/src/engine/register-engine.ts +26 -3
  169. package/src/errors/classify.test.ts +6 -2
  170. package/src/errors/retry.test.ts +1 -4
  171. package/src/facades/facade-factory.test.ts +110 -64
  172. package/src/flows/epilogue.test.ts +16 -10
  173. package/src/flows/gate-evaluator.test.ts +12 -6
  174. package/src/flows/gate-evaluator.ts +1 -3
  175. package/src/governance/governance.test.ts +137 -21
  176. package/src/health/health-registry.test.ts +8 -1
  177. package/src/index.ts +8 -0
  178. package/src/intake/content-classifier.test.ts +121 -51
  179. package/src/intake/dedup-gate.test.ts +38 -22
  180. package/src/intake/intake-pipeline.test.ts +5 -3
  181. package/src/intake/text-ingester.test.ts +26 -20
  182. package/src/llm/key-pool.test.ts +1 -3
  183. package/src/llm/llm-client.test.ts +1 -4
  184. package/src/llm/oauth-discovery.test.ts +16 -16
  185. package/src/llm/utils.test.ts +62 -18
  186. package/src/logging/logger.test.ts +4 -1
  187. package/src/loop/loop-manager.test.ts +2 -6
  188. package/src/migrations/migration-runner.edge-cases.test.ts +2 -7
  189. package/src/operator/operator-profile-extended.test.ts +15 -5
  190. package/src/operator/operator-profile.test.ts +26 -8
  191. package/src/operator/operator-profile.ts +38 -22
  192. package/src/operator/operator-signals-extended.test.ts +35 -23
  193. package/src/operator/operator-signals.test.ts +6 -10
  194. package/src/operator/operator-signals.ts +2 -1
  195. package/src/operator/prompts/hook-precompact-operator-dispatch.md +10 -6
  196. package/src/operator/prompts/subagent-soft-signal-extractor.md +5 -0
  197. package/src/operator/prompts/subagent-synthesis-cognition.md +19 -10
  198. package/src/operator/prompts/subagent-synthesis-communication.md +13 -7
  199. package/src/operator/prompts/subagent-synthesis-technical.md +19 -9
  200. package/src/operator/prompts/subagent-synthesis-trust.md +27 -21
  201. package/src/persona/defaults.test.ts +1 -5
  202. package/src/planning/evidence-collector.test.ts +147 -38
  203. package/src/planning/evidence-collector.ts +1 -4
  204. package/src/planning/gap-analysis-alternatives.test.ts +41 -11
  205. package/src/planning/gap-passes.test.ts +215 -33
  206. package/src/planning/gap-passes.ts +115 -46
  207. package/src/planning/gap-patterns.test.ts +87 -13
  208. package/src/planning/gap-patterns.ts +114 -31
  209. package/src/planning/github-projection.test.ts +6 -1
  210. package/src/planning/github-projection.ts +41 -20
  211. package/src/planning/impact-analyzer.test.ts +10 -23
  212. package/src/planning/impact-analyzer.ts +33 -46
  213. package/src/planning/plan-lifecycle.test.ts +103 -36
  214. package/src/planning/plan-lifecycle.ts +49 -18
  215. package/src/planning/planner.test.ts +12 -2
  216. package/src/planning/planner.ts +198 -58
  217. package/src/planning/rationalization-detector.test.ts +5 -20
  218. package/src/planning/rationalization-detector.ts +14 -16
  219. package/src/planning/reconciliation-engine.test.ts +20 -3
  220. package/src/planning/reconciliation-engine.ts +1 -2
  221. package/src/planning/task-complexity-assessor.test.ts +298 -0
  222. package/src/planning/task-complexity-assessor.ts +183 -0
  223. package/src/planning/task-verifier.test.ts +59 -27
  224. package/src/planning/task-verifier.ts +15 -9
  225. package/src/playbooks/playbook-executor.test.ts +1 -3
  226. package/src/plugins/plugin-loader.test.ts +19 -14
  227. package/src/plugins/plugin-registry.test.ts +45 -33
  228. package/src/project/project-registry.test.ts +23 -12
  229. package/src/prompts/template-manager.test.ts +4 -1
  230. package/src/queue/job-queue.test.ts +10 -14
  231. package/src/runtime/admin-extra-ops.test.ts +5 -19
  232. package/src/runtime/admin-ops.test.ts +22 -1
  233. package/src/runtime/admin-ops.ts +19 -0
  234. package/src/runtime/admin-setup-ops.test.ts +3 -4
  235. package/src/runtime/admin-setup-ops.ts +9 -2
  236. package/src/runtime/archive-ops.test.ts +4 -1
  237. package/src/runtime/branching-ops.test.ts +144 -0
  238. package/src/runtime/branching-ops.ts +107 -0
  239. package/src/runtime/capture-ops.test.ts +7 -21
  240. package/src/runtime/chain-ops.test.ts +16 -6
  241. package/src/runtime/claude-md-helpers.test.ts +1 -3
  242. package/src/runtime/context-health.test.ts +1 -3
  243. package/src/runtime/context-health.ts +1 -3
  244. package/src/runtime/curator-extra-ops.test.ts +3 -1
  245. package/src/runtime/domain-ops.test.ts +46 -36
  246. package/src/runtime/facades/admin-facade.test.ts +1 -4
  247. package/src/runtime/facades/archive-facade.test.ts +21 -7
  248. package/src/runtime/facades/brain-facade.test.ts +176 -72
  249. package/src/runtime/facades/branching-facade.test.ts +43 -0
  250. package/src/runtime/facades/branching-facade.ts +11 -0
  251. package/src/runtime/facades/chat-facade.test.ts +81 -28
  252. package/src/runtime/facades/chat-service-ops.test.ts +178 -73
  253. package/src/runtime/facades/chat-service-ops.ts +3 -1
  254. package/src/runtime/facades/chat-session-ops.test.ts +25 -10
  255. package/src/runtime/facades/chat-transport-ops.test.ts +101 -34
  256. package/src/runtime/facades/chat-transport-ops.ts +0 -1
  257. package/src/runtime/facades/context-facade.test.ts +19 -4
  258. package/src/runtime/facades/control-facade.test.ts +3 -3
  259. package/src/runtime/facades/index.ts +42 -0
  260. package/src/runtime/facades/intake-facade.test.ts +215 -0
  261. package/src/runtime/facades/intake-facade.ts +14 -0
  262. package/src/runtime/facades/links-facade.test.ts +203 -0
  263. package/src/runtime/facades/links-facade.ts +13 -0
  264. package/src/runtime/facades/loop-facade.test.ts +22 -5
  265. package/src/runtime/facades/memory-facade.test.ts +19 -5
  266. package/src/runtime/facades/operator-facade.test.ts +17 -4
  267. package/src/runtime/facades/operator-facade.ts +11 -3
  268. package/src/runtime/facades/orchestrate-facade.test.ts +7 -1
  269. package/src/runtime/facades/plan-facade.test.ts +29 -12
  270. package/src/runtime/facades/plan-facade.ts +7 -2
  271. package/src/runtime/facades/tier-facade.test.ts +47 -0
  272. package/src/runtime/facades/tier-facade.ts +11 -0
  273. package/src/runtime/facades/vault-facade.test.ts +174 -242
  274. package/src/runtime/facades/vault-facade.ts +55 -199
  275. package/src/runtime/github-integration.ts +11 -8
  276. package/src/runtime/grading-ops.test.ts +39 -8
  277. package/src/runtime/intake-ops.test.ts +69 -16
  278. package/src/runtime/loop-ops.test.ts +16 -6
  279. package/src/runtime/memory-cross-project-ops.test.ts +25 -14
  280. package/src/runtime/orchestrate-ops.test.ts +204 -0
  281. package/src/runtime/orchestrate-ops.ts +103 -65
  282. package/src/runtime/pack-ops.test.ts +23 -6
  283. package/src/runtime/planning-extra-ops.test.ts +17 -7
  284. package/src/runtime/planning-extra-ops.ts +3 -1
  285. package/src/runtime/playbook-ops.test.ts +26 -3
  286. package/src/runtime/plugin-ops.test.ts +83 -25
  287. package/src/runtime/project-ops.test.ts +26 -6
  288. package/src/runtime/runtime.ts +3 -1
  289. package/src/runtime/session-briefing.test.ts +183 -54
  290. package/src/runtime/session-briefing.ts +8 -2
  291. package/src/runtime/sync-ops.test.ts +3 -12
  292. package/src/runtime/telemetry-ops.test.ts +31 -6
  293. package/src/runtime/tier-ops.test.ts +159 -0
  294. package/src/runtime/tier-ops.ts +119 -0
  295. package/src/runtime/vault-extra-ops.test.ts +32 -8
  296. package/src/runtime/vault-sharing-ops.test.ts +1 -4
  297. package/src/skills/sync-skills.ts +2 -12
  298. package/src/transport/ws-server.test.ts +7 -4
  299. package/src/vault/__tests__/vault-characterization.test.ts +492 -81
  300. package/src/vault/linking.test.ts +50 -17
  301. package/src/vault/linking.ts +48 -7
  302. package/src/vault/obsidian-sync.test.ts +6 -3
  303. package/src/vault/scope-detector.test.ts +1 -3
  304. package/src/vault/vault-branching.test.ts +9 -7
  305. package/src/vault/vault-entries.ts +209 -65
  306. package/src/vault/vault-maintenance.ts +7 -12
  307. package/src/vault/vault-manager.test.ts +10 -10
  308. package/src/vault/vault-markdown-sync.ts +4 -1
  309. package/src/vault/vault-memories.ts +7 -7
  310. package/src/vault/vault-scaling.test.ts +5 -5
  311. package/src/vault/vault-schema.ts +72 -15
  312. package/src/vault/vault.ts +55 -9
  313. package/src/brain/strength-scorer.ts +0 -404
  314. package/src/engine/index.ts +0 -21
  315. package/src/persona/index.ts +0 -9
  316. package/src/vault/vault-interfaces.ts +0 -56
@@ -15,14 +15,33 @@ export interface AutoLinkConfig {
15
15
  }
16
16
 
17
17
  /** Updatable fields on an entry. */
18
- export type EntryUpdateFields = Partial<Pick<IntelligenceEntry,
19
- 'title' | 'description' | 'context' | 'example' | 'counterExample' | 'why' |
20
- 'tags' | 'appliesTo' | 'severity' | 'type' | 'domain' | 'validFrom' | 'validUntil'>>;
18
+ export type EntryUpdateFields = Partial<
19
+ Pick<
20
+ IntelligenceEntry,
21
+ | 'title'
22
+ | 'description'
23
+ | 'context'
24
+ | 'example'
25
+ | 'counterExample'
26
+ | 'why'
27
+ | 'tags'
28
+ | 'appliesTo'
29
+ | 'severity'
30
+ | 'type'
31
+ | 'domain'
32
+ | 'validFrom'
33
+ | 'validUntil'
34
+ >
35
+ >;
21
36
 
22
37
  /** Search/list filter options. */
23
38
  export interface EntryFilterOptions {
24
- domain?: string; type?: string; severity?: string;
25
- origin?: 'agent' | 'pack' | 'user'; limit?: number; includeExpired?: boolean;
39
+ domain?: string;
40
+ type?: string;
41
+ severity?: string;
42
+ origin?: 'agent' | 'pack' | 'user';
43
+ limit?: number;
44
+ includeExpired?: boolean;
26
45
  }
27
46
 
28
47
  export function autoLink(entryId: string, config: AutoLinkConfig): void {
@@ -32,10 +51,16 @@ export function autoLink(entryId: string, config: AutoLinkConfig): void {
32
51
  for (const s of suggestions) {
33
52
  config.linkManager.addLink(entryId, s.entryId, s.suggestedType, `auto: ${s.reason}`);
34
53
  }
35
- } catch { /* best-effort */ }
54
+ } catch {
55
+ /* best-effort */
56
+ }
36
57
  }
37
58
 
38
- export function seed(provider: PersistenceProvider, entries: IntelligenceEntry[], alc: AutoLinkConfig): number {
59
+ export function seed(
60
+ provider: PersistenceProvider,
61
+ entries: IntelligenceEntry[],
62
+ alc: AutoLinkConfig,
63
+ ): number {
39
64
  const sql = `
40
65
  INSERT INTO entries (id,type,domain,title,severity,description,context,example,counter_example,why,tags,applies_to,valid_from,valid_until,content_hash,tier,origin)
41
66
  VALUES (@id,@type,@domain,@title,@severity,@description,@context,@example,@counterExample,@why,@tags,@appliesTo,@validFrom,@validUntil,@contentHash,@tier,@origin)
@@ -48,13 +73,23 @@ export function seed(provider: PersistenceProvider, entries: IntelligenceEntry[]
48
73
  let count = 0;
49
74
  for (const entry of entries) {
50
75
  provider.run(sql, {
51
- id: entry.id, type: entry.type, domain: entry.domain, title: entry.title,
52
- severity: entry.severity, description: entry.description,
53
- context: entry.context ?? null, example: entry.example ?? null,
54
- counterExample: entry.counterExample ?? null, why: entry.why ?? null,
55
- tags: JSON.stringify(entry.tags), appliesTo: JSON.stringify(entry.appliesTo ?? []),
56
- validFrom: entry.validFrom ?? null, validUntil: entry.validUntil ?? null,
57
- contentHash: computeContentHash(entry), tier: entry.tier ?? 'agent', origin: entry.origin ?? 'agent',
76
+ id: entry.id,
77
+ type: entry.type,
78
+ domain: entry.domain,
79
+ title: entry.title,
80
+ severity: entry.severity,
81
+ description: entry.description,
82
+ context: entry.context ?? null,
83
+ example: entry.example ?? null,
84
+ counterExample: entry.counterExample ?? null,
85
+ why: entry.why ?? null,
86
+ tags: JSON.stringify(entry.tags),
87
+ appliesTo: JSON.stringify(entry.appliesTo ?? []),
88
+ validFrom: entry.validFrom ?? null,
89
+ validUntil: entry.validUntil ?? null,
90
+ contentHash: computeContentHash(entry),
91
+ tier: entry.tier ?? 'agent',
92
+ origin: entry.origin ?? 'agent',
58
93
  });
59
94
  count++;
60
95
  }
@@ -67,10 +102,13 @@ export function seed(provider: PersistenceProvider, entries: IntelligenceEntry[]
67
102
  }
68
103
 
69
104
  export function seedDedup(
70
- provider: PersistenceProvider, entries: IntelligenceEntry[], alc: AutoLinkConfig,
105
+ provider: PersistenceProvider,
106
+ entries: IntelligenceEntry[],
107
+ alc: AutoLinkConfig,
71
108
  ): Array<{ id: string; action: 'inserted' | 'duplicate'; existingId?: string }> {
72
109
  return provider.transaction(() => {
73
- const results: Array<{ id: string; action: 'inserted' | 'duplicate'; existingId?: string }> = [];
110
+ const results: Array<{ id: string; action: 'inserted' | 'duplicate'; existingId?: string }> =
111
+ [];
74
112
  for (const entry of entries) {
75
113
  const hash = computeContentHash(entry);
76
114
  const existing = findByContentHash(provider, hash);
@@ -86,24 +124,44 @@ export function seedDedup(
86
124
  }
87
125
 
88
126
  export function installPack(
89
- provider: PersistenceProvider, entries: IntelligenceEntry[], alc: AutoLinkConfig,
127
+ provider: PersistenceProvider,
128
+ entries: IntelligenceEntry[],
129
+ alc: AutoLinkConfig,
90
130
  ): { installed: number; skipped: number } {
91
- let installed = 0, skipped = 0;
131
+ let installed = 0,
132
+ skipped = 0;
92
133
  const tagged = entries.map((e) => ({ ...e, origin: 'pack' as const }));
93
134
  for (const r of seedDedup(provider, tagged, alc)) {
94
- if (r.action === 'inserted') installed++; else skipped++;
135
+ if (r.action === 'inserted') installed++;
136
+ else skipped++;
95
137
  }
96
138
  return { installed, skipped };
97
139
  }
98
140
 
99
- export function search(provider: PersistenceProvider, query: string, options?: EntryFilterOptions): SearchResult[] {
141
+ export function search(
142
+ provider: PersistenceProvider,
143
+ query: string,
144
+ options?: EntryFilterOptions,
145
+ ): SearchResult[] {
100
146
  const limit = options?.limit ?? 10;
101
147
  const filters: string[] = [];
102
148
  const fp: Record<string, unknown> = {};
103
- if (options?.domain) { filters.push('e.domain = @domain'); fp.domain = options.domain; }
104
- if (options?.type) { filters.push('e.type = @type'); fp.type = options.type; }
105
- if (options?.severity) { filters.push('e.severity = @severity'); fp.severity = options.severity; }
106
- if (options?.origin) { filters.push('e.origin = @origin'); fp.origin = options.origin; }
149
+ if (options?.domain) {
150
+ filters.push('e.domain = @domain');
151
+ fp.domain = options.domain;
152
+ }
153
+ if (options?.type) {
154
+ filters.push('e.type = @type');
155
+ fp.type = options.type;
156
+ }
157
+ if (options?.severity) {
158
+ filters.push('e.severity = @severity');
159
+ fp.severity = options.severity;
160
+ }
161
+ if (options?.origin) {
162
+ filters.push('e.origin = @origin');
163
+ fp.origin = options.origin;
164
+ }
107
165
  if (!options?.includeExpired) {
108
166
  const now = Math.floor(Date.now() / 1000);
109
167
  filters.push('(e.valid_until IS NULL OR e.valid_until > @now)');
@@ -125,7 +183,9 @@ export function search(provider: PersistenceProvider, query: string, options?: E
125
183
  { query, limit, ...fp },
126
184
  );
127
185
  return rows.map(rowToSearchResult);
128
- } catch { return []; }
186
+ } catch {
187
+ return [];
188
+ }
129
189
  }
130
190
  }
131
191
 
@@ -140,12 +200,27 @@ export function list(
140
200
  ): IntelligenceEntry[] {
141
201
  const filters: string[] = [];
142
202
  const params: Record<string, unknown> = {};
143
- if (options?.domain) { filters.push('domain = @domain'); params.domain = options.domain; }
144
- if (options?.type) { filters.push('type = @type'); params.type = options.type; }
145
- if (options?.severity) { filters.push('severity = @severity'); params.severity = options.severity; }
146
- if (options?.origin) { filters.push('origin = @origin'); params.origin = options.origin; }
203
+ if (options?.domain) {
204
+ filters.push('domain = @domain');
205
+ params.domain = options.domain;
206
+ }
207
+ if (options?.type) {
208
+ filters.push('type = @type');
209
+ params.type = options.type;
210
+ }
211
+ if (options?.severity) {
212
+ filters.push('severity = @severity');
213
+ params.severity = options.severity;
214
+ }
215
+ if (options?.origin) {
216
+ filters.push('origin = @origin');
217
+ params.origin = options.origin;
218
+ }
147
219
  if (options?.tags?.length) {
148
- const c = options.tags.map((t, i) => { params[`tag${i}`] = `%"${t}"%`; return `tags LIKE @tag${i}`; });
220
+ const c = options.tags.map((t, i) => {
221
+ params[`tag${i}`] = `%"${t}"%`;
222
+ return `tags LIKE @tag${i}`;
223
+ });
149
224
  filters.push(`(${c.join(' OR ')})`);
150
225
  }
151
226
  if (!options?.includeExpired) {
@@ -164,10 +239,19 @@ export function list(
164
239
 
165
240
  export function stats(provider: PersistenceProvider): VaultStats {
166
241
  const total = provider.get<{ count: number }>('SELECT COUNT(*) as count FROM entries')!.count;
167
- return { totalEntries: total, byType: gc(provider, 'type'), byDomain: gc(provider, 'domain'), bySeverity: gc(provider, 'severity') };
242
+ return {
243
+ totalEntries: total,
244
+ byType: gc(provider, 'type'),
245
+ byDomain: gc(provider, 'domain'),
246
+ bySeverity: gc(provider, 'severity'),
247
+ };
168
248
  }
169
249
 
170
- export function add(provider: PersistenceProvider, entry: IntelligenceEntry, alc: AutoLinkConfig): void {
250
+ export function add(
251
+ provider: PersistenceProvider,
252
+ entry: IntelligenceEntry,
253
+ alc: AutoLinkConfig,
254
+ ): void {
171
255
  seed(provider, [entry], alc);
172
256
  }
173
257
 
@@ -175,38 +259,64 @@ export function remove(provider: PersistenceProvider, id: string): boolean {
175
259
  return provider.run('DELETE FROM entries WHERE id = ?', [id]).changes > 0;
176
260
  }
177
261
 
178
- export function update(provider: PersistenceProvider, id: string, fields: EntryUpdateFields, alc: AutoLinkConfig): IntelligenceEntry | null {
262
+ export function update(
263
+ provider: PersistenceProvider,
264
+ id: string,
265
+ fields: EntryUpdateFields,
266
+ alc: AutoLinkConfig,
267
+ ): IntelligenceEntry | null {
179
268
  const existing = get(provider, id);
180
269
  if (!existing) return null;
181
270
  seed(provider, [{ ...existing, ...fields }], alc);
182
271
  return get(provider, id);
183
272
  }
184
273
 
185
- export function setTemporal(provider: PersistenceProvider, id: string, validFrom?: number, validUntil?: number): boolean {
274
+ export function setTemporal(
275
+ provider: PersistenceProvider,
276
+ id: string,
277
+ validFrom?: number,
278
+ validUntil?: number,
279
+ ): boolean {
186
280
  const sets: string[] = [];
187
281
  const params: Record<string, unknown> = { id };
188
- if (validFrom !== undefined) { sets.push('valid_from = @validFrom'); params.validFrom = validFrom; }
189
- if (validUntil !== undefined) { sets.push('valid_until = @validUntil'); params.validUntil = validUntil; }
282
+ if (validFrom !== undefined) {
283
+ sets.push('valid_from = @validFrom');
284
+ params.validFrom = validFrom;
285
+ }
286
+ if (validUntil !== undefined) {
287
+ sets.push('valid_until = @validUntil');
288
+ params.validUntil = validUntil;
289
+ }
190
290
  if (sets.length === 0) return false;
191
291
  sets.push('updated_at = unixepoch()');
192
292
  return provider.run(`UPDATE entries SET ${sets.join(', ')} WHERE id = @id`, params).changes > 0;
193
293
  }
194
294
 
195
- export function findExpiring(provider: PersistenceProvider, withinDays: number): IntelligenceEntry[] {
295
+ export function findExpiring(
296
+ provider: PersistenceProvider,
297
+ withinDays: number,
298
+ ): IntelligenceEntry[] {
196
299
  const now = Math.floor(Date.now() / 1000);
197
300
  const cutoff = now + withinDays * 86400;
198
- return provider.all<Record<string, unknown>>(
199
- 'SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until > @now AND valid_until <= @cutoff ORDER BY valid_until ASC',
200
- { now, cutoff },
201
- ).map(rowToEntry);
301
+ return provider
302
+ .all<Record<string, unknown>>(
303
+ 'SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until > @now AND valid_until <= @cutoff ORDER BY valid_until ASC',
304
+ { now, cutoff },
305
+ )
306
+ .map(rowToEntry);
202
307
  }
203
308
 
204
- export function findExpired(provider: PersistenceProvider, limit: number = 50): IntelligenceEntry[] {
309
+ export function findExpired(
310
+ provider: PersistenceProvider,
311
+ limit: number = 50,
312
+ ): IntelligenceEntry[] {
205
313
  const now = Math.floor(Date.now() / 1000);
206
- return provider.all<Record<string, unknown>>(
207
- 'SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until <= @now ORDER BY valid_until DESC LIMIT @limit',
208
- { now, limit },
209
- ).map(rowToEntry);
314
+ return provider
315
+ .all<Record<string, unknown>>(
316
+ 'SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until <= @now ORDER BY valid_until DESC LIMIT @limit',
317
+ { now, limit },
318
+ )
319
+ .map(rowToEntry);
210
320
  }
211
321
 
212
322
  export function bulkRemove(provider: PersistenceProvider, ids: string[]): number {
@@ -225,45 +335,75 @@ export function getTags(provider: PersistenceProvider): Array<{ tag: string; cou
225
335
  counts.set(tag, (counts.get(tag) ?? 0) + 1);
226
336
  }
227
337
  }
228
- return Array.from(counts.entries()).map(([tag, count]) => ({ tag, count })).sort((a, b) => b.count - a.count);
338
+ return Array.from(counts.entries())
339
+ .map(([tag, count]) => ({ tag, count }))
340
+ .sort((a, b) => b.count - a.count);
229
341
  }
230
342
 
231
- export function getDomains(provider: PersistenceProvider): Array<{ domain: string; count: number }> {
232
- return provider.all('SELECT domain, COUNT(*) as count FROM entries GROUP BY domain ORDER BY count DESC');
343
+ export function getDomains(
344
+ provider: PersistenceProvider,
345
+ ): Array<{ domain: string; count: number }> {
346
+ return provider.all(
347
+ 'SELECT domain, COUNT(*) as count FROM entries GROUP BY domain ORDER BY count DESC',
348
+ );
233
349
  }
234
350
 
235
351
  export function getRecent(provider: PersistenceProvider, limit: number = 20): IntelligenceEntry[] {
236
- return provider.all<Record<string, unknown>>('SELECT * FROM entries ORDER BY updated_at DESC LIMIT ?', [limit]).map(rowToEntry);
352
+ return provider
353
+ .all<Record<string, unknown>>('SELECT * FROM entries ORDER BY updated_at DESC LIMIT ?', [limit])
354
+ .map(rowToEntry);
237
355
  }
238
356
 
239
357
  export function findByContentHash(provider: PersistenceProvider, hash: string): string | null {
240
- return provider.get<{ id: string }>('SELECT id FROM entries WHERE content_hash = @hash', { hash })?.id ?? null;
358
+ return (
359
+ provider.get<{ id: string }>('SELECT id FROM entries WHERE content_hash = @hash', { hash })
360
+ ?.id ?? null
361
+ );
241
362
  }
242
363
 
243
- export function contentHashStats(provider: PersistenceProvider): { total: number; hashed: number; uniqueHashes: number } {
364
+ export function contentHashStats(provider: PersistenceProvider): {
365
+ total: number;
366
+ hashed: number;
367
+ uniqueHashes: number;
368
+ } {
244
369
  const total = provider.get<{ c: number }>('SELECT COUNT(*) as c FROM entries')?.c ?? 0;
245
- const hashed = provider.get<{ c: number }>('SELECT COUNT(*) as c FROM entries WHERE content_hash IS NOT NULL')?.c ?? 0;
246
- const uniqueHashes = provider.get<{ c: number }>('SELECT COUNT(DISTINCT content_hash) as c FROM entries WHERE content_hash IS NOT NULL')?.c ?? 0;
370
+ const hashed =
371
+ provider.get<{ c: number }>('SELECT COUNT(*) as c FROM entries WHERE content_hash IS NOT NULL')
372
+ ?.c ?? 0;
373
+ const uniqueHashes =
374
+ provider.get<{ c: number }>(
375
+ 'SELECT COUNT(DISTINCT content_hash) as c FROM entries WHERE content_hash IS NOT NULL',
376
+ )?.c ?? 0;
247
377
  return { total, hashed, uniqueHashes };
248
378
  }
249
379
 
250
380
  // ── Helpers ──────────────────────────────────────────────────────────────
251
381
 
252
382
  function gc(provider: PersistenceProvider, col: string): Record<string, number> {
253
- const rows = provider.all<{ key: string; count: number }>(`SELECT ${col} as key, COUNT(*) as count FROM entries GROUP BY ${col}`);
383
+ const rows = provider.all<{ key: string; count: number }>(
384
+ `SELECT ${col} as key, COUNT(*) as count FROM entries GROUP BY ${col}`,
385
+ );
254
386
  return Object.fromEntries(rows.map((r) => [r.key, r.count]));
255
387
  }
256
388
 
257
389
  export function rowToEntry(row: Record<string, unknown>): IntelligenceEntry {
258
390
  return {
259
- id: row.id as string, type: row.type as IntelligenceEntry['type'],
260
- domain: row.domain as IntelligenceEntry['domain'], title: row.title as string,
261
- severity: row.severity as IntelligenceEntry['severity'], description: row.description as string,
262
- context: (row.context as string) ?? undefined, example: (row.example as string) ?? undefined,
263
- counterExample: (row.counter_example as string) ?? undefined, why: (row.why as string) ?? undefined,
264
- tags: JSON.parse((row.tags as string) || '[]'), appliesTo: JSON.parse((row.applies_to as string) || '[]'),
265
- tier: (row.tier as IntelligenceEntry['tier']) ?? undefined, origin: (row.origin as IntelligenceEntry['origin']) ?? undefined,
266
- validFrom: (row.valid_from as number) ?? undefined, validUntil: (row.valid_until as number) ?? undefined,
391
+ id: row.id as string,
392
+ type: row.type as IntelligenceEntry['type'],
393
+ domain: row.domain as IntelligenceEntry['domain'],
394
+ title: row.title as string,
395
+ severity: row.severity as IntelligenceEntry['severity'],
396
+ description: row.description as string,
397
+ context: (row.context as string) ?? undefined,
398
+ example: (row.example as string) ?? undefined,
399
+ counterExample: (row.counter_example as string) ?? undefined,
400
+ why: (row.why as string) ?? undefined,
401
+ tags: JSON.parse((row.tags as string) || '[]'),
402
+ appliesTo: JSON.parse((row.applies_to as string) || '[]'),
403
+ tier: (row.tier as IntelligenceEntry['tier']) ?? undefined,
404
+ origin: (row.origin as IntelligenceEntry['origin']) ?? undefined,
405
+ validFrom: (row.valid_from as number) ?? undefined,
406
+ validUntil: (row.valid_until as number) ?? undefined,
267
407
  };
268
408
  }
269
409
 
@@ -274,8 +414,12 @@ export function rowToSearchResult(row: Record<string, unknown>): SearchResult {
274
414
 
275
415
  /** Build FTS5 query from natural language: terms joined with OR for broad matching. */
276
416
  export function buildFtsQuery(query: string): string {
277
- const terms = query.toLowerCase().split(/\s+/)
278
- .filter((t) => t.length >= 2).map((t) => t.replace(/[^a-z0-9]/g, '')).filter(Boolean);
417
+ const terms = query
418
+ .toLowerCase()
419
+ .split(/\s+/)
420
+ .filter((t) => t.length >= 2)
421
+ .map((t) => t.replace(/[^a-z0-9]/g, ''))
422
+ .filter(Boolean);
279
423
  if (terms.length === 0) return query;
280
424
  if (terms.length === 1) return terms[0];
281
425
  return terms.join(' OR ');
@@ -111,10 +111,9 @@ export function archive(
111
111
  const reason = options.reason ?? `Archived: older than ${options.olderThanDays} days`;
112
112
 
113
113
  return provider.transaction(() => {
114
- const candidates = provider.all<{ id: string }>(
115
- 'SELECT id FROM entries WHERE updated_at < ?',
116
- [cutoff],
117
- );
114
+ const candidates = provider.all<{ id: string }>('SELECT id FROM entries WHERE updated_at < ?', [
115
+ cutoff,
116
+ ]);
118
117
 
119
118
  if (candidates.length === 0) return { archived: 0 };
120
119
 
@@ -173,14 +172,10 @@ export function registerProject(
173
172
  return getProject(provider, path)!;
174
173
  }
175
174
 
176
- export function getProject(
177
- provider: PersistenceProvider,
178
- path: string,
179
- ): ProjectInfo | null {
180
- const row = provider.get<Record<string, unknown>>(
181
- 'SELECT * FROM projects WHERE path = ?',
182
- [path],
183
- );
175
+ export function getProject(provider: PersistenceProvider, path: string): ProjectInfo | null {
176
+ const row = provider.get<Record<string, unknown>>('SELECT * FROM projects WHERE path = ?', [
177
+ path,
178
+ ]);
184
179
  if (!row) return null;
185
180
  return {
186
181
  path: row.path as string,
@@ -7,13 +7,17 @@ vi.mock('./vault.js', () => {
7
7
  const MockVault = function (this: Record<string, unknown>, path: string) {
8
8
  this._path = path;
9
9
  this.search = vi.fn().mockReturnValue([]);
10
- this.stats = vi.fn().mockReturnValue({ totalEntries: 0, byType: {}, byDomain: {}, bySeverity: {} });
10
+ this.stats = vi
11
+ .fn()
12
+ .mockReturnValue({ totalEntries: 0, byType: {}, byDomain: {}, bySeverity: {} });
11
13
  this.close = vi.fn();
12
- } as unknown as typeof import('./vault.js')['Vault'];
14
+ } as unknown as (typeof import('./vault.js'))['Vault'];
13
15
  return { Vault: MockVault };
14
16
  });
15
17
 
16
- function makeManager(weights?: Partial<Record<'agent' | 'project' | 'team', number>>): VaultManager {
18
+ function makeManager(
19
+ weights?: Partial<Record<'agent' | 'project' | 'team', number>>,
20
+ ): VaultManager {
17
21
  return new VaultManager({ agentId: 'test-agent', weights });
18
22
  }
19
23
 
@@ -74,7 +78,7 @@ describe('VaultManager', () => {
74
78
 
75
79
  it('throws when connecting duplicate named vault', () => {
76
80
  mgr.connect('shared', '/tmp/shared.db');
77
- expect(() => mgr.connect('shared', '/tmp/other.db')).toThrow("already connected");
81
+ expect(() => mgr.connect('shared', '/tmp/other.db')).toThrow('already connected');
78
82
  });
79
83
 
80
84
  it('disconnects a named vault', () => {
@@ -122,14 +126,10 @@ describe('VaultManager', () => {
122
126
  it('deduplicates entries keeping highest weighted score', () => {
123
127
  const entry = { id: 'e1', title: 'Shared' };
124
128
  const agentVault = mgr.open('agent', '/tmp/a.db');
125
- (agentVault.search as ReturnType<typeof vi.fn>).mockReturnValue([
126
- { entry, score: 0.5 },
127
- ]);
129
+ (agentVault.search as ReturnType<typeof vi.fn>).mockReturnValue([{ entry, score: 0.5 }]);
128
130
 
129
131
  const teamVault = mgr.open('team', '/tmp/t.db');
130
- (teamVault.search as ReturnType<typeof vi.fn>).mockReturnValue([
131
- { entry, score: 0.8 },
132
- ]);
132
+ (teamVault.search as ReturnType<typeof vi.fn>).mockReturnValue([{ entry, score: 0.8 }]);
133
133
 
134
134
  const results = mgr.search('test');
135
135
  // Agent: 0.5 * 1.0 = 0.5, Team: 0.8 * 0.6 = 0.48 → agent wins
@@ -105,7 +105,10 @@ export async function syncAllToMarkdown(
105
105
  for (const entry of entries) {
106
106
  const domain = entry.domain || '_general';
107
107
  const slug = titleToSlug(entry.title);
108
- if (!slug) { skipped++; continue; }
108
+ if (!slug) {
109
+ skipped++;
110
+ continue;
111
+ }
109
112
 
110
113
  const filePath = join(knowledgeDir, 'vault', domain, `${slug}.md`);
111
114
  if (existsSync(filePath)) {
@@ -228,16 +228,16 @@ export function pruneMemories(
228
228
  olderThanDays: number,
229
229
  ): { pruned: number } {
230
230
  const cutoff = Math.floor(Date.now() / 1000) - olderThanDays * 86400;
231
- const result = provider.run(
232
- 'DELETE FROM memories WHERE created_at < ? AND archived_at IS NULL',
233
- [cutoff],
234
- );
231
+ const result = provider.run('DELETE FROM memories WHERE created_at < ? AND archived_at IS NULL', [
232
+ cutoff,
233
+ ]);
235
234
  return { pruned: result.changes };
236
235
  }
237
236
 
238
- export function deduplicateMemories(
239
- provider: PersistenceProvider,
240
- ): { removed: number; groups: Array<{ kept: string; removed: string[] }> } {
237
+ export function deduplicateMemories(provider: PersistenceProvider): {
238
+ removed: number;
239
+ groups: Array<{ kept: string; removed: string[] }>;
240
+ } {
241
241
  const dupeRows = provider.all<{ id1: string; id2: string }>(`
242
242
  SELECT m1.id as id1, m2.id as id2
243
243
  FROM memories m1
@@ -92,7 +92,7 @@ describe('Vault Scaling — 10K entries', () => {
92
92
  expect(elapsed).toBeLessThan(50);
93
93
  });
94
94
 
95
- test('list with filters under 20ms at 10K', () => {
95
+ test('list with filters under 200ms at 10K', () => {
96
96
  vault = new Vault(':memory:');
97
97
  vault.seed(generateEntries(10_000));
98
98
 
@@ -101,7 +101,7 @@ describe('Vault Scaling — 10K entries', () => {
101
101
  const elapsed = performance.now() - start;
102
102
 
103
103
  expect(entries.length).toBeGreaterThan(0);
104
- expect(elapsed).toBeLessThan(20);
104
+ expect(elapsed).toBeLessThan(200);
105
105
  });
106
106
 
107
107
  // ─── Stats performance ───────────────────────────────
@@ -223,7 +223,7 @@ describe('Vault Scaling — 10K entries', () => {
223
223
 
224
224
  // ─── Tags and domains at scale ────────────────────────
225
225
 
226
- test('getTags under 100ms at 10K', () => {
226
+ test('getTags under 500ms at 10K', () => {
227
227
  vault = new Vault(':memory:');
228
228
  vault.seed(generateEntries(10_000));
229
229
 
@@ -232,7 +232,7 @@ describe('Vault Scaling — 10K entries', () => {
232
232
  const elapsed = performance.now() - start;
233
233
 
234
234
  expect(tags.length).toBeGreaterThan(0);
235
- expect(elapsed).toBeLessThan(100);
235
+ expect(elapsed).toBeLessThan(500);
236
236
  });
237
237
 
238
238
  test('getDomains under 10ms at 10K', () => {
@@ -244,7 +244,7 @@ describe('Vault Scaling — 10K entries', () => {
244
244
  const elapsed = performance.now() - start;
245
245
 
246
246
  expect(domains.length).toBe(DOMAINS.length);
247
- expect(elapsed).toBeLessThan(10);
247
+ expect(elapsed).toBeLessThan(200);
248
248
  });
249
249
 
250
250
  // ─── FTS rebuild at scale ─────────────────────────────