@cleocode/core 2026.9.7 → 2026.9.9

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 (565) hide show
  1. package/dist/audit/reconstruct.d.ts +13 -43
  2. package/dist/audit/reconstruct.d.ts.map +1 -1
  3. package/dist/audit/reconstruct.js +295 -290
  4. package/dist/audit/reconstruct.js.map +1 -1
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/bootstrap.js +8 -2
  7. package/dist/bootstrap.js.map +1 -1
  8. package/dist/dispatch/mutate-projection.d.ts.map +1 -1
  9. package/dist/dispatch/mutate-projection.js +12 -0
  10. package/dist/dispatch/mutate-projection.js.map +1 -1
  11. package/dist/dispatch/mvi-projection.d.ts +29 -6
  12. package/dist/dispatch/mvi-projection.d.ts.map +1 -1
  13. package/dist/dispatch/mvi-projection.js +109 -139
  14. package/dist/dispatch/mvi-projection.js.map +1 -1
  15. package/dist/docs/docs-read-model.d.ts +3 -2
  16. package/dist/docs/docs-read-model.d.ts.map +1 -1
  17. package/dist/docs/docs-read-model.js +4 -3
  18. package/dist/docs/docs-read-model.js.map +1 -1
  19. package/dist/docs/export-document.js +5100 -2297
  20. package/dist/docs/export-document.js.map +3 -3
  21. package/dist/docs/projection.d.ts +67 -0
  22. package/dist/docs/projection.d.ts.map +1 -0
  23. package/dist/docs/projection.js +370 -0
  24. package/dist/docs/projection.js.map +1 -0
  25. package/dist/doctor/acceptance-drift.d.ts +6 -2
  26. package/dist/doctor/acceptance-drift.d.ts.map +1 -1
  27. package/dist/doctor/acceptance-drift.js +43 -5
  28. package/dist/doctor/acceptance-drift.js.map +1 -1
  29. package/dist/doctor/knowledge-summary.d.ts +41 -0
  30. package/dist/doctor/knowledge-summary.d.ts.map +1 -0
  31. package/dist/doctor/knowledge-summary.js +81 -0
  32. package/dist/doctor/knowledge-summary.js.map +1 -0
  33. package/dist/doctor/knowledge.d.ts +192 -0
  34. package/dist/doctor/knowledge.d.ts.map +1 -0
  35. package/dist/doctor/knowledge.js +1864 -0
  36. package/dist/doctor/knowledge.js.map +1 -0
  37. package/dist/git/work-tree.d.ts +64 -0
  38. package/dist/git/work-tree.d.ts.map +1 -0
  39. package/dist/git/work-tree.js +111 -0
  40. package/dist/git/work-tree.js.map +1 -0
  41. package/dist/hooks/handlers/task-hooks.d.ts +8 -5
  42. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  43. package/dist/hooks/handlers/task-hooks.js +15 -60
  44. package/dist/hooks/handlers/task-hooks.js.map +1 -1
  45. package/dist/identity/cleo-identity.d.ts +13 -0
  46. package/dist/identity/cleo-identity.d.ts.map +1 -1
  47. package/dist/identity/cleo-identity.js +20 -6
  48. package/dist/identity/cleo-identity.js.map +1 -1
  49. package/dist/injection.d.ts.map +1 -1
  50. package/dist/injection.js +29 -13
  51. package/dist/injection.js.map +1 -1
  52. package/dist/internal.d.ts +2 -0
  53. package/dist/internal.d.ts.map +1 -1
  54. package/dist/internal.js +2 -0
  55. package/dist/internal.js.map +1 -1
  56. package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
  57. package/dist/lifecycle/verification/satisfies-validator.js +124 -120
  58. package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
  59. package/dist/llm/plugin-facade.js +4018 -1726
  60. package/dist/llm/plugin-facade.js.map +3 -3
  61. package/dist/memory/brain-backfill.d.ts +27 -12
  62. package/dist/memory/brain-backfill.d.ts.map +1 -1
  63. package/dist/memory/brain-backfill.js +325 -134
  64. package/dist/memory/brain-backfill.js.map +1 -1
  65. package/dist/memory/brain-doctor.d.ts +21 -0
  66. package/dist/memory/brain-doctor.d.ts.map +1 -1
  67. package/dist/memory/brain-doctor.js +111 -53
  68. package/dist/memory/brain-doctor.js.map +1 -1
  69. package/dist/memory/brain-links.d.ts.map +1 -1
  70. package/dist/memory/brain-links.js +31 -4
  71. package/dist/memory/brain-links.js.map +1 -1
  72. package/dist/memory/brain-reasoning.d.ts.map +1 -1
  73. package/dist/memory/brain-reasoning.js +28 -2
  74. package/dist/memory/brain-reasoning.js.map +1 -1
  75. package/dist/memory/brain-reconciler.d.ts +14 -19
  76. package/dist/memory/brain-reconciler.d.ts.map +1 -1
  77. package/dist/memory/brain-reconciler.js +70 -97
  78. package/dist/memory/brain-reconciler.js.map +1 -1
  79. package/dist/memory/brain-search.d.ts +2 -0
  80. package/dist/memory/brain-search.d.ts.map +1 -1
  81. package/dist/memory/brain-search.js +59 -29
  82. package/dist/memory/brain-search.js.map +1 -1
  83. package/dist/memory/brain-similarity.d.ts.map +1 -1
  84. package/dist/memory/brain-similarity.js +5 -4
  85. package/dist/memory/brain-similarity.js.map +1 -1
  86. package/dist/memory/brain-stub-prune.d.ts +31 -9
  87. package/dist/memory/brain-stub-prune.d.ts.map +1 -1
  88. package/dist/memory/brain-stub-prune.js +65 -18
  89. package/dist/memory/brain-stub-prune.js.map +1 -1
  90. package/dist/memory/brain-writer-handlers.d.ts +10 -1
  91. package/dist/memory/brain-writer-handlers.d.ts.map +1 -1
  92. package/dist/memory/brain-writer-handlers.js +23 -3
  93. package/dist/memory/brain-writer-handlers.js.map +1 -1
  94. package/dist/memory/brain-writer-thread.d.ts +31 -1
  95. package/dist/memory/brain-writer-thread.d.ts.map +1 -1
  96. package/dist/memory/brain-writer-thread.js +166 -24
  97. package/dist/memory/brain-writer-thread.js.map +1 -1
  98. package/dist/memory/brain-writer-worker.js +8 -1
  99. package/dist/memory/brain-writer-worker.js.map +1 -1
  100. package/dist/memory/decision-cross-link.d.ts +39 -0
  101. package/dist/memory/decision-cross-link.d.ts.map +1 -1
  102. package/dist/memory/decision-cross-link.js +316 -0
  103. package/dist/memory/decision-cross-link.js.map +1 -1
  104. package/dist/memory/decisions.d.ts +4 -1
  105. package/dist/memory/decisions.d.ts.map +1 -1
  106. package/dist/memory/decisions.js +7 -24
  107. package/dist/memory/decisions.js.map +1 -1
  108. package/dist/memory/dispatch-trace.d.ts +12 -5
  109. package/dist/memory/dispatch-trace.d.ts.map +1 -1
  110. package/dist/memory/dispatch-trace.js +17 -7
  111. package/dist/memory/dispatch-trace.js.map +1 -1
  112. package/dist/memory/eligibility.d.ts +51 -0
  113. package/dist/memory/eligibility.d.ts.map +1 -0
  114. package/dist/memory/eligibility.js +77 -0
  115. package/dist/memory/eligibility.js.map +1 -0
  116. package/dist/memory/engine-compat.d.ts +2 -0
  117. package/dist/memory/engine-compat.d.ts.map +1 -1
  118. package/dist/memory/engine-compat.js +10 -0
  119. package/dist/memory/engine-compat.js.map +1 -1
  120. package/dist/memory/extraction-gate.d.ts +21 -7
  121. package/dist/memory/extraction-gate.d.ts.map +1 -1
  122. package/dist/memory/extraction-gate.js +178 -216
  123. package/dist/memory/extraction-gate.js.map +1 -1
  124. package/dist/memory/graph-auto-populate.d.ts +38 -5
  125. package/dist/memory/graph-auto-populate.d.ts.map +1 -1
  126. package/dist/memory/graph-auto-populate.js +182 -60
  127. package/dist/memory/graph-auto-populate.js.map +1 -1
  128. package/dist/memory/graph-memory-bridge.d.ts +14 -1
  129. package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
  130. package/dist/memory/graph-memory-bridge.js +66 -28
  131. package/dist/memory/graph-memory-bridge.js.map +1 -1
  132. package/dist/memory/index.d.ts +1 -19
  133. package/dist/memory/index.d.ts.map +1 -1
  134. package/dist/memory/index.js +1 -50
  135. package/dist/memory/index.js.map +1 -1
  136. package/dist/memory/learnings.d.ts.map +1 -1
  137. package/dist/memory/learnings.js +2 -23
  138. package/dist/memory/learnings.js.map +1 -1
  139. package/dist/memory/manifest-filter.d.ts +21 -0
  140. package/dist/memory/manifest-filter.d.ts.map +1 -0
  141. package/dist/memory/manifest-filter.js +51 -0
  142. package/dist/memory/manifest-filter.js.map +1 -0
  143. package/dist/memory/manifest-ingestion.d.ts +28 -30
  144. package/dist/memory/manifest-ingestion.d.ts.map +1 -1
  145. package/dist/memory/manifest-ingestion.js +104 -235
  146. package/dist/memory/manifest-ingestion.js.map +1 -1
  147. package/dist/memory/observer-reflector.d.ts +2 -0
  148. package/dist/memory/observer-reflector.d.ts.map +1 -1
  149. package/dist/memory/observer-reflector.js +6 -49
  150. package/dist/memory/observer-reflector.js.map +1 -1
  151. package/dist/memory/patterns.d.ts +10 -0
  152. package/dist/memory/patterns.d.ts.map +1 -1
  153. package/dist/memory/patterns.js +25 -33
  154. package/dist/memory/patterns.js.map +1 -1
  155. package/dist/memory/pipeline-manifest-sqlite.d.ts +72 -9
  156. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  157. package/dist/memory/pipeline-manifest-sqlite.js +508 -412
  158. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  159. package/dist/memory/retrieval/build-retrieval-bundle.d.ts.map +1 -1
  160. package/dist/memory/retrieval/build-retrieval-bundle.js +16 -15
  161. package/dist/memory/retrieval/build-retrieval-bundle.js.map +1 -1
  162. package/dist/memory/retrieval/fetch.d.ts +7 -0
  163. package/dist/memory/retrieval/fetch.d.ts.map +1 -1
  164. package/dist/memory/retrieval/fetch.js +14 -11
  165. package/dist/memory/retrieval/fetch.js.map +1 -1
  166. package/dist/memory/retrieval/observe.d.ts +7 -1
  167. package/dist/memory/retrieval/observe.d.ts.map +1 -1
  168. package/dist/memory/retrieval/observe.js +58 -4
  169. package/dist/memory/retrieval/observe.js.map +1 -1
  170. package/dist/memory/retrieval/search.d.ts +14 -1
  171. package/dist/memory/retrieval/search.d.ts.map +1 -1
  172. package/dist/memory/retrieval/search.js +133 -69
  173. package/dist/memory/retrieval/search.js.map +1 -1
  174. package/dist/memory/retrieval/telemetry.d.ts +31 -0
  175. package/dist/memory/retrieval/telemetry.d.ts.map +1 -0
  176. package/dist/memory/retrieval/telemetry.js +53 -0
  177. package/dist/memory/retrieval/telemetry.js.map +1 -0
  178. package/dist/nexus/analyze-orchestrator.d.ts +41 -9
  179. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  180. package/dist/nexus/analyze-orchestrator.js +257 -58
  181. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  182. package/dist/nexus/api-contracts.d.ts +2 -6
  183. package/dist/nexus/api-contracts.d.ts.map +1 -1
  184. package/dist/nexus/api-contracts.js +11 -2
  185. package/dist/nexus/api-contracts.js.map +1 -1
  186. package/dist/nexus/context.d.ts.map +1 -1
  187. package/dist/nexus/context.js +14 -37
  188. package/dist/nexus/context.js.map +1 -1
  189. package/dist/nexus/diff.d.ts.map +1 -1
  190. package/dist/nexus/diff.js +2 -1
  191. package/dist/nexus/diff.js.map +1 -1
  192. package/dist/nexus/identity.d.ts +29 -3
  193. package/dist/nexus/identity.d.ts.map +1 -1
  194. package/dist/nexus/identity.js +63 -12
  195. package/dist/nexus/identity.js.map +1 -1
  196. package/dist/nexus/impact.d.ts +21 -19
  197. package/dist/nexus/impact.d.ts.map +1 -1
  198. package/dist/nexus/impact.js +96 -192
  199. package/dist/nexus/impact.js.map +1 -1
  200. package/dist/nexus/knowledge.d.ts +80 -0
  201. package/dist/nexus/knowledge.d.ts.map +1 -0
  202. package/dist/nexus/knowledge.js +786 -0
  203. package/dist/nexus/knowledge.js.map +1 -0
  204. package/dist/nexus/living-brain.d.ts +8 -5
  205. package/dist/nexus/living-brain.d.ts.map +1 -1
  206. package/dist/nexus/living-brain.js +252 -188
  207. package/dist/nexus/living-brain.js.map +1 -1
  208. package/dist/nexus/registry.d.ts +11 -2
  209. package/dist/nexus/registry.d.ts.map +1 -1
  210. package/dist/nexus/registry.js +144 -128
  211. package/dist/nexus/registry.js.map +1 -1
  212. package/dist/nexus/source-roots.d.ts +16 -0
  213. package/dist/nexus/source-roots.d.ts.map +1 -0
  214. package/dist/nexus/source-roots.js +174 -0
  215. package/dist/nexus/source-roots.js.map +1 -0
  216. package/dist/nexus/task-evidence.d.ts +22 -0
  217. package/dist/nexus/task-evidence.d.ts.map +1 -0
  218. package/dist/nexus/task-evidence.js +210 -0
  219. package/dist/nexus/task-evidence.js.map +1 -0
  220. package/dist/nexus/tasks-bridge.d.ts +14 -7
  221. package/dist/nexus/tasks-bridge.d.ts.map +1 -1
  222. package/dist/nexus/tasks-bridge.js +81 -40
  223. package/dist/nexus/tasks-bridge.js.map +1 -1
  224. package/dist/orchestrate/lifecycle-ops.d.ts.map +1 -1
  225. package/dist/orchestrate/lifecycle-ops.js +170 -120
  226. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  227. package/dist/orchestrate/query-ops.d.ts +6 -7
  228. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  229. package/dist/orchestrate/query-ops.js +509 -532
  230. package/dist/orchestrate/query-ops.js.map +1 -1
  231. package/dist/orchestration/bootstrap.d.ts +15 -1
  232. package/dist/orchestration/bootstrap.d.ts.map +1 -1
  233. package/dist/orchestration/bootstrap.js +21 -10
  234. package/dist/orchestration/bootstrap.js.map +1 -1
  235. package/dist/orchestration/index.d.ts +35 -3
  236. package/dist/orchestration/index.d.ts.map +1 -1
  237. package/dist/orchestration/index.js +64 -35
  238. package/dist/orchestration/index.js.map +1 -1
  239. package/dist/orchestration/lead-rollup.d.ts +24 -1
  240. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  241. package/dist/orchestration/lead-rollup.js +31 -11
  242. package/dist/orchestration/lead-rollup.js.map +1 -1
  243. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  244. package/dist/orchestration/spawn-prompt.js +16 -41
  245. package/dist/orchestration/spawn-prompt.js.map +1 -1
  246. package/dist/orchestration/unblock.d.ts +15 -1
  247. package/dist/orchestration/unblock.d.ts.map +1 -1
  248. package/dist/orchestration/unblock.js +23 -12
  249. package/dist/orchestration/unblock.js.map +1 -1
  250. package/dist/orchestration/validate-spawn.d.ts.map +1 -1
  251. package/dist/orchestration/validate-spawn.js +3 -3
  252. package/dist/orchestration/validate-spawn.js.map +1 -1
  253. package/dist/orchestration/waves.d.ts +29 -13
  254. package/dist/orchestration/waves.d.ts.map +1 -1
  255. package/dist/orchestration/waves.js +43 -55
  256. package/dist/orchestration/waves.js.map +1 -1
  257. package/dist/paths.d.ts +17 -163
  258. package/dist/paths.d.ts.map +1 -1
  259. package/dist/paths.js +145 -496
  260. package/dist/paths.js.map +1 -1
  261. package/dist/project-info.d.ts +2 -11
  262. package/dist/project-info.d.ts.map +1 -1
  263. package/dist/project-info.js +3 -31
  264. package/dist/project-info.js.map +1 -1
  265. package/dist/project-scope.d.ts +239 -0
  266. package/dist/project-scope.d.ts.map +1 -0
  267. package/dist/project-scope.js +473 -0
  268. package/dist/project-scope.js.map +1 -0
  269. package/dist/release/pr-evidence.d.ts +16 -3
  270. package/dist/release/pr-evidence.d.ts.map +1 -1
  271. package/dist/release/pr-evidence.js +53 -7
  272. package/dist/release/pr-evidence.js.map +1 -1
  273. package/dist/render/nexus/graph/index.d.ts.map +1 -1
  274. package/dist/render/nexus/graph/index.js +4 -2
  275. package/dist/render/nexus/graph/index.js.map +1 -1
  276. package/dist/render/orchestration/audit-reconstruct.d.ts +11 -0
  277. package/dist/render/orchestration/audit-reconstruct.d.ts.map +1 -1
  278. package/dist/render/orchestration/audit-reconstruct.js +21 -6
  279. package/dist/render/orchestration/audit-reconstruct.js.map +1 -1
  280. package/dist/render/tasks/show.js +2 -1
  281. package/dist/render/tasks/show.js.map +1 -1
  282. package/dist/resources/spawn-wrapper.d.ts +82 -14
  283. package/dist/resources/spawn-wrapper.d.ts.map +1 -1
  284. package/dist/resources/spawn-wrapper.js +585 -27
  285. package/dist/resources/spawn-wrapper.js.map +1 -1
  286. package/dist/selfimprove/fix-gen.js +4026 -1734
  287. package/dist/selfimprove/fix-gen.js.map +3 -3
  288. package/dist/sequence/index.d.ts.map +1 -1
  289. package/dist/sequence/index.js +76 -68
  290. package/dist/sequence/index.js.map +1 -1
  291. package/dist/session/canon-lint.d.ts +24 -3
  292. package/dist/session/canon-lint.d.ts.map +1 -1
  293. package/dist/session/canon-lint.js +72 -31
  294. package/dist/session/canon-lint.js.map +1 -1
  295. package/dist/session/engine-ops.d.ts +1 -4
  296. package/dist/session/engine-ops.d.ts.map +1 -1
  297. package/dist/session/engine-ops.js +6 -2
  298. package/dist/session/engine-ops.js.map +1 -1
  299. package/dist/sessions/briefing.d.ts +11 -1
  300. package/dist/sessions/briefing.d.ts.map +1 -1
  301. package/dist/sessions/briefing.js +76 -8
  302. package/dist/sessions/briefing.js.map +1 -1
  303. package/dist/sessions/handoff.d.ts +3 -1
  304. package/dist/sessions/handoff.d.ts.map +1 -1
  305. package/dist/sessions/handoff.js +2 -0
  306. package/dist/sessions/handoff.js.map +1 -1
  307. package/dist/shutdown-deadline.d.ts +24 -33
  308. package/dist/shutdown-deadline.d.ts.map +1 -1
  309. package/dist/shutdown-deadline.js +71 -14
  310. package/dist/shutdown-deadline.js.map +1 -1
  311. package/dist/shutdown.d.ts +21 -10
  312. package/dist/shutdown.d.ts.map +1 -1
  313. package/dist/shutdown.js +91 -35
  314. package/dist/shutdown.js.map +1 -1
  315. package/dist/skills/index.d.ts +1 -1
  316. package/dist/skills/index.d.ts.map +1 -1
  317. package/dist/skills/index.js +1 -1
  318. package/dist/skills/index.js.map +1 -1
  319. package/dist/skills/orchestrator/validator.d.ts +87 -20
  320. package/dist/skills/orchestrator/validator.d.ts.map +1 -1
  321. package/dist/skills/orchestrator/validator.js +330 -241
  322. package/dist/skills/orchestrator/validator.js.map +1 -1
  323. package/dist/store/agent-resolver.d.ts.map +1 -1
  324. package/dist/store/agent-resolver.js +16 -9
  325. package/dist/store/agent-resolver.js.map +1 -1
  326. package/dist/store/attachment-store.d.ts +4 -1
  327. package/dist/store/attachment-store.d.ts.map +1 -1
  328. package/dist/store/attachment-store.js +20 -3
  329. package/dist/store/attachment-store.js.map +1 -1
  330. package/dist/store/background-jobs.d.ts +426 -105
  331. package/dist/store/background-jobs.d.ts.map +1 -1
  332. package/dist/store/background-jobs.js +1208 -252
  333. package/dist/store/background-jobs.js.map +1 -1
  334. package/dist/store/background-ops.d.ts +145 -8
  335. package/dist/store/background-ops.d.ts.map +1 -1
  336. package/dist/store/background-ops.js +459 -15
  337. package/dist/store/background-ops.js.map +1 -1
  338. package/dist/store/backup-inspect.d.ts +48 -4
  339. package/dist/store/backup-inspect.d.ts.map +1 -1
  340. package/dist/store/backup-inspect.js +384 -4
  341. package/dist/store/backup-inspect.js.map +1 -1
  342. package/dist/store/converters.d.ts.map +1 -1
  343. package/dist/store/converters.js +19 -2
  344. package/dist/store/converters.js.map +1 -1
  345. package/dist/store/data-accessor.d.ts +9 -1
  346. package/dist/store/data-accessor.d.ts.map +1 -1
  347. package/dist/store/data-accessor.js +22 -5
  348. package/dist/store/data-accessor.js.map +1 -1
  349. package/dist/store/data-safety-central.d.ts.map +1 -1
  350. package/dist/store/data-safety-central.js +272 -232
  351. package/dist/store/data-safety-central.js.map +1 -1
  352. package/dist/store/db-helpers.d.ts +19 -3
  353. package/dist/store/db-helpers.d.ts.map +1 -1
  354. package/dist/store/db-helpers.js +42 -58
  355. package/dist/store/db-helpers.js.map +1 -1
  356. package/dist/store/dual-scope-db.d.ts +63 -4
  357. package/dist/store/dual-scope-db.d.ts.map +1 -1
  358. package/dist/store/dual-scope-db.js +166 -19
  359. package/dist/store/dual-scope-db.js.map +1 -1
  360. package/dist/store/exodus/archive.d.ts +21 -7
  361. package/dist/store/exodus/archive.d.ts.map +1 -1
  362. package/dist/store/exodus/archive.js +60 -18
  363. package/dist/store/exodus/archive.js.map +1 -1
  364. package/dist/store/exodus/migrate.d.ts.map +1 -1
  365. package/dist/store/exodus/migrate.js +27 -23
  366. package/dist/store/exodus/migrate.js.map +1 -1
  367. package/dist/store/exodus/on-open.d.ts +16 -27
  368. package/dist/store/exodus/on-open.d.ts.map +1 -1
  369. package/dist/store/exodus/on-open.js +121 -169
  370. package/dist/store/exodus/on-open.js.map +1 -1
  371. package/dist/store/exodus/recovery.d.ts +90 -0
  372. package/dist/store/exodus/recovery.d.ts.map +1 -0
  373. package/dist/store/exodus/recovery.js +434 -0
  374. package/dist/store/exodus/recovery.js.map +1 -0
  375. package/dist/store/exodus/types.d.ts +15 -0
  376. package/dist/store/exodus/types.d.ts.map +1 -1
  377. package/dist/store/memory-accessor.d.ts +52 -3
  378. package/dist/store/memory-accessor.d.ts.map +1 -1
  379. package/dist/store/memory-accessor.js +122 -7
  380. package/dist/store/memory-accessor.js.map +1 -1
  381. package/dist/store/nexus-sqlite.d.ts +24 -6
  382. package/dist/store/nexus-sqlite.d.ts.map +1 -1
  383. package/dist/store/nexus-sqlite.js +39 -20
  384. package/dist/store/nexus-sqlite.js.map +1 -1
  385. package/dist/store/ports/domain-binding.d.ts.map +1 -1
  386. package/dist/store/ports/domain-binding.js +27 -5
  387. package/dist/store/ports/domain-binding.js.map +1 -1
  388. package/dist/store/schema/background-jobs.d.ts +181 -2
  389. package/dist/store/schema/background-jobs.d.ts.map +1 -1
  390. package/dist/store/schema/background-jobs.js +27 -3
  391. package/dist/store/schema/background-jobs.js.map +1 -1
  392. package/dist/store/schema/cleo-global/skills.d.ts +2 -2
  393. package/dist/store/schema/cleo-project/lifecycle.d.ts +2 -2
  394. package/dist/store/schema/cleo-project/runtime.d.ts +1 -1
  395. package/dist/store/schema/cleo-project/tasks-core.d.ts +1 -1
  396. package/dist/store/schema/lifecycle.d.ts +2 -2
  397. package/dist/store/schema/skills-schema.d.ts +2 -2
  398. package/dist/store/schema/tasks.d.ts +1 -1
  399. package/dist/store/session-store.d.ts +3 -1
  400. package/dist/store/session-store.d.ts.map +1 -1
  401. package/dist/store/session-store.js +252 -207
  402. package/dist/store/session-store.js.map +1 -1
  403. package/dist/store/sqlite-data-accessor.d.ts +39 -4
  404. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  405. package/dist/store/sqlite-data-accessor.js +689 -527
  406. package/dist/store/sqlite-data-accessor.js.map +1 -1
  407. package/dist/store/tasks-sqlite.d.ts +3 -1
  408. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  409. package/dist/store/tasks-sqlite.js +309 -279
  410. package/dist/store/tasks-sqlite.js.map +1 -1
  411. package/dist/store/validation-schemas.d.ts +8 -8
  412. package/dist/store/writer-lease.d.ts +80 -8
  413. package/dist/store/writer-lease.d.ts.map +1 -1
  414. package/dist/store/writer-lease.js +503 -134
  415. package/dist/store/writer-lease.js.map +1 -1
  416. package/dist/system/audit.d.ts +2 -1
  417. package/dist/system/audit.d.ts.map +1 -1
  418. package/dist/system/audit.js +118 -71
  419. package/dist/system/audit.js.map +1 -1
  420. package/dist/system/backup.d.ts.map +1 -1
  421. package/dist/system/backup.js +5 -5
  422. package/dist/system/backup.js.map +1 -1
  423. package/dist/system/inject-generate.js +1 -1
  424. package/dist/task-work/index.d.ts +3 -0
  425. package/dist/task-work/index.d.ts.map +1 -1
  426. package/dist/task-work/index.js +34 -37
  427. package/dist/task-work/index.js.map +1 -1
  428. package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
  429. package/dist/tasks/ac-coverage-gate.js +4 -0
  430. package/dist/tasks/ac-coverage-gate.js.map +1 -1
  431. package/dist/tasks/ac-immutability.d.ts +7 -4
  432. package/dist/tasks/ac-immutability.d.ts.map +1 -1
  433. package/dist/tasks/ac-immutability.js +19 -17
  434. package/dist/tasks/ac-immutability.js.map +1 -1
  435. package/dist/tasks/ac-table.d.ts +5 -5
  436. package/dist/tasks/ac-table.d.ts.map +1 -1
  437. package/dist/tasks/ac-table.js +26 -12
  438. package/dist/tasks/ac-table.js.map +1 -1
  439. package/dist/tasks/acceptance-input.d.ts +52 -0
  440. package/dist/tasks/acceptance-input.d.ts.map +1 -0
  441. package/dist/tasks/acceptance-input.js +259 -0
  442. package/dist/tasks/acceptance-input.js.map +1 -0
  443. package/dist/tasks/add.d.ts +67 -29
  444. package/dist/tasks/add.d.ts.map +1 -1
  445. package/dist/tasks/add.js +255 -97
  446. package/dist/tasks/add.js.map +1 -1
  447. package/dist/tasks/complete.d.ts +16 -1
  448. package/dist/tasks/complete.d.ts.map +1 -1
  449. package/dist/tasks/complete.js +152 -55
  450. package/dist/tasks/complete.js.map +1 -1
  451. package/dist/tasks/decompose.d.ts +103 -0
  452. package/dist/tasks/decompose.d.ts.map +1 -0
  453. package/dist/tasks/decompose.js +224 -0
  454. package/dist/tasks/decompose.js.map +1 -0
  455. package/dist/tasks/delete.d.ts +5 -8
  456. package/dist/tasks/delete.d.ts.map +1 -1
  457. package/dist/tasks/delete.js +4 -3
  458. package/dist/tasks/delete.js.map +1 -1
  459. package/dist/tasks/dependency-check.d.ts +59 -0
  460. package/dist/tasks/dependency-check.d.ts.map +1 -1
  461. package/dist/tasks/dependency-check.js +73 -0
  462. package/dist/tasks/dependency-check.js.map +1 -1
  463. package/dist/tasks/deps-ready.d.ts +13 -1
  464. package/dist/tasks/deps-ready.d.ts.map +1 -1
  465. package/dist/tasks/deps-ready.js +16 -5
  466. package/dist/tasks/deps-ready.js.map +1 -1
  467. package/dist/tasks/engine-converters.d.ts +7 -0
  468. package/dist/tasks/engine-converters.d.ts.map +1 -1
  469. package/dist/tasks/engine-converters.js +8 -1
  470. package/dist/tasks/engine-converters.js.map +1 -1
  471. package/dist/tasks/evidence.d.ts +54 -26
  472. package/dist/tasks/evidence.d.ts.map +1 -1
  473. package/dist/tasks/evidence.js +292 -40
  474. package/dist/tasks/evidence.js.map +1 -1
  475. package/dist/tasks/find.d.ts +16 -12
  476. package/dist/tasks/find.d.ts.map +1 -1
  477. package/dist/tasks/find.js +107 -93
  478. package/dist/tasks/find.js.map +1 -1
  479. package/dist/tasks/gate-runner.d.ts +88 -14
  480. package/dist/tasks/gate-runner.d.ts.map +1 -1
  481. package/dist/tasks/gate-runner.js +596 -253
  482. package/dist/tasks/gate-runner.js.map +1 -1
  483. package/dist/tasks/hierarchy-policy.d.ts +8 -0
  484. package/dist/tasks/hierarchy-policy.d.ts.map +1 -1
  485. package/dist/tasks/hierarchy-policy.js +9 -2
  486. package/dist/tasks/hierarchy-policy.js.map +1 -1
  487. package/dist/tasks/hierarchy.d.ts +67 -1
  488. package/dist/tasks/hierarchy.d.ts.map +1 -1
  489. package/dist/tasks/hierarchy.js +81 -1
  490. package/dist/tasks/hierarchy.js.map +1 -1
  491. package/dist/tasks/index.d.ts +3 -0
  492. package/dist/tasks/index.d.ts.map +1 -1
  493. package/dist/tasks/index.js +3 -0
  494. package/dist/tasks/index.js.map +1 -1
  495. package/dist/tasks/infer-add-params.d.ts +1 -20
  496. package/dist/tasks/infer-add-params.d.ts.map +1 -1
  497. package/dist/tasks/infer-add-params.js +2 -203
  498. package/dist/tasks/infer-add-params.js.map +1 -1
  499. package/dist/tasks/list.d.ts +7 -2
  500. package/dist/tasks/list.d.ts.map +1 -1
  501. package/dist/tasks/list.js +24 -36
  502. package/dist/tasks/list.js.map +1 -1
  503. package/dist/tasks/ops.d.ts +6 -61
  504. package/dist/tasks/ops.d.ts.map +1 -1
  505. package/dist/tasks/ops.js +5 -53
  506. package/dist/tasks/ops.js.map +1 -1
  507. package/dist/tasks/plan.d.ts +15 -1
  508. package/dist/tasks/plan.d.ts.map +1 -1
  509. package/dist/tasks/plan.js +23 -25
  510. package/dist/tasks/plan.js.map +1 -1
  511. package/dist/tasks/population.d.ts +46 -0
  512. package/dist/tasks/population.d.ts.map +1 -0
  513. package/dist/tasks/population.js +88 -0
  514. package/dist/tasks/population.js.map +1 -0
  515. package/dist/tasks/reconcile-scope.d.ts +157 -0
  516. package/dist/tasks/reconcile-scope.d.ts.map +1 -0
  517. package/dist/tasks/reconcile-scope.js +242 -0
  518. package/dist/tasks/reconcile-scope.js.map +1 -0
  519. package/dist/tasks/req.d.ts +51 -12
  520. package/dist/tasks/req.d.ts.map +1 -1
  521. package/dist/tasks/req.js +125 -69
  522. package/dist/tasks/req.js.map +1 -1
  523. package/dist/tasks/session-scope.d.ts +6 -31
  524. package/dist/tasks/session-scope.d.ts.map +1 -1
  525. package/dist/tasks/session-scope.js +3 -17
  526. package/dist/tasks/session-scope.js.map +1 -1
  527. package/dist/tasks/severity-attestation.d.ts +39 -10
  528. package/dist/tasks/severity-attestation.d.ts.map +1 -1
  529. package/dist/tasks/severity-attestation.js +75 -36
  530. package/dist/tasks/severity-attestation.js.map +1 -1
  531. package/dist/tasks/task-next.d.ts +5 -0
  532. package/dist/tasks/task-next.d.ts.map +1 -1
  533. package/dist/tasks/task-next.js +10 -9
  534. package/dist/tasks/task-next.js.map +1 -1
  535. package/dist/tasks/task-reparent.d.ts.map +1 -1
  536. package/dist/tasks/task-reparent.js +3 -13
  537. package/dist/tasks/task-reparent.js.map +1 -1
  538. package/dist/tasks/update.d.ts +20 -43
  539. package/dist/tasks/update.d.ts.map +1 -1
  540. package/dist/tasks/update.js +64 -49
  541. package/dist/tasks/update.js.map +1 -1
  542. package/dist/teardown-signal.d.ts +72 -0
  543. package/dist/teardown-signal.d.ts.map +1 -0
  544. package/dist/teardown-signal.js +108 -0
  545. package/dist/teardown-signal.js.map +1 -0
  546. package/dist/validation/engine-ops.d.ts +17 -1
  547. package/dist/validation/engine-ops.d.ts.map +1 -1
  548. package/dist/validation/engine-ops.js +149 -11
  549. package/dist/validation/engine-ops.js.map +1 -1
  550. package/dist/workgraph/reparent-preflight.d.ts +1 -1
  551. package/dist/workgraph/reparent-preflight.d.ts.map +1 -1
  552. package/dist/workgraph/reparent-preflight.js +6 -1
  553. package/dist/workgraph/reparent-preflight.js.map +1 -1
  554. package/dist/workgraph/scaffold-apply.d.ts.map +1 -1
  555. package/dist/workgraph/scaffold-apply.js +81 -76
  556. package/dist/workgraph/scaffold-apply.js.map +1 -1
  557. package/dist/workgraph/structure-validation.d.ts +1 -1
  558. package/dist/workgraph/structure-validation.d.ts.map +1 -1
  559. package/dist/workgraph/structure-validation.js +6 -1
  560. package/dist/workgraph/structure-validation.js.map +1 -1
  561. package/migrations/drizzle-tasks/20260919180000_t12263-job-ownership-fences/migration.sql +34 -0
  562. package/migrations/drizzle-tasks/20260919184500_t12265-durable-pending-proposals/migration.sql +4 -0
  563. package/package.json +18 -13
  564. package/schemas/config.schema.json +2 -2
  565. package/templates/CLEO-INJECTION.md +103 -101
@@ -17,7 +17,7 @@
17
17
  * which tasks touched those nodes?
18
18
  *
19
19
  * Design constraints:
20
- * - All substrate errors are caught and produce empty collections — never throws.
20
+ * - Substrate errors are recorded in coverage; ambiguity returns qualified candidates.
21
21
  * - conduit.db absence is a graceful no-op: conduitThreads returns [].
22
22
  * - All return shapes are defined in packages/contracts/src/nexus-living-brain-ops.ts.
23
23
  * - REUSES existing primitives: T1067 bridge, T1066 edge writers, existing
@@ -29,11 +29,15 @@
29
29
  import { existsSync } from 'node:fs';
30
30
  import { engineError, engineSuccess } from '../engine-result.js';
31
31
  import { reasonWhySymbol } from '../memory/brain-reasoning.js';
32
+ import { isCurrentDecisionCodeEvidence } from '../memory/decision-cross-link.js';
32
33
  import { EDGE_TYPES } from '../memory/edge-types.js';
34
+ import { graphMemoryAuthority, memoryEligibilityClause } from '../memory/eligibility.js';
33
35
  import { getConduitDbPath } from '../store/conduit-sqlite.js';
34
36
  import { getBrainDb, getBrainNativeDb } from '../store/memory-sqlite.js';
35
37
  import { getNexusDb, getNexusNativeDb } from '../store/nexus-sqlite.js';
36
38
  import { typedAll, typedGet } from '../store/typed-query.js';
39
+ import { assessKnowledgeCoverage, KnowledgeSymbolAmbiguityError, recordKnowledgeGap, resolveKnowledgeSymbol, } from './knowledge.js';
40
+ import { getTaskKnowledgeEvidence } from './task-evidence.js';
37
41
  import { getSymbolsForTask, getTasksForSymbol } from './tasks-bridge.js';
38
42
  // ---------------------------------------------------------------------------
39
43
  // Internal: map ImpactResult riskLevel → RiskTier
@@ -52,13 +56,15 @@ function toRiskTier(riskLevel) {
52
56
  case 'low':
53
57
  return 'LOW';
54
58
  default:
55
- return 'NONE';
59
+ return 'UNKNOWN';
56
60
  }
57
61
  }
58
62
  /**
59
63
  * Return the highest risk tier from an array.
60
64
  */
61
65
  function maxRiskTier(tiers) {
66
+ if (tiers.length === 0 || tiers.includes('UNKNOWN'))
67
+ return 'UNKNOWN';
62
68
  const order = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
63
69
  let max = 0;
64
70
  for (const t of tiers) {
@@ -81,14 +87,16 @@ function maxRiskTier(tiers) {
81
87
  * - **SENTIENT**: Tier-2 proposals whose sourceId matches this symbol
82
88
  * - **CONDUIT**: message threads mentioning this symbol (empty if conduit.db absent)
83
89
  *
84
- * All substrate failures produce empty collections — never throws.
90
+ * Substrate failures are exposed through coverage; ambiguous names are rejected.
85
91
  *
86
92
  * @param symbolId - Nexus node ID or symbol name (partial match accepted for nexus lookup)
87
93
  * @param projectRoot - Absolute path to project root
88
94
  * @returns Full cross-substrate context
89
95
  */
90
96
  export async function getSymbolFullContext(symbolId, projectRoot) {
97
+ const coverage = await assessKnowledgeCoverage(projectRoot);
91
98
  const result = {
99
+ coverage,
92
100
  symbolId,
93
101
  nexus: null,
94
102
  brainMemories: [],
@@ -100,20 +108,18 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
100
108
  // ---- NEXUS substrate ----
101
109
  let resolvedSymbolId = symbolId;
102
110
  try {
103
- await getNexusDb();
104
- const nexusNative = getNexusNativeDb();
111
+ await getNexusDb(projectRoot);
112
+ const nexusNative = getNexusNativeDb(projectRoot);
105
113
  if (nexusNative) {
106
- // Try exact match on id first; fall back to name lookup.
107
- // ADR-090 · T11648: project-scoped graph — `project_id` column dropped.
108
- let symbolNode = typedGet(nexusNative.prepare(`SELECT id, kind, name, file_path, label, community_id
109
- FROM nexus_nodes WHERE id = ? LIMIT 1`), symbolId);
110
- if (!symbolNode) {
111
- // Fuzzy match on name (case-insensitive)
112
- symbolNode = typedGet(nexusNative.prepare(`SELECT id, kind, name, file_path, label, community_id
113
- FROM nexus_nodes
114
- WHERE LOWER(name) = LOWER(?) AND kind NOT IN ('community', 'process', 'folder')
115
- LIMIT 1`), symbolId);
116
- }
114
+ const candidates = typedAll(nexusNative.prepare(`SELECT id, kind, name, file_path, label, community_id FROM nexus_nodes`));
115
+ const selected = resolveKnowledgeSymbol(symbolId, candidates.map((node) => ({
116
+ id: node.id,
117
+ name: node.name,
118
+ label: node.label,
119
+ kind: node.kind,
120
+ filePath: node.file_path,
121
+ })));
122
+ const symbolNode = candidates.find((node) => node.id === selected?.id);
117
123
  if (symbolNode) {
118
124
  resolvedSymbolId = symbolNode.id;
119
125
  // Callers: relations where target_id = symbolNode.id.
@@ -182,6 +188,9 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
182
188
  }
183
189
  }
184
190
  catch (err) {
191
+ if (err instanceof KnowledgeSymbolAmbiguityError)
192
+ throw err;
193
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
185
194
  console.warn('[living-brain] NEXUS substrate error:', err instanceof Error ? err.message : String(err));
186
195
  }
187
196
  // ---- BRAIN substrate ----
@@ -200,12 +209,12 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
200
209
  ];
201
210
  const placeholders = codeEdgeTypes.map(() => '?').join(', ');
202
211
  // brain → symbol edges (from_id is brain node, to_id is symbol)
203
- const brainToSymbolEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
212
+ const brainToSymbolEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
204
213
  FROM brain_page_edges
205
214
  WHERE to_id = ? AND edge_type IN (${placeholders})
206
215
  LIMIT 100`), resolvedSymbolId, ...codeEdgeTypes);
207
216
  // symbol → observation edges (from_id is symbol/file, to_id is brain node)
208
- const symbolToBrainEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
217
+ const symbolToBrainEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
209
218
  FROM brain_page_edges
210
219
  WHERE from_id = ? AND edge_type = ?
211
220
  LIMIT 100`), resolvedSymbolId, EDGE_TYPES.AFFECTS);
@@ -213,6 +222,8 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
213
222
  const brainNodeIds = new Set();
214
223
  const edgeByBrainId = new Map();
215
224
  for (const edge of brainToSymbolEdges) {
225
+ if (!isCurrentDecisionCodeEvidence(brainNative, edge.provenance))
226
+ continue;
216
227
  brainNodeIds.add(edge.from_id);
217
228
  edgeByBrainId.set(edge.from_id, edge);
218
229
  }
@@ -226,6 +237,11 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
226
237
  FROM brain_page_nodes WHERE id = ? LIMIT 1`), nodeId);
227
238
  const edge = edgeByBrainId.get(nodeId);
228
239
  if (brainNode && edge) {
240
+ const authority = graphMemoryAuthority(brainNative, brainNode.id, brainNode.node_type);
241
+ if (authority === 'historical')
242
+ continue;
243
+ if (authority === 'unverified')
244
+ recordKnowledgeGap(coverage, 'partial', `Graph memory source is unverified: ${brainNode.id}`);
229
245
  // Filter out conduit_mentions_symbol — those go to conduitThreads
230
246
  if (edge.edge_type === EDGE_TYPES.CONDUIT_MENTIONS_SYMBOL) {
231
247
  result.conduitThreads.push({
@@ -235,6 +251,7 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
235
251
  }
236
252
  else {
237
253
  result.brainMemories.push({
254
+ authority,
238
255
  nodeId: brainNode.id,
239
256
  nodeType: brainNode.node_type,
240
257
  label: brainNode.label,
@@ -248,6 +265,9 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
248
265
  }
249
266
  }
250
267
  catch (err) {
268
+ if (err instanceof KnowledgeSymbolAmbiguityError)
269
+ throw err;
270
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
251
271
  console.warn('[living-brain] BRAIN substrate error:', err instanceof Error ? err.message : String(err));
252
272
  }
253
273
  // ---- TASKS substrate ----
@@ -261,6 +281,9 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
261
281
  }));
262
282
  }
263
283
  catch (err) {
284
+ if (err instanceof KnowledgeSymbolAmbiguityError)
285
+ throw err;
286
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
264
287
  console.warn('[living-brain] TASKS substrate error:', err instanceof Error ? err.message : String(err));
265
288
  }
266
289
  // ---- SENTIENT substrate ----
@@ -299,6 +322,9 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
299
322
  }
300
323
  }
301
324
  catch (err) {
325
+ if (err instanceof KnowledgeSymbolAmbiguityError)
326
+ throw err;
327
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
302
328
  console.warn('[living-brain] SENTIENT substrate error:', err instanceof Error ? err.message : String(err));
303
329
  }
304
330
  // ---- CONDUIT substrate ----
@@ -315,6 +341,8 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
315
341
  catch {
316
342
  // Non-fatal: conduit check is best-effort
317
343
  }
344
+ if (!result.nexus)
345
+ recordKnowledgeGap(coverage, 'missing', `No indexed symbol matches '${symbolId}'.`);
318
346
  return result;
319
347
  }
320
348
  // ---------------------------------------------------------------------------
@@ -331,158 +359,133 @@ export async function getSymbolFullContext(symbolId, projectRoot) {
331
359
  * - Queries brain decisions linked to this task via brain_memory_links
332
360
  * - Computes aggregate risk tier
333
361
  *
334
- * All substrate failures produce empty collections — never throws.
362
+ * Substrate failures are exposed through coverage; ambiguous names are rejected.
363
+ * Historical file associations survive optional impact failure. UNKNOWN entries
364
+ * use zero numeric placeholders; only blastRadius.symbolsAnalyzed counts completed
365
+ * assessments, and file precision does not establish that a symbol changed.
335
366
  *
336
367
  * @param taskId - Task ID (e.g., 'T001')
337
368
  * @param projectRoot - Absolute path to project root
338
369
  * @returns Full task code impact analysis
339
370
  */
340
371
  export async function getTaskCodeImpact(taskId, projectRoot) {
372
+ const coverage = await assessKnowledgeCoverage(projectRoot);
341
373
  const result = {
374
+ coverage,
342
375
  taskId,
343
376
  files: [],
344
377
  symbols: [],
345
- blastRadius: { totalAffected: 0, maxRisk: 'NONE', symbolsAnalyzed: 0 },
378
+ blastRadius: { totalAffected: 0, maxRisk: 'UNKNOWN', symbolsAnalyzed: 0 },
346
379
  brainObservations: [],
347
380
  decisions: [],
348
- riskScore: 'NONE',
381
+ riskScore: 'UNKNOWN',
349
382
  };
350
- // ---- Resolve files from tasks.db ----
351
- let filesJson = null;
352
- try {
353
- const { getDb } = await import('../store/sqlite.js');
354
- const { eq } = await import('drizzle-orm');
355
- const { tasks: tasksTable } = await import('../store/tasks-schema.js');
356
- const tasksDb = await getDb(projectRoot);
357
- const rows = await tasksDb
358
- .select({ filesJson: tasksTable.filesJson })
359
- .from(tasksTable)
360
- .where(eq(tasksTable.id, taskId))
361
- .all();
362
- if (rows[0]?.filesJson) {
363
- filesJson = rows[0].filesJson;
364
- }
365
- }
366
- catch {
367
- // Fallback: try to get files from brain_page_edges task edges
368
- }
369
- if (!filesJson) {
370
- // Try to infer from task_touches_symbol edges
371
- try {
372
- await getBrainDb(projectRoot);
373
- const brainNative = getBrainNativeDb(projectRoot);
374
- await getNexusDb();
375
- const nexusNative = getNexusNativeDb();
376
- if (brainNative && nexusNative) {
377
- const taskEdges = typedAll(brainNative.prepare(`SELECT to_id FROM brain_page_edges
378
- WHERE from_id = ? AND edge_type = ?
379
- LIMIT 100`), `task:${taskId}`, EDGE_TYPES.TASK_TOUCHES_SYMBOL);
380
- const filePaths = new Set();
381
- for (const edge of taskEdges) {
382
- const node = typedGet(nexusNative.prepare(`SELECT file_path FROM nexus_nodes WHERE id = ? LIMIT 1`), edge.to_id);
383
- if (node?.file_path)
384
- filePaths.add(node.file_path);
385
- }
386
- if (filePaths.size > 0) {
387
- filesJson = JSON.stringify(Array.from(filePaths));
388
- }
389
- }
390
- }
391
- catch {
392
- // Give up on file resolution
393
- }
394
- }
395
- if (filesJson) {
396
- try {
397
- const parsed = JSON.parse(filesJson);
398
- if (Array.isArray(parsed)) {
399
- result.files = parsed.filter((f) => typeof f === 'string');
400
- }
401
- }
402
- catch {
403
- // malformed JSON
404
- }
405
- }
383
+ const taskEvidence = await getTaskKnowledgeEvidence(taskId, projectRoot, coverage);
384
+ result.files = taskEvidence.files.map((file) => file.path);
385
+ result.findings = taskEvidence.findings;
406
386
  // ---- Symbols via T1067 bridge ----
407
387
  let symbolIds = [];
388
+ const evidenceBySymbol = new Map();
408
389
  try {
409
- const symbolRefs = await getSymbolsForTask(taskId, projectRoot);
390
+ const symbolRefs = await getSymbolsForTask(taskId, projectRoot, taskEvidence);
391
+ for (const ref of symbolRefs)
392
+ evidenceBySymbol.set(ref.nexusNodeId, ref);
410
393
  symbolIds = symbolRefs.map((s) => s.nexusNodeId);
411
394
  }
412
395
  catch (err) {
396
+ if (err instanceof KnowledgeSymbolAmbiguityError)
397
+ throw err;
398
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
413
399
  console.warn('[living-brain] getSymbolsForTask failed:', err instanceof Error ? err.message : String(err));
414
400
  }
415
401
  // ---- Impact BFS per symbol ----
416
402
  if (symbolIds.length > 0) {
417
403
  try {
418
- await getNexusDb();
419
- const nexusNative = getNexusNativeDb();
420
- if (nexusNative) {
421
- const { analyzeImpact } = await import('@cleocode/nexus');
422
- // Load all nodes + relations once
423
- const allNodes = typedAll(nexusNative.prepare(`SELECT id, name, kind, file_path, label, is_exported FROM nexus_nodes LIMIT 50000`));
424
- // T11545: `weight` moved to the sibling nexus_relation_weights table and
425
- // is unused by the GraphRelation mapping below — select only structural cols.
426
- const allRelations = typedAll(nexusNative.prepare(`SELECT id, source_id, target_id, type, confidence FROM nexus_relations LIMIT 200000`));
427
- // Map to GraphNode / GraphRelation contracts
428
- const graphNodes = allNodes.map((n) => ({
429
- id: n.id,
430
- name: n.name ?? n.label,
431
- kind: n.kind,
432
- filePath: n.file_path ?? '',
433
- startLine: 0,
434
- endLine: 0,
435
- language: 'unknown',
436
- exported: n.is_exported === 1,
437
- }));
438
- const graphRelations = allRelations.map((r) => ({
439
- source: r.source_id,
440
- target: r.target_id,
441
- type: r.type,
442
- confidence: r.confidence ?? 1.0,
443
- }));
444
- const symbolEntries = [];
445
- for (const symbolId of symbolIds.slice(0, 50)) {
446
- const node = allNodes.find((n) => n.id === symbolId);
447
- if (!node)
448
- continue;
449
- let impactResult;
450
- try {
451
- impactResult = analyzeImpact(symbolId, graphNodes, graphRelations);
452
- }
453
- catch {
454
- impactResult = {
455
- target: symbolId,
456
- riskLevel: 'low',
457
- summary: '',
458
- affectedByDepth: {
459
- depth1_willBreak: [],
460
- depth2_likelyAffected: [],
461
- depth3_mayNeedTesting: [],
462
- },
463
- totalAffected: 0,
464
- };
465
- }
466
- symbolEntries.push({
467
- nexusNodeId: symbolId,
468
- label: node.name ?? node.label,
469
- kind: node.kind,
470
- filePath: node.file_path,
471
- riskLevel: toRiskTier(impactResult.riskLevel),
472
- totalAffected: impactResult.totalAffected,
473
- directCallers: impactResult.affectedByDepth.depth1_willBreak.length,
474
- });
475
- }
476
- result.symbols = symbolEntries;
477
- result.blastRadius = {
478
- totalAffected: symbolEntries.reduce((sum, s) => sum + s.totalAffected, 0),
479
- maxRisk: maxRiskTier(symbolEntries.map((s) => s.riskLevel)),
480
- symbolsAnalyzed: symbolEntries.length,
481
- };
482
- result.riskScore = result.blastRadius.maxRisk;
404
+ await getNexusDb(projectRoot);
405
+ const nexusNative = getNexusNativeDb(projectRoot);
406
+ if (!nexusNative)
407
+ throw new Error('Task impact graph connection is unavailable.');
408
+ // Historical association is independent of the optional impact engine.
409
+ const readSymbol = nexusNative.prepare('SELECT id, name, kind, file_path, label FROM nexus_nodes WHERE id = ?');
410
+ for (const symbolId of symbolIds) {
411
+ const node = typedGet(readSymbol, symbolId);
412
+ if (!node)
413
+ continue;
414
+ result.symbols.push({
415
+ nexusNodeId: symbolId,
416
+ precision: evidenceBySymbol.get(symbolId)?.precision ?? 'file',
417
+ evidence: evidenceBySymbol.get(symbolId)?.evidence ?? [],
418
+ label: node.name ?? node.label,
419
+ kind: node.kind,
420
+ filePath: node.file_path,
421
+ riskLevel: 'UNKNOWN',
422
+ totalAffected: 0,
423
+ directCallers: 0,
424
+ });
425
+ }
426
+ const { analyzeImpact } = await import('@cleocode/nexus');
427
+ // Load all nodes + relations once
428
+ const allNodes = typedAll(nexusNative.prepare(`SELECT id, name, kind, file_path, label, is_exported FROM nexus_nodes LIMIT 50001`));
429
+ // T11545: `weight` moved to the sibling nexus_relation_weights table and
430
+ // is unused by the GraphRelation mapping below — select only structural cols.
431
+ const allRelations = typedAll(nexusNative.prepare(`SELECT id, source_id, target_id, type, confidence FROM nexus_relations LIMIT 200001`));
432
+ if (allNodes.length > 50000 || allRelations.length > 200000) {
433
+ recordKnowledgeGap(coverage, 'partial', 'Impact graph exceeds the 50000-node or 200000-relationship assessment limit.');
434
+ coverage.nextAction = `cleo doctor knowledge --task ${taskId}`;
435
+ }
436
+ // Map to GraphNode / GraphRelation contracts
437
+ const graphNodes = allNodes.map((n) => ({
438
+ id: n.id,
439
+ name: n.name ?? n.label,
440
+ kind: n.kind,
441
+ filePath: n.file_path ?? '',
442
+ startLine: 0,
443
+ endLine: 0,
444
+ language: 'unknown',
445
+ exported: n.is_exported === 1,
446
+ }));
447
+ const graphRelations = allRelations.map((r) => ({
448
+ source: r.source_id,
449
+ target: r.target_id,
450
+ type: r.type,
451
+ confidence: r.confidence ?? 1.0,
452
+ }));
453
+ for (const entry of result.symbols.slice(0, 50)) {
454
+ const impactResult = analyzeImpact(entry.nexusNodeId, graphNodes, graphRelations);
455
+ entry.riskLevel =
456
+ coverage.status !== 'current'
457
+ ? 'UNKNOWN'
458
+ : impactResult.totalAffected === 0
459
+ ? 'NONE'
460
+ : toRiskTier(impactResult.riskLevel);
461
+ entry.totalAffected = impactResult.totalAffected;
462
+ entry.directCallers = impactResult.affectedByDepth.depth1_willBreak.length;
463
+ result.blastRadius.symbolsAnalyzed += 1;
464
+ result.blastRadius.totalAffected += impactResult.totalAffected;
483
465
  }
466
+ result.blastRadius.maxRisk = maxRiskTier(result.symbols.map((entry) => entry.riskLevel));
467
+ result.riskScore = result.blastRadius.maxRisk;
484
468
  }
485
469
  catch (err) {
470
+ if (err instanceof KnowledgeSymbolAmbiguityError)
471
+ throw err;
472
+ const failure = err instanceof Error ? err.message : String(err);
473
+ recordKnowledgeGap(coverage, 'failed', `Task impact assessment failed: ${failure}`);
474
+ coverage.nextAction = `cleo doctor knowledge --task ${taskId}`;
475
+ result.findings.push({
476
+ id: `task-impact:${taskId}`,
477
+ projectId: coverage.projectId,
478
+ affectedRecordIds: [taskId, ...symbolIds],
479
+ description: `Optional impact assessment failed: ${failure}. Inspect the diagnostic and retry the task footprint after the analyzer is available. Historical associations remain evidence, not proof that each symbol changed.`,
480
+ evidence: taskEvidence.files.flatMap((file) => file.evidence),
481
+ repairClass: 'agent-resolvable',
482
+ state: 'failed',
483
+ proposedAction: null,
484
+ verification: [
485
+ 'Repeat the task footprint with a working impact analyzer; retain the same independently supported file and symbol associations.',
486
+ ],
487
+ recovery: null,
488
+ });
486
489
  console.warn('[living-brain] blast radius analysis failed:', err instanceof Error ? err.message : String(err));
487
490
  }
488
491
  }
@@ -490,8 +493,8 @@ export async function getTaskCodeImpact(taskId, projectRoot) {
490
493
  try {
491
494
  await getBrainDb(projectRoot);
492
495
  const brainNative = getBrainNativeDb(projectRoot);
493
- await getNexusDb();
494
- const nexusNative = getNexusNativeDb();
496
+ await getNexusDb(projectRoot);
497
+ const nexusNative = getNexusNativeDb(projectRoot);
495
498
  if (brainNative && nexusNative && result.files.length > 0) {
496
499
  for (const filePath of result.files) {
497
500
  // Find nexus file node for this path
@@ -499,12 +502,12 @@ export async function getTaskCodeImpact(taskId, projectRoot) {
499
502
  if (!fileNode)
500
503
  continue;
501
504
  // Find modified_by edges from this file node to observation nodes
502
- const modEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
505
+ const modEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
503
506
  FROM brain_page_edges
504
507
  WHERE from_id = ? AND edge_type = ?
505
508
  LIMIT 20`), fileNode.id, EDGE_TYPES.AFFECTS);
506
509
  // Also check reverse (observation → file via modified_by)
507
- const modByEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
510
+ const modByEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
508
511
  FROM brain_page_edges
509
512
  WHERE to_id = ? AND edge_type = 'modified_by'
510
513
  LIMIT 20`), fileNode.id);
@@ -530,6 +533,9 @@ export async function getTaskCodeImpact(taskId, projectRoot) {
530
533
  }
531
534
  }
532
535
  catch (err) {
536
+ if (err instanceof KnowledgeSymbolAmbiguityError)
537
+ throw err;
538
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
533
539
  console.warn('[living-brain] brain observations query failed:', err instanceof Error ? err.message : String(err));
534
540
  }
535
541
  // ---- Decisions from brain_memory_links ----
@@ -542,7 +548,7 @@ export async function getTaskCodeImpact(taskId, projectRoot) {
542
548
  WHERE task_id = ? AND memory_type = 'decision'
543
549
  LIMIT 20`), taskId);
544
550
  for (const link of linkRows) {
545
- const decisionRow = typedGet(brainNative.prepare(`SELECT id, decision FROM brain_decisions WHERE id = ? LIMIT 1`), link.memory_id);
551
+ const decisionRow = typedGet(brainNative.prepare(`SELECT id, decision FROM main.brain_decisions AS source WHERE id = ?${memoryEligibilityClause('decisions', 'source')} LIMIT 1`), link.memory_id);
546
552
  if (decisionRow) {
547
553
  result.decisions.push({
548
554
  decisionId: decisionRow.id,
@@ -554,8 +560,32 @@ export async function getTaskCodeImpact(taskId, projectRoot) {
554
560
  }
555
561
  }
556
562
  catch (err) {
563
+ if (err instanceof KnowledgeSymbolAmbiguityError)
564
+ throw err;
565
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
557
566
  console.warn('[living-brain] decisions query failed:', err instanceof Error ? err.message : String(err));
558
567
  }
568
+ if (result.symbols.length === 0) {
569
+ recordKnowledgeGap(coverage, coverage.maintenanceState === 'pending' ? 'partial' : 'missing', coverage.maintenanceState === 'pending'
570
+ ? 'Task evidence assessment is deferred; zero matches do not establish missing evidence.'
571
+ : 'No task evidence has been resolved to indexed symbols.');
572
+ }
573
+ if (symbolIds.length > 50) {
574
+ coverage.nextAction = `cleo doctor knowledge --task ${taskId}`;
575
+ recordKnowledgeGap(coverage, 'partial', 'Impact is bounded to 50 task symbols; additional associations remain unassessed.');
576
+ }
577
+ if (result.symbols.length < symbolIds.length) {
578
+ recordKnowledgeGap(coverage, 'partial', 'Some task-linked symbols are absent from the graph.');
579
+ }
580
+ if (result.blastRadius.symbolsAnalyzed < result.symbols.length) {
581
+ coverage.limitations.push('Impact counts include only completed analyzer results. Zero counts for unassessed symbols are placeholders, not evidence of NONE; their risk remains UNKNOWN.');
582
+ }
583
+ if (coverage.status !== 'current') {
584
+ result.riskScore = 'UNKNOWN';
585
+ result.blastRadius.maxRisk = 'UNKNOWN';
586
+ for (const entry of result.symbols)
587
+ entry.riskLevel = 'UNKNOWN';
588
+ }
559
589
  return result;
560
590
  }
561
591
  // ---------------------------------------------------------------------------
@@ -569,7 +599,7 @@ export async function getTaskCodeImpact(taskId, projectRoot) {
569
599
  * - tasksForNodes: for each code node, which tasks touched it (T1067 reverse-lookup)
570
600
  * - plasticitySignal: sum of weights on all anchoring edges
571
601
  *
572
- * All substrate failures produce empty collections — never throws.
602
+ * Substrate failures are exposed through coverage; ambiguous names are rejected.
573
603
  *
574
604
  * @param entryId - Brain entry node ID (format: '<type>:<source-id>')
575
605
  * @param projectRoot - Absolute path to project root
@@ -591,18 +621,20 @@ export async function getBrainEntryCodeAnchors(entryId, projectRoot) {
591
621
  try {
592
622
  await getBrainDb(projectRoot);
593
623
  const brainNative = getBrainNativeDb(projectRoot);
594
- await getNexusDb();
595
- const nexusNative = getNexusNativeDb();
624
+ await getNexusDb(projectRoot);
625
+ const nexusNative = getNexusNativeDb(projectRoot);
596
626
  if (!brainNative || !nexusNative)
597
627
  return result;
598
628
  const placeholders = anchorEdgeTypes.map(() => '?').join(', ');
599
629
  // brain entry → code node edges
600
- const anchorEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
630
+ const anchorEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
601
631
  FROM brain_page_edges
602
632
  WHERE from_id = ? AND edge_type IN (${placeholders})
603
633
  LIMIT 100`), entryId, ...anchorEdgeTypes);
604
634
  let totalWeight = 0;
605
635
  for (const edge of anchorEdges) {
636
+ if (!isCurrentDecisionCodeEvidence(brainNative, edge.provenance))
637
+ continue;
606
638
  // Verify the target exists in nexus
607
639
  const nexusNode = typedGet(nexusNative.prepare(`SELECT id, kind, name, file_path, label FROM nexus_nodes WHERE id = ? LIMIT 1`), edge.to_id);
608
640
  if (nexusNode) {
@@ -656,7 +688,7 @@ export async function getBrainEntryCodeAnchors(entryId, projectRoot) {
656
688
  * 2. `getTasksForSymbol(symbolId)` — tasks that touch this symbol
657
689
  * 3. Brain observations/decisions via `code_reference`, `modified_by`, `documents` edges
658
690
  *
659
- * All substrate failures produce empty collections — never throws.
691
+ * Substrate failures are exposed through coverage; ambiguous names are rejected.
660
692
  *
661
693
  * @param symbolId - Nexus node ID or symbol name (partial match accepted)
662
694
  * @param projectRoot - Absolute path to project root
@@ -665,35 +697,39 @@ export async function getBrainEntryCodeAnchors(entryId, projectRoot) {
665
697
  * @epic T1042
666
698
  */
667
699
  export async function reasonImpactOfChange(symbolId, projectRoot) {
700
+ const coverage = await assessKnowledgeCoverage(projectRoot);
668
701
  const result = {
702
+ coverage,
669
703
  symbolId,
670
704
  structural: {
671
705
  directCallers: 0,
672
706
  likelyAffected: 0,
673
707
  mayNeedTesting: 0,
674
708
  totalAffected: 0,
675
- riskLevel: 'NONE',
709
+ riskLevel: 'UNKNOWN',
676
710
  },
677
711
  openTasks: [],
678
712
  brainRiskNotes: [],
679
- mergedRiskScore: 'NONE',
713
+ mergedRiskScore: 'UNKNOWN',
680
714
  narrative: `No impact data available for symbol '${symbolId}'.`,
681
715
  };
682
716
  // ---- Resolve nexus node ID (may be a name) ----
683
717
  let resolvedId = symbolId;
684
718
  try {
685
- await getNexusDb();
686
- const nexusNative = getNexusNativeDb();
719
+ await getNexusDb(projectRoot);
720
+ const nexusNative = getNexusNativeDb(projectRoot);
687
721
  if (nexusNative) {
688
- // ADR-090 · T11648: project-scoped graph — `project_id` column dropped
689
- // (the stray `weight` column never existed on nexus_nodes; removed too).
690
- let nexusNode = typedGet(nexusNative.prepare(`SELECT id, kind, name, file_path, label, community_id
691
- FROM nexus_nodes WHERE id = ? LIMIT 1`), symbolId);
722
+ const candidates = typedAll(nexusNative.prepare(`SELECT id, kind, name, file_path, label, community_id FROM nexus_nodes`));
723
+ const nexusNode = resolveKnowledgeSymbol(symbolId, candidates.map((node) => ({
724
+ id: node.id,
725
+ name: node.name,
726
+ label: node.label,
727
+ kind: node.kind,
728
+ filePath: node.file_path,
729
+ })));
692
730
  if (!nexusNode) {
693
- nexusNode = typedGet(nexusNative.prepare(`SELECT id, kind, name, file_path, label, community_id
694
- FROM nexus_nodes
695
- WHERE LOWER(name) = LOWER(?) AND kind NOT IN ('community', 'process', 'folder')
696
- LIMIT 1`), symbolId);
731
+ recordKnowledgeGap(coverage, 'missing', `No indexed symbol matches '${symbolId}'.`);
732
+ return result;
697
733
  }
698
734
  if (nexusNode) {
699
735
  resolvedId = nexusNode.id;
@@ -701,12 +737,15 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
701
737
  }
702
738
  }
703
739
  catch (err) {
740
+ if (err instanceof KnowledgeSymbolAmbiguityError)
741
+ throw err;
742
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
704
743
  console.warn('[living-brain] reasonImpactOfChange nexus resolve failed:', err instanceof Error ? err.message : String(err));
705
744
  }
706
745
  // ---- Structural blast radius via analyzeImpact ----
707
746
  try {
708
- await getNexusDb();
709
- const nexusNative = getNexusNativeDb();
747
+ await getNexusDb(projectRoot);
748
+ const nexusNative = getNexusNativeDb(projectRoot);
710
749
  if (nexusNative) {
711
750
  const { analyzeImpact } = await import('@cleocode/nexus');
712
751
  const allNodes = typedAll(nexusNative.prepare(`SELECT id, name, kind, file_path, label, is_exported FROM nexus_nodes LIMIT 50000`));
@@ -729,33 +768,24 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
729
768
  type: r.type,
730
769
  confidence: r.confidence ?? 1.0,
731
770
  }));
732
- let impactResult;
733
- try {
734
- impactResult = analyzeImpact(resolvedId, graphNodes, graphRelations);
735
- }
736
- catch {
737
- impactResult = {
738
- target: resolvedId,
739
- riskLevel: 'low',
740
- summary: '',
741
- affectedByDepth: {
742
- depth1_willBreak: [],
743
- depth2_likelyAffected: [],
744
- depth3_mayNeedTesting: [],
745
- },
746
- totalAffected: 0,
747
- };
748
- }
771
+ const impactResult = analyzeImpact(resolvedId, graphNodes, graphRelations);
749
772
  result.structural = {
750
773
  directCallers: impactResult.affectedByDepth.depth1_willBreak.length,
751
774
  likelyAffected: impactResult.affectedByDepth.depth2_likelyAffected.length,
752
775
  mayNeedTesting: impactResult.affectedByDepth.depth3_mayNeedTesting.length,
753
776
  totalAffected: impactResult.totalAffected,
754
- riskLevel: toRiskTier(impactResult.riskLevel),
777
+ riskLevel: coverage.status !== 'current'
778
+ ? 'UNKNOWN'
779
+ : impactResult.totalAffected === 0
780
+ ? 'NONE'
781
+ : toRiskTier(impactResult.riskLevel),
755
782
  };
756
783
  }
757
784
  }
758
785
  catch (err) {
786
+ if (err instanceof KnowledgeSymbolAmbiguityError)
787
+ throw err;
788
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
759
789
  console.warn('[living-brain] reasonImpactOfChange structural analysis failed:', err instanceof Error ? err.message : String(err));
760
790
  }
761
791
  // ---- Open tasks via task_touches_symbol ----
@@ -768,6 +798,9 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
768
798
  }));
769
799
  }
770
800
  catch (err) {
801
+ if (err instanceof KnowledgeSymbolAmbiguityError)
802
+ throw err;
803
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
771
804
  console.warn('[living-brain] reasonImpactOfChange open-tasks lookup failed:', err instanceof Error ? err.message : String(err));
772
805
  }
773
806
  // ---- Brain risk notes via code_reference / documents / modified_by edges ----
@@ -783,18 +816,20 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
783
816
  ];
784
817
  const placeholders = riskEdgeTypes.map(() => '?').join(', ');
785
818
  // Brain nodes → symbol (brain references this symbol)
786
- const brainToSymbolEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
819
+ const brainToSymbolEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
787
820
  FROM brain_page_edges
788
821
  WHERE to_id = ? AND edge_type IN (${placeholders})
789
822
  LIMIT 50`), resolvedId, ...riskEdgeTypes);
790
823
  // symbol → brain nodes (symbol points to observations)
791
- const symbolToBrainEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight
824
+ const symbolToBrainEdges = typedAll(brainNative.prepare(`SELECT from_id, to_id, edge_type, weight, provenance
792
825
  FROM brain_page_edges
793
826
  WHERE from_id = ? AND edge_type = ?
794
827
  LIMIT 50`), resolvedId, EDGE_TYPES.AFFECTS);
795
828
  const seenIds = new Set();
796
829
  const processEdges = (edges, isReverse) => {
797
830
  for (const edge of edges) {
831
+ if (!isCurrentDecisionCodeEvidence(brainNative, edge.provenance))
832
+ continue;
798
833
  const nodeId = isReverse ? edge.from_id : edge.to_id;
799
834
  if (seenIds.has(nodeId))
800
835
  continue;
@@ -802,7 +837,13 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
802
837
  const brainNode = typedGet(brainNative.prepare(`SELECT id, node_type, label, quality_score
803
838
  FROM brain_page_nodes WHERE id = ? LIMIT 1`), nodeId);
804
839
  if (brainNode) {
840
+ const authority = graphMemoryAuthority(brainNative, brainNode.id, brainNode.node_type);
841
+ if (authority === 'historical')
842
+ continue;
843
+ if (authority === 'unverified')
844
+ recordKnowledgeGap(coverage, 'partial', `Graph memory source is unverified: ${brainNode.id}`);
805
845
  const riskNote = {
846
+ authority,
806
847
  nodeId: brainNode.id,
807
848
  nodeType: brainNode.node_type,
808
849
  label: brainNode.label,
@@ -818,6 +859,9 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
818
859
  }
819
860
  }
820
861
  catch (err) {
862
+ if (err instanceof KnowledgeSymbolAmbiguityError)
863
+ throw err;
864
+ recordKnowledgeGap(coverage, 'failed', err instanceof Error ? err.message : String(err));
821
865
  console.warn('[living-brain] reasonImpactOfChange brain risk notes failed:', err instanceof Error ? err.message : String(err));
822
866
  }
823
867
  // ---- Compute merged risk score ----
@@ -841,7 +885,7 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
841
885
  const openCount = result.openTasks.length;
842
886
  const riskNoteCount = result.brainRiskNotes.length;
843
887
  result.narrative =
844
- `Changing ${symLabel} will break ${d1} direct caller${d1 !== 1 ? 's' : ''} (d=1)` +
888
+ `Static analysis of ${symLabel} identifies ${d1} direct caller${d1 !== 1 ? 's' : ''} (d=1)` +
845
889
  (d2 > 0 ? `, likely affect ${d2} at d=2` : '') +
846
890
  (openCount > 0
847
891
  ? `, and is referenced in ${openCount} open task${openCount !== 1 ? 's' : ''}`
@@ -850,6 +894,11 @@ export async function reasonImpactOfChange(symbolId, projectRoot) {
850
894
  ? ` and ${riskNoteCount} BRAIN risk note${riskNoteCount !== 1 ? 's' : ''}`
851
895
  : '') +
852
896
  `. Merged risk: ${result.mergedRiskScore}.`;
897
+ if (coverage.status !== 'current') {
898
+ result.mergedRiskScore = 'UNKNOWN';
899
+ result.structural.riskLevel = 'UNKNOWN';
900
+ result.narrative = `Impact cannot be fully assessed for ${symLabel}. Coverage: ${coverage.status}. ${coverage.reasons.join(' ')}`;
901
+ }
853
902
  return result;
854
903
  }
855
904
  // ---------------------------------------------------------------------------
@@ -862,6 +911,9 @@ export async function nexusFullContext(symbolId, projectRoot) {
862
911
  return engineSuccess(result);
863
912
  }
864
913
  catch (error) {
914
+ if (error instanceof KnowledgeSymbolAmbiguityError) {
915
+ return engineError(error.code, error.message, { details: { candidates: error.candidates } });
916
+ }
865
917
  return engineError('E_INTERNAL', error instanceof Error ? error.message : String(error));
866
918
  }
867
919
  }
@@ -872,6 +924,9 @@ export async function nexusTaskFootprint(taskId, projectRoot) {
872
924
  return engineSuccess(result);
873
925
  }
874
926
  catch (error) {
927
+ if (error instanceof KnowledgeSymbolAmbiguityError) {
928
+ return engineError(error.code, error.message, { details: { candidates: error.candidates } });
929
+ }
875
930
  return engineError('E_INTERNAL', error instanceof Error ? error.message : String(error));
876
931
  }
877
932
  }
@@ -882,6 +937,9 @@ export async function nexusBrainAnchors(entryId, projectRoot) {
882
937
  return engineSuccess(result);
883
938
  }
884
939
  catch (error) {
940
+ if (error instanceof KnowledgeSymbolAmbiguityError) {
941
+ return engineError(error.code, error.message, { details: { candidates: error.candidates } });
942
+ }
885
943
  return engineError('E_INTERNAL', error instanceof Error ? error.message : String(error));
886
944
  }
887
945
  }
@@ -892,6 +950,9 @@ export async function nexusImpactFull(symbolId, projectRoot) {
892
950
  return engineSuccess(result);
893
951
  }
894
952
  catch (error) {
953
+ if (error instanceof KnowledgeSymbolAmbiguityError) {
954
+ return engineError(error.code, error.message, { details: { candidates: error.candidates } });
955
+ }
895
956
  return engineError('E_INTERNAL', error instanceof Error ? error.message : String(error));
896
957
  }
897
958
  }
@@ -902,6 +963,9 @@ export async function nexusWhy(symbolId, projectRoot) {
902
963
  return engineSuccess(result);
903
964
  }
904
965
  catch (error) {
966
+ if (error instanceof KnowledgeSymbolAmbiguityError) {
967
+ return engineError(error.code, error.message, { details: { candidates: error.candidates } });
968
+ }
905
969
  return engineError('E_INTERNAL', error instanceof Error ? error.message : String(error));
906
970
  }
907
971
  }