akm-cli 0.9.0-rc.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -10,22 +10,20 @@
10
10
  * than crashing the caller.
11
11
  *
12
12
  * Relocated from `src/indexer/db/entry-mapper.ts` (WI-5a): it now imports the
13
- * shared shapes from the leaf types module rather than from `db.ts`, so it no
14
- * longer participates in the indexer-db import cycle.
13
+ * shared shapes from the leaf types module `./index-entry-types.ts` rather
14
+ * than reaching across the storage↔indexer boundary into `db.ts`, so it no
15
+ * longer participates in the `db.ts` / `entry-mapper.ts` / `schema.ts` import
16
+ * cycle that used to pin them together.
15
17
  */
16
18
  import { warn } from "../../core/warn.js";
17
19
  /**
18
20
  * Canonical column list for reading a full indexed entry from the `entries`
19
21
  * table, in the order {@link rowToIndexedEntry} expects.
20
22
  *
21
- * Chunk-5 flip (Checkpoint A): the durable identity columns `concept_id` and
22
- * `bundle_id` are surfaced here so the state.db salience/outcome dual-read arms
23
- * can build the fully-qualified `<bundle>//<concept-id>` new-grammar key from a
24
- * mapped entry with ZERO extra queries (they are the last two columns and both
25
- * nullable — a NULL-provenance write-back straggler simply yields `undefined`,
26
- * and the reader falls through to its inline legacy `type:name` arm).
23
+ * Durable identity columns are surfaced here so every mapped entry carries
24
+ * current indexed provenance.
27
25
  */
28
- export const ENTRY_COLUMNS = "id, entry_key, dir_path, file_path, stash_dir, entry_json, search_text, concept_id, bundle_id";
26
+ export const ENTRY_COLUMNS = "id, entry_key, dir_path, file_path, stash_dir, entry_json, search_text, item_ref, concept_id, bundle_id, adapter_id";
29
27
  /**
30
28
  * Map one raw `entries` row to a {@link DbIndexedEntry}, parsing `entry_json`.
31
29
  * Returns `null` (and warns, tagged with `context`) when the JSON is corrupt so
@@ -40,6 +38,10 @@ export function rowToIndexedEntry(row, context) {
40
38
  warn(`[db] ${context}: skipping entry id=${row.id} — corrupt entry_json`);
41
39
  return null;
42
40
  }
41
+ if (!row.item_ref || !row.concept_id || !row.bundle_id || !row.adapter_id) {
42
+ warn(`[db] ${context}: skipping entry id=${row.id} — missing indexed provenance`);
43
+ return null;
44
+ }
43
45
  return {
44
46
  id: row.id,
45
47
  entryKey: row.entry_key,
@@ -48,7 +50,9 @@ export function rowToIndexedEntry(row, context) {
48
50
  stashDir: row.stash_dir,
49
51
  entry,
50
52
  searchText: row.search_text,
51
- conceptId: row.concept_id ?? undefined,
52
- bundleId: row.bundle_id ?? undefined,
53
+ itemRef: row.item_ref,
54
+ conceptId: row.concept_id,
55
+ bundleId: row.bundle_id,
56
+ adapterId: row.adapter_id,
53
57
  };
54
58
  }
@@ -5,7 +5,7 @@
5
5
  * `index.db` FTS5 search + rebuild repository.
6
6
  *
7
7
  * Owns the `entries_fts` full-text query path and the incremental/full FTS
8
- * rebuild. Extracted verbatim from `src/indexer/db/db.ts` (WI-5a).
8
+ * rebuild.
9
9
  */
10
10
  import { warn } from "../../core/warn.js";
11
11
  import { buildPrefixQuery, sanitizeFtsQuery } from "../../indexer/search/fts-query.js";
@@ -52,7 +52,7 @@ function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
52
52
  }
53
53
  const sql = `
54
54
  SELECT e.id, e.file_path AS filePath, e.entry_json, e.search_text AS searchText,
55
- e.item_ref AS itemRef,
55
+ e.item_ref AS itemRef, e.bundle_id AS bundleId, e.concept_id AS conceptId, e.adapter_id AS adapterId,
56
56
  bm25(entries_fts, 0, 10.0, 5.0, 3.0, 2.0, 1.0) AS bm25Score
57
57
  FROM entries_fts f
58
58
  JOIN entries e ON e.id = f.entry_id
@@ -81,6 +81,9 @@ function runFtsQuery(db, ftsQuery, limit, entryType, excludeTypes) {
81
81
  searchText: row.searchText,
82
82
  bm25Score: row.bm25Score,
83
83
  itemRef: row.itemRef,
84
+ bundleId: row.bundleId,
85
+ conceptId: row.conceptId,
86
+ adapterId: row.adapterId,
84
87
  });
85
88
  }
86
89
  return results;
@@ -6,7 +6,6 @@
6
6
  *
7
7
  * Owns the raw SQL for `llm_enrichment_cache` — the body-hash-keyed cache that
8
8
  * lets `akm index --enrich` skip the LLM call when a file's body is unchanged.
9
- * Extracted verbatim from `src/indexer/db/db.ts` (WI-5a).
10
9
  */
11
10
  import { bestEffort } from "../../core/best-effort.js";
12
11
  import { sha256Hex } from "../../runtime.js";
@@ -5,9 +5,8 @@
5
5
  * `index.db` meta + per-directory index-state repository.
6
6
  *
7
7
  * Owns the raw SQL for `index_meta` (the key/value stamp table) and
8
- * `index_dir_state` (incremental-index bookkeeping). Extracted verbatim from
9
- * `src/indexer/db/db.ts` (WI-5a) so the storage layer, not the indexer god-file,
10
- * owns these primitives.
8
+ * `index_dir_state` (incremental-index bookkeeping). Lives in the storage
9
+ * layer, not the indexer, so the storage layer owns these primitives.
11
10
  */
12
11
  import path from "node:path";
13
12
  // ── Meta helpers ────────────────────────────────────────────────────────────
@@ -2,14 +2,13 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * index.db schema, version stamps, and targeted migrations relocated from
6
- * `src/indexer/db/schema.ts` (WI-5a) into the storage layer. This isolates the
7
- * one genuinely risky area (schema evolution) from the CRUD/FTS/vector queries.
5
+ * index.db schema, version stamps, and targeted migrations, kept in the
6
+ * storage layer. This isolates the one genuinely risky area (schema
7
+ * evolution) from the CRUD/FTS/vector queries.
8
8
  *
9
9
  * The meta accessors, embedding purge, and vec-availability probe that
10
- * `ensureSchema` leans on now live in the sibling `index-meta-repository` /
11
- * `index-vec-repository` modules; importing them from there (rather than from
12
- * the old `db.ts` hub) is what lets this module leave the import cycle.
10
+ * `ensureSchema` leans on live in the sibling `index-meta-repository` /
11
+ * `index-vec-repository` modules.
13
12
  */
14
13
  import { bestEffort } from "../../core/best-effort.js";
15
14
  import { warn } from "../../core/warn.js";
@@ -529,27 +528,13 @@ function ensureBundleRefColumns(db) {
529
528
  * durable identity — spec §11.4). A pre-v19 DB has a NON-unique
530
529
  * `idx_entries_item_ref`, so we DROP-then-CREATE (a `CREATE UNIQUE INDEX IF NOT
531
530
  * EXISTS` under the same name would no-op against the existing non-unique index).
532
- * SQLite treats NULLs as distinct in a UNIQUE index, so NULL-item_ref write-back
533
- * stragglers do not collide.
534
- *
535
- * A partially-migrated index could still hold two rows with the same non-NULL
536
- * item_ref; the UNIQUE build then throws. The index is a regenerable derived
537
- * cache, so we fall back to the plain lookup index (reads stay fast) and warn —
538
- * a full `akm index` rebuild repopulates one row per item_ref and the next open
539
- * upgrades cleanly.
531
+ * SQLite treats NULLs as distinct in a UNIQUE index. Duplicate durable identities
532
+ * are an invalid index and fail the schema open rather than enabling a dual-key
533
+ * fallback.
540
534
  */
541
535
  function ensureUniqueItemRefIndex(db) {
542
- let uniqueOk = false;
543
- bestEffort(() => {
544
- db.exec("DROP INDEX IF EXISTS idx_entries_item_ref");
545
- db.exec("CREATE UNIQUE INDEX idx_entries_item_ref ON entries(item_ref)");
546
- uniqueOk = true;
547
- }, "entries.item_ref UNIQUE index — column added by ensureBundleRefColumns above");
548
- if (!uniqueOk) {
549
- warn("[akm] entries.item_ref UNIQUE index could not be built (duplicate item_ref on a partially-migrated index) — " +
550
- "keeping the plain lookup index; a full `akm index` rebuild restores uniqueness.");
551
- bestEffort(() => db.exec("CREATE INDEX IF NOT EXISTS idx_entries_item_ref ON entries(item_ref)"), "entries.item_ref lookup index fallback");
552
- }
536
+ db.exec("DROP INDEX IF EXISTS idx_entries_item_ref");
537
+ db.exec("CREATE UNIQUE INDEX idx_entries_item_ref ON entries(item_ref)");
553
538
  }
554
539
  /**
555
540
  * Returns true when a table exists in the current database.
@@ -7,7 +7,6 @@
7
7
  * Owns the raw SQL for `utility_scores` / `utility_scores_scoped` and the
8
8
  * retrieval-frequency counting over `usage_events`. The bounded-step EMA policy
9
9
  * itself lives in `indexer/feedback/utility-policy`; this repo only reads/writes.
10
- * Extracted verbatim from `src/indexer/db/db.ts` (WI-5a).
11
10
  */
12
11
  import path from "node:path";
13
12
  import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
@@ -106,11 +105,7 @@ export function upsertUtilityScore(db, entryId, data) {
106
105
  }
107
106
  /**
108
107
  * Reduce a stored ref to its bare form, dropping any `origin//` / `bundle//`
109
- * prefix the SAME strip the counting SQL does (`substr` after the first
110
- * `//`). The bare form is `type:name` for a legacy row and `conceptId` for a
111
- * 0.9.0 re-keyed row (Chunk-5 flip F4c). Matching the SQL strip exactly keeps
112
- * the JS row-grouping and the SQL `IN (…)` filter in lockstep across both
113
- * spellings.
108
+ * prefix, matching the counting SQL's `substr` after the first `//`.
114
109
  */
115
110
  function bareRef(ref) {
116
111
  const boundary = ref.indexOf("//");
@@ -124,13 +119,8 @@ function bareRef(ref) {
124
119
  */
125
120
  function bareRefCandidates(ref) {
126
121
  const bare = bareRef(ref.trim());
127
- try {
128
- const parsed = parseRefInput(bare);
129
- return [conceptIdFromTypeName(parsed.type, parsed.name)];
130
- }
131
- catch {
132
- return [bare];
133
- }
122
+ const parsed = parseRefInput(bare);
123
+ return [conceptIdFromTypeName(parsed.type, parsed.name)];
134
124
  }
135
125
  /**
136
126
  * Count retrieval events for the given entry refs.
@@ -141,16 +131,13 @@ function bareRefCandidates(ref) {
141
131
  * proactive-maintenance selector to rank zero-feedback assets by retrieval
142
132
  * frequency.
143
133
  *
144
- * Unscoped callers retain normalization-aware legacy matching. Source-scoped
145
- * callers instead require either an event linked to an entry in the selected
146
- * stash root or a detached ref qualified with the selected source name. Bare
147
- * detached events are accepted only when `includeLegacyBare` is explicitly set
148
- * for the historical local stash.
134
+ * Source-scoped callers require either an event linked to an entry in the
135
+ * selected stash root or a detached ref qualified with the selected source
136
+ * name.
149
137
  *
150
138
  * `curate` events are included: their per-item rows are written with
151
139
  * entry_ref populated (see logCurateEvent), so curation is a real retrieval
152
- * signal here. Legacy summary-only curate rows with a NULL entry_ref simply
153
- * contribute nothing.
140
+ * signal here. Summary-only rows with a NULL entry_ref contribute nothing.
154
141
  *
155
142
  * Machine/eval/unattributed/extension events are excluded: this count feeds
156
143
  * salience and ranking, so only explicitly attributed `user` traffic counts.
@@ -161,9 +148,8 @@ export function getRetrievalCounts(indexDb, stateDb, refs, options = {}) {
161
148
  if (options.sourceName || options.stashDir) {
162
149
  return getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options);
163
150
  }
164
- // Map each candidate bare form (both spellings) back to the input ref(s) that
165
- // produced it so we can re-key DB results (grouped by bare form) onto the
166
- // caller's ref strings — spelling-agnostic across the §11.4 re-key.
151
+ // Map each conceptId back to the input refs that produced it so DB results
152
+ // can be re-keyed onto the caller's strings.
167
153
  const bareToInputs = new Map();
168
154
  for (const ref of refs) {
169
155
  for (const bare of bareRefCandidates(ref)) {
@@ -185,7 +171,7 @@ export function getRetrievalCounts(indexDb, stateDb, refs, options = {}) {
185
171
  // everything up to and including the last `//` separator. SQLite has no
186
172
  // rfind, but stored origins never themselves contain `//`, so a stash ref
187
173
  // has exactly one `//` and `substr(... instr ...)` is exact; bare refs have
188
- // no `//` and pass through unchanged.
174
+ // no `//` and are excluded above.
189
175
  // usage_events lives in state.db (Chunk-8 WI-8.3) — this global count needs
190
176
  // no entries join, so it reads state.db directly.
191
177
  const rows = stateDb
@@ -199,7 +185,8 @@ export function getRetrievalCounts(indexDb, stateDb, refs, options = {}) {
199
185
  FROM usage_events
200
186
  WHERE event_type IN ('search','show','curate')
201
187
  AND entry_ref IS NOT NULL
202
- AND source = 'user'
188
+ AND instr(entry_ref, '//') > 0
189
+ AND source = 'user'
203
190
  AND CASE
204
191
  WHEN instr(entry_ref, '//') > 0
205
192
  THEN substr(entry_ref, instr(entry_ref, '//') + 2)
@@ -253,7 +240,8 @@ function getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options) {
253
240
  FROM usage_events ue
254
241
  WHERE ue.event_type IN ('search','show','curate')
255
242
  AND ue.entry_ref IS NOT NULL
256
- AND ue.source = 'user'
243
+ AND instr(ue.entry_ref, '//') > 0
244
+ AND ue.source = 'user'
257
245
  AND CASE
258
246
  WHEN instr(ue.entry_ref, '//') > 0
259
247
  THEN substr(ue.entry_ref, instr(ue.entry_ref, '//') + 2)
@@ -268,8 +256,7 @@ function getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options) {
268
256
  : false;
269
257
  const detached = row.entry_id === null || selectedRoot === undefined;
270
258
  const qualifiedForSource = detached && options.sourceName !== undefined && row.entry_ref === `${options.sourceName}//${bare}`;
271
- const acceptedLegacyBare = detached && options.includeLegacyBare === true && row.entry_ref === bare;
272
- if (!linkedToSelectedRoot && !qualifiedForSource && !acceptedLegacyBare)
259
+ if (!linkedToSelectedRoot && !qualifiedForSource)
273
260
  continue;
274
261
  countsByBare.set(bare, (countsByBare.get(bare) ?? 0) + 1);
275
262
  }
@@ -6,7 +6,6 @@
6
6
  *
7
7
  * Owns the sqlite-vec extension load/availability probe, the BLOB `embeddings`
8
8
  * table, the `entries_vec` virtual table, and the JS-cosine fallback path.
9
- * Extracted verbatim from `src/indexer/db/db.ts` (WI-5a).
10
9
  */
11
10
  import { createRequire } from "node:module";
12
11
  import { bestEffort } from "../../core/best-effort.js";
@@ -59,6 +58,12 @@ export function setVecFastPathReady(db, ready) {
59
58
  export function isVecFastPathReady(db) {
60
59
  return getMeta(db, VEC_FAST_PATH_READY_META) !== "0";
61
60
  }
61
+ /** Remove both vector representations for an entry whose embedding input changed. */
62
+ export function deleteEntryVectors(db, id) {
63
+ db.prepare("DELETE FROM embeddings WHERE id = ?").run(id);
64
+ if (isVecAvailable(db))
65
+ db.prepare("DELETE FROM entries_vec WHERE id = ?").run(id);
66
+ }
62
67
  const VEC_DOCS_URL = "https://github.com/itlackey/akm/blob/main/docs/reference/configuration.md#sqlite-vec-extension";
63
68
  const VEC_FALLBACK_THRESHOLD = 10_000;
64
69
  // Per-database warning state: tracks which databases have already emitted the
@@ -0,0 +1,119 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Upsert one `asset_outcome` row. Extracted verbatim from the tail of
6
+ * `updateAssetOutcome` in outcome-loop.ts — same SQL text, same bind order;
7
+ * the business logic that computes these values (warm-start seed vs.
8
+ * differential update) stays in outcome-loop.ts and calls this function.
9
+ *
10
+ * `review_pressure` is intentionally omitted from both the INSERT column list
11
+ * and the ON CONFLICT SET clause: the column's DEFAULT 0 seeds fresh rows, and
12
+ * omitting it from SET leaves an existing row's value untouched on update
13
+ * (never written going forward). The column itself is dropped in migration 018.
14
+ */
15
+ export function upsertAssetOutcome(db, values) {
16
+ db.prepare(`INSERT INTO asset_outcome
17
+ (asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate,
18
+ negative_feedback_count, accepted_change_count,
19
+ outcome_score, updated_at)
20
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
21
+ ON CONFLICT(asset_ref) DO UPDATE SET
22
+ last_retrieved_at = excluded.last_retrieved_at,
23
+ retrieval_count = excluded.retrieval_count,
24
+ expected_retrieval_rate= excluded.expected_retrieval_rate,
25
+ negative_feedback_count= excluded.negative_feedback_count,
26
+ accepted_change_count = excluded.accepted_change_count,
27
+ outcome_score = excluded.outcome_score,
28
+ updated_at = excluded.updated_at`).run(values.ref, values.lastRetrievedAt, values.retrievalCount, values.expectedRetrievalRate, values.negativeFeedbackCount, values.acceptedChangeCount, values.outcomeScore, values.updatedAt);
29
+ }
30
+ /**
31
+ * Load the outcome row for one asset, or `undefined` if not yet written.
32
+ */
33
+ export function getAssetOutcome(db, ref) {
34
+ const row = db
35
+ .prepare(`SELECT asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate,
36
+ negative_feedback_count, accepted_change_count,
37
+ outcome_score, updated_at
38
+ FROM asset_outcome WHERE asset_ref = ?`)
39
+ .get(ref);
40
+ return row == null ? undefined : row;
41
+ }
42
+ /**
43
+ * Load ALL asset_outcome rows. Used for the proxy-adequacy tripwire computation.
44
+ */
45
+ export function getAllAssetOutcomes(db) {
46
+ return db
47
+ .prepare(`SELECT asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate,
48
+ negative_feedback_count, accepted_change_count,
49
+ outcome_score, updated_at
50
+ FROM asset_outcome ORDER BY asset_ref`)
51
+ .all();
52
+ }
53
+ /**
54
+ * Build a Map<ref, outcome_score> for a set of refs in one query.
55
+ * Used by `salience.ts` to populate `outcomeSalience`.
56
+ */
57
+ export function getOutcomeScoresByRef(db, refs) {
58
+ const result = new Map();
59
+ if (refs.length === 0)
60
+ return result;
61
+ const CHUNK = 500;
62
+ for (let i = 0; i < refs.length; i += CHUNK) {
63
+ const chunk = refs.slice(i, i + CHUNK);
64
+ const placeholders = chunk.map(() => "?").join(",");
65
+ const rows = db
66
+ .prepare(`SELECT asset_ref, outcome_score FROM asset_outcome WHERE asset_ref IN (${placeholders})`)
67
+ .all(...chunk);
68
+ for (const row of rows) {
69
+ result.set(row.asset_ref, row.outcome_score);
70
+ }
71
+ }
72
+ return result;
73
+ }
74
+ /** List every `asset_outcome` ref with its current `missing_since` marker. */
75
+ export function listAssetOutcomeMissingState(db) {
76
+ return db.prepare(`SELECT asset_ref, missing_since FROM asset_outcome`).all();
77
+ }
78
+ /**
79
+ * Stamp `missing_since = now` for the given refs, but ONLY where it is
80
+ * currently NULL — a ref already stamped keeps its original timestamp so the
81
+ * grace window measures from first sighting, not last. Refs with no row at
82
+ * all are silently skipped (0 rows affected). Returns the number of rows
83
+ * actually stamped.
84
+ */
85
+ export function stampAssetOutcomeMissing(db, refs, now) {
86
+ if (refs.length === 0)
87
+ return 0;
88
+ const stmt = db.prepare(`UPDATE asset_outcome SET missing_since = ? WHERE asset_ref = ? AND missing_since IS NULL`);
89
+ let changed = 0;
90
+ for (const ref of refs)
91
+ changed += Number(stmt.run(now, ref).changes);
92
+ return changed;
93
+ }
94
+ /**
95
+ * Clear `missing_since` for refs that resolved again. Returns the number of
96
+ * rows actually cleared.
97
+ */
98
+ export function clearAssetOutcomeMissing(db, refs) {
99
+ if (refs.length === 0)
100
+ return 0;
101
+ const stmt = db.prepare(`UPDATE asset_outcome SET missing_since = NULL WHERE asset_ref = ? AND missing_since IS NOT NULL`);
102
+ let changed = 0;
103
+ for (const ref of refs)
104
+ changed += Number(stmt.run(ref).changes);
105
+ return changed;
106
+ }
107
+ /**
108
+ * Delete `asset_outcome` rows whose `missing_since` is older than
109
+ * `cutoffMs`. A single DELETE — SQLite runs it as one implicit transaction.
110
+ * Returns the number of rows deleted.
111
+ */
112
+ export function deleteAssetOutcomeMissingBefore(db, cutoffMs) {
113
+ return Number(db.prepare(`DELETE FROM asset_outcome WHERE missing_since IS NOT NULL AND missing_since < ?`).run(cutoffMs).changes);
114
+ }
115
+ /** Count `asset_outcome` rows currently marked missing (the live backlog size). */
116
+ export function countAssetOutcomeMissing(db) {
117
+ const row = db.prepare(`SELECT COUNT(*) AS n FROM asset_outcome WHERE missing_since IS NOT NULL`).get();
118
+ return row.n;
119
+ }