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
@@ -23,6 +23,9 @@ import { purgeOldCycleMetrics } from "../../storage/repositories/canaries-reposi
23
23
  import { purgeOldEvents } from "../../storage/repositories/events-repository.js";
24
24
  import { purgeOldImproveRuns } from "../../storage/repositories/improve-runs-repository.js";
25
25
  import { closeDatabase, openIndexDatabase } from "../../storage/repositories/index-connection.js";
26
+ import { getEntryByRef } from "../../storage/repositories/index-entries-repository.js";
27
+ import { clearAssetOutcomeMissing, countAssetOutcomeMissing, deleteAssetOutcomeMissingBefore, listAssetOutcomeMissingState, stampAssetOutcomeMissing, } from "../../storage/repositories/outcome-repository.js";
28
+ import { clearAssetSalienceMissing, countAssetSalienceMissing, deleteAssetSalienceMissingBefore, listAssetSalienceMissingState, stampAssetSalienceMissing, } from "../../storage/repositories/salience-repository.js";
26
29
  import { expireStaleProposals, listProposals, purgeOrphanProposals } from "../proposal/repository.js";
27
30
  import { checkDeadUrls } from "../url-checker.js";
28
31
  import { DEFAULT_RETENTION_DAYS as CYCLE_METRICS_RETENTION_DAYS, runCollapseDetector } from "./collapse-detector.js";
@@ -34,7 +37,7 @@ import { writeEvalCase } from "./eval-cases.js";
34
37
  import { shouldSkipRef } from "./improve-strategies.js";
35
38
  import { recordNoOp, resetConsecutiveNoOps } from "./salience.js";
36
39
  import { errMessage, refSlug } from "./shared.js";
37
- import { durableImproveRef } from "./source-identity.js";
40
+ import { bareImproveRef, durableImproveRef } from "./source-identity.js";
38
41
  // ── improve loop / post-loop / maintenance stages ───────────────────
39
42
  // The cycle stages run by akmImprove, extracted from improve.ts.
40
43
  /** O-5 / #378: rolling per-originator error-window cap. */
@@ -180,17 +183,17 @@ async function runLoopReflectPass(planned, isDistillOnly, env, tally) {
180
183
  const reflectProfileRunner = resolvedPlan.processes.reflect.runner;
181
184
  const reflectCallArgs = {
182
185
  ref: planned.ref,
183
- ...(options.sourceName ? { sourceName: options.sourceName } : {}),
184
- ...(options.legacyBareState ? { legacyBareState: true } : {}),
185
- // Chunk-5 flip F5f — carry the resolved item_ref so reflect keys its
186
- // reflect_invoked event + source/distill_invoked reads on it (dormant
187
- // until item_ref populates through the improve path).
186
+ // Carry the resolved item_ref so reflect uses the same durable key for
187
+ // events and state reads.
188
188
  ...(planned.itemRef ? { itemRef: planned.itemRef } : {}),
189
189
  task: options.task,
190
190
  // Active strategy supplies non-engine process tuning.
191
191
  ...(improveProfile ? { improveProfile } : {}),
192
192
  config: options.config,
193
193
  ...(primaryStashDir ? { stashDir: primaryStashDir } : {}),
194
+ ...(options.sourceName && primaryStashDir
195
+ ? { target: { source: options.sourceName, root: primaryStashDir } }
196
+ : {}),
194
197
  ...(reflectErrors.length > 0 ? { avoidPatterns: [...reflectErrors] } : {}),
195
198
  eventSource: "improve",
196
199
  // #639 — resolve the low-value filter from the ACTIVE improve profile
@@ -271,11 +274,8 @@ async function runLoopReflectPass(planned, isDistillOnly, env, tally) {
271
274
  // A no_change reflect means the LLM was invoked but found nothing to
272
275
  // improve — the asset is stable. Track it. A successful reflect means
273
276
  // the asset changed; reset the counter so the dampener lifts.
274
- // Chunk-5 flip F5e — key the plasticity counter by the SAME durable
275
- // salience write key the preparation/distill salience writers use:
276
- // item_ref when the planner resolved one, else the source-qualified
277
- // `type:name`. A split key would strand consecutive_no_ops on a second row.
278
- const plasticityKey = planned.itemRef ?? durableImproveRef(planned.ref, options.sourceName);
277
+ // Use the same item_ref-or-conceptId salience key as preparation/distill.
278
+ const plasticityKey = planned.itemRef ?? durableImproveRef(planned.ref);
279
279
  if (isNoChange && eventsCtx?.db) {
280
280
  try {
281
281
  recordNoOp(eventsCtx.db, plasticityKey);
@@ -430,11 +430,8 @@ async function invokeDistillAndRecord(planned, parsedPlannedRef, env, tally) {
430
430
  const { options, primaryStashDir, distillFn, eventsCtx, improveProfile, resolvedPlan, budgetSignal } = env;
431
431
  const distillResult = await withLlmStage("distill", () => distillFn({
432
432
  ref: planned.ref,
433
- // Chunk-5 flip F5e — the resolved item_ref so distill keys its salience
434
- // write by it (matching preparation), when the planner supplied one.
433
+ // Carry the resolved item_ref so distill matches preparation's state key.
435
434
  ...(planned.itemRef ? { itemRef: planned.itemRef } : {}),
436
- ...(options.sourceName ? { sourceName: options.sourceName } : {}),
437
- ...(options.legacyBareState ? { legacyBareState: true } : {}),
438
435
  ...(parsedPlannedRef.type === "memory" ? { proposalKind: "auto" } : {}),
439
436
  ...(primaryStashDir ? { stashDir: primaryStashDir } : {}),
440
437
  // Active profile so distill's per-process reads honor `--profile`.
@@ -461,9 +458,8 @@ async function invokeDistillAndRecord(planned, parsedPlannedRef, env, tally) {
461
458
  // quality gate — the asset is not yielding useful distill output.
462
459
  // queued: a proposal was produced; reset the no-op counter.
463
460
  if (eventsCtx?.db) {
464
- // Chunk-5 flip F5e — same durable salience write key as the distill/
465
- // preparation salience writers (item_ref, else source-qualified type:name).
466
- const plasticityKey = planned.itemRef ?? durableImproveRef(planned.ref, options.sourceName);
461
+ // Use the same item_ref-or-conceptId key as the distill/preparation writers.
462
+ const plasticityKey = planned.itemRef ?? durableImproveRef(planned.ref);
467
463
  try {
468
464
  if (distillResult.outcome === "quality_rejected" || distillResult.outcome === "skipped") {
469
465
  recordNoOp(eventsCtx.db, plasticityKey);
@@ -624,7 +620,6 @@ export async function runImprovePostLoopStage(args) {
624
620
  runId: options.runId ?? "improve-adhoc",
625
621
  ...(improveProfile ? { improveProfile } : {}),
626
622
  pass: "consolidate",
627
- acceptedActions: args.acceptedActions ?? 0,
628
623
  mergeFloorViolations: args.consolidationMergeFloorViolations ?? 0,
629
624
  config: options.config ?? loadConfig(),
630
625
  ...(eventsCtx ? { eventsCtx } : {}),
@@ -744,6 +739,12 @@ async function runMaintenancePassesUnderLease(ctx, dbCell, args) {
744
739
  allWarnings.push(...graph.warnings);
745
740
  const orphan = runOrphanProposalPurgePass(ctx);
746
741
  allWarnings.push(...orphan.warnings);
742
+ // #733: orphan-state GC — stamps/clears/(optionally) collects
743
+ // asset_salience/asset_outcome rows whose ref no longer resolves in
744
+ // index.db. Needs the SAME already-open index.db handle (dbCell.current)
745
+ // the passes above share.
746
+ const stateGc = runOrphanStateGcPass(ctx, dbCell);
747
+ allWarnings.push(...stateGc.warnings);
747
748
  const expiration = runProposalExpirationPass(ctx);
748
749
  allWarnings.push(...expiration.warnings);
749
750
  allWarnings.push(...runRetentionPurgePass(ctx).warnings);
@@ -764,7 +765,7 @@ async function runMaintenancePassesUnderLease(ctx, dbCell, args) {
764
765
  }
765
766
  /**
766
767
  * Memory inference candidate-discovery (post-Item 9 fix from
767
- * memory:akm-improve-critical-review-2026-05-20). Previously this pass
768
+ * memories/akm-improve-critical-review-2026-05-20). Previously this pass
768
769
  * was gated on memoryRefsForInference.size > 0 AND passed those refs as a
769
770
  * candidateRefs filter. But memoryRefsForInference is populated from refs
770
771
  * distilled THIS RUN — by the time that happens, those parents are
@@ -1123,3 +1124,164 @@ export function runRetentionPurgePass(ctx) {
1123
1124
  }
1124
1125
  return { warnings };
1125
1126
  }
1127
+ // ── #733 — orphan-state GC pass (Workstream C) ──────────────────────────────
1128
+ //
1129
+ // Deliberately lean: one maintenance pass, one additive migration (021), one
1130
+ // event type (asset_state_gc), one config gate (improve.stateGc.collect,
1131
+ // default false). See docs/architecture/specs/0.9.0-close-out-plan.md
1132
+ // Workstream C for the full design rationale. No quarantine archive, no
1133
+ // circuit breaker, no health-advisory plumbing, no new tables.
1134
+ /**
1135
+ * Grace window (ms) before an unresolved `asset_salience` / `asset_outcome`
1136
+ * row becomes delete-eligible — only when `improve.stateGc.collect` is true.
1137
+ * A named constant, not a config knob (owner ruling — see the close-out
1138
+ * plan's Workstream C). Mirrors `TXN_SWEEP_GRACE_MS` (src/core/fs-txn.ts:298).
1139
+ */
1140
+ export const STATE_GC_GRACE_MS = daysToMs(7);
1141
+ /**
1142
+ * Resolve one state-table's stored `asset_ref` against the live index.
1143
+ *
1144
+ * "ref not present in entries.item_ref" is the authoritative-deletion
1145
+ * predicate (see the pass doc comment below), so this is a thin wrapper
1146
+ * around the same single-ref probe the rest of improve uses
1147
+ * (`getEntryByRef`, index-entries-repository.ts) — which already resolves
1148
+ * both storage spellings a write can produce (`salienceWriteKey`/
1149
+ * `outcomeWriteKey` = `itemRef ?? ref`): an exact bundle-qualified item_ref,
1150
+ * or a bare conceptId matched by suffix across all bundles.
1151
+ *
1152
+ * On top of that, falls back to the BARE conceptId form (`bareImproveRef` —
1153
+ * the same primitive `preparation.ts`'s `normalizeStoredKey` map is built
1154
+ * from via `improveStateReadRefs`) when the stored ref carries a bundle
1155
+ * prefix that no longer matches exactly. This is the legacy-spelling
1156
+ * normalization trap: a naive `asset_ref NOT IN (SELECT item_ref FROM
1157
+ * entries)` would treat a live asset whose row predates bundle-qualification
1158
+ * (or whose bundle prefix is stale) as an orphan and delete it. Preferring
1159
+ * "never delete a live row" over "never miss a genuinely dead one" mirrors
1160
+ * `getEntryByRef`'s own bare-conceptId suffix-match trade-off.
1161
+ */
1162
+ function isStateRefLive(indexDb, storedRef) {
1163
+ if (getEntryByRef(indexDb, storedRef) !== null)
1164
+ return true;
1165
+ const bare = bareImproveRef(storedRef);
1166
+ return bare !== storedRef && getEntryByRef(indexDb, bare) !== null;
1167
+ }
1168
+ /**
1169
+ * Sweep ONE state table: stamp refs that just went unresolved, clear refs
1170
+ * that resolved again, and — only when `collect` is true — delete rows whose
1171
+ * `missing_since` is older than {@link STATE_GC_GRACE_MS}. `pending` is a
1172
+ * point-in-time snapshot taken AFTER stamp/clear/delete (re-queried, not
1173
+ * accumulated), so it reflects the current backlog rather than this run's
1174
+ * delta — "every run emits the counts either way, so live data accumulates
1175
+ * proof" (close-out plan, Workstream C).
1176
+ */
1177
+ function gcOneStateTable(args) {
1178
+ const { refRows, indexDb, now, collect, stamp, clear, deleteOlderThan, countPending } = args;
1179
+ const toStamp = [];
1180
+ const toClear = [];
1181
+ for (const row of refRows) {
1182
+ const live = isStateRefLive(indexDb, row.asset_ref);
1183
+ if (!live && row.missing_since == null)
1184
+ toStamp.push(row.asset_ref);
1185
+ else if (live && row.missing_since != null)
1186
+ toClear.push(row.asset_ref);
1187
+ }
1188
+ if (toStamp.length > 0)
1189
+ stamp(toStamp, now);
1190
+ if (toClear.length > 0)
1191
+ clear(toClear);
1192
+ const collected = collect ? deleteOlderThan(now - STATE_GC_GRACE_MS) : 0;
1193
+ const pending = countPending();
1194
+ return { pending, collected };
1195
+ }
1196
+ /**
1197
+ * Orphan-state GC — #733 (Workstream C). For each of the two per-asset state
1198
+ * tables (`asset_salience`, `asset_outcome`), stamps `missing_since` on refs
1199
+ * that no longer resolve against `entries.item_ref` in index.db, clears the
1200
+ * stamp on refs that resolve again, and — only when `improve.stateGc.collect`
1201
+ * is true — deletes rows whose stamp is older than {@link STATE_GC_GRACE_MS}.
1202
+ *
1203
+ * "ref not present in entries.item_ref" IS the authoritative-deletion
1204
+ * predicate: "absent ≠ deleted" is inherited from the indexer, not
1205
+ * re-implemented here — an incomplete or failed source scan preserves that
1206
+ * source's last-known-good `entries` rows (indexer.ts ~1195-1199), and
1207
+ * mass-wipe is already gated upstream (`preserveExistingIndex` +
1208
+ * `fullDelete && scanComplete`). A temporarily unreachable source therefore
1209
+ * never surfaces candidates; no separate scan-status tracking is needed.
1210
+ *
1211
+ * Runs under the SAME index-writer lease / borrowed-state.db-connection
1212
+ * discipline as the neighboring maintenance passes: `dbCell.current` supplies
1213
+ * the already-open index.db handle (#584), and state.db access goes through
1214
+ * `withStateDb(..., { borrowed: eventsCtx?.db })` so this never opens a
1215
+ * second live writer alongside a long-lived `eventsCtx.db` connection — see
1216
+ * the #585 comment on {@link runRetentionPurgePass}'s events-purge call for
1217
+ * why that matters ("database is locked").
1218
+ *
1219
+ * Exported for direct test coverage (tests/integration/commands/improve/
1220
+ * state-gc.test.ts), mirroring the `runMemoryInferenceMaintenancePass` /
1221
+ * `runGraphExtractionMaintenancePass` / `runRetentionPurgePass` precedent;
1222
+ * production callers reach it only through `runMaintenancePassesUnderLease`.
1223
+ */
1224
+ export function runOrphanStateGcPass(ctx, dbCell) {
1225
+ const { eventsCtx, config } = ctx;
1226
+ const warnings = [];
1227
+ const indexDb = dbCell.current;
1228
+ if (!indexDb) {
1229
+ warnings.push("orphan state GC skipped: no index.db handle available");
1230
+ return { pending: 0, collected: 0, warnings };
1231
+ }
1232
+ const collect = config.improve?.stateGc?.collect === true;
1233
+ const now = Date.now();
1234
+ let pending = 0;
1235
+ let collected = 0;
1236
+ try {
1237
+ withStateDb((stateDb) => {
1238
+ const salienceResult = gcOneStateTable({
1239
+ refRows: listAssetSalienceMissingState(stateDb),
1240
+ indexDb,
1241
+ now,
1242
+ collect,
1243
+ stamp: (refs, ts) => stampAssetSalienceMissing(stateDb, refs, ts),
1244
+ clear: (refs) => clearAssetSalienceMissing(stateDb, refs),
1245
+ deleteOlderThan: (cutoffMs) => deleteAssetSalienceMissingBefore(stateDb, cutoffMs),
1246
+ countPending: () => countAssetSalienceMissing(stateDb),
1247
+ });
1248
+ const outcomeResult = gcOneStateTable({
1249
+ refRows: listAssetOutcomeMissingState(stateDb),
1250
+ indexDb,
1251
+ now,
1252
+ collect,
1253
+ stamp: (refs, ts) => stampAssetOutcomeMissing(stateDb, refs, ts),
1254
+ clear: (refs) => clearAssetOutcomeMissing(stateDb, refs),
1255
+ deleteOlderThan: (cutoffMs) => deleteAssetOutcomeMissingBefore(stateDb, cutoffMs),
1256
+ countPending: () => countAssetOutcomeMissing(stateDb),
1257
+ });
1258
+ // Table-name-shaped keys ("salience"/"outcome", not the guarded
1259
+ // "asset_salience"/"asset_outcome" table names) — this file sits
1260
+ // outside src/storage/repositories/**, where the state-table-sql
1261
+ // lint rule (#672) forbids naming those tables even in a log string
1262
+ // or an object key, not just in raw SQL.
1263
+ const byTable = { salience: salienceResult, outcome: outcomeResult };
1264
+ pending = salienceResult.pending + outcomeResult.pending;
1265
+ collected = salienceResult.collected + outcomeResult.collected;
1266
+ if (pending > 0 || collected > 0) {
1267
+ info(`[improve] orphan state GC: ${pending} pending, ${collected} collected ` +
1268
+ `(salience ${salienceResult.pending}/${salienceResult.collected}, ` +
1269
+ `outcome ${outcomeResult.pending}/${outcomeResult.collected})`);
1270
+ // #733 — asset_state_gc reports the current per-table backlog
1271
+ // snapshot (`pending`) plus this run's deletions (`collected`);
1272
+ // emitted only when there is something to report (mirrors the
1273
+ // rekey script's no-op-stays-silent precedent) so a perpetually
1274
+ // clean stash never accumulates events.
1275
+ appendEvent({
1276
+ eventType: "asset_state_gc",
1277
+ ref: "asset_state/_gc",
1278
+ metadata: { pending, collected, byTable },
1279
+ }, eventsCtx);
1280
+ }
1281
+ }, { path: eventsCtx?.dbPath, borrowed: eventsCtx?.db });
1282
+ }
1283
+ catch (err) {
1284
+ warnings.push(`orphan state GC failed: ${errMessage(err)}`);
1285
+ }
1286
+ return { pending, collected, warnings };
1287
+ }
@@ -9,10 +9,9 @@
9
9
  * (`memory-improve.ts`, keyed on the memory name) and the PRODUCER
10
10
  * (`memory-contradiction-detect.ts`, keyed on the file path). The producer's
11
11
  * copy was strictly narrower: it ignored `derivedFrom` entirely and matched
12
- * `source:` only via a raw `startsWith("memory:")` (so a whitespace- or
13
- * origin-prefixed `source:` fell through to the filename heuristic). That let
14
- * the producer and consumer disagree on a memory's parent — the exact defect
15
- * plan §6 calls out ("producer/consumer cannot disagree").
12
+ * `source:` through a separate parser. That let the producer and consumer
13
+ * disagree on a memory's parent — the exact defect plan §6 calls out
14
+ * ("producer/consumer cannot disagree").
16
15
  *
17
16
  * Both sides now share this one impl, keyed on the memory NAME (the stash-
18
17
  * relative path without the `.md` extension, e.g. `nested/foo.derived`). The
@@ -21,9 +20,8 @@
21
20
  * `tests/commands/improve/derived-ref.test.ts`:
22
21
  * - `derivedFrom`-keyed families now resolve a parent (and so participate in
23
22
  * contradiction detection); and
24
- * - `source:` is normalised through `parseRefInput` (trim + origin) so a
25
- * `source: " team//memory:parent "` resolves to `memory:parent` instead of
26
- * silently degrading to the filename.
23
+ * - `source:` is parsed through `parseRefInput` so current bundle-qualified
24
+ * refs resolve consistently.
27
25
  *
28
26
  * Resolution order (source → derivedFrom → `.derived` suffix) matches the
29
27
  * consumer's prior behaviour exactly, so the consumer side is a pure move.
@@ -32,62 +30,66 @@ import { conceptIdFromTypeName, parseRefInput } from "../../../core/asset/resolv
32
30
  import { asNonEmptyString } from "../../../core/common.js";
33
31
  import { DERIVED_SUFFIX } from "../../../core/recognition-util.js";
34
32
  /**
35
- * Parse an arbitrary `source:`/edge string to the BARE memory name (no type
36
- * prefix), or `undefined` when it is empty, unparseable, or not a memory ref.
37
- * Trims whitespace and drops any origin/bundle prefix.
33
+ * Parse a belief edge (`supersededBy` / `contradictedBy` / `currentBeliefRefs`)
34
+ * to the bare memory name the identity channel keys on.
38
35
  *
39
- * READ tolerance is intentionally dual-grammar: the value may carry the legacy
40
- * `[origin//]memory:<name>` spelling (un-migrated stash content in the wild) OR
41
- * the 0.9.0 `[bundle//]memories/<name>` conceptId. Callers format the bare name
42
- * into whichever CHANNEL grammar they compare against:
43
- * - the `derived_from` channel → `memories/<name>` conceptId (see
44
- * {@link parseMemoryRef} / {@link resolveParentRef});
45
- * - the belief-edge / identity channel → `memory:<name>` (memory-improve's
46
- * `refArray`, compared against a derived memory's own `memory:<name>` ref,
47
- * a separate legacy remnant Group-C item 2 does NOT touch).
36
+ * Accepts BOTH spellings, because both reach this function:
37
+ * - `memory:<name>` — the internal identity spelling, and what belief edges
38
+ * written before 0.9.0 carry on disk;
39
+ * - `memories/<name>` / `<bundle>//memories/<name>` — the conceptId grammar
40
+ * the current writers emit (`akm remember --supersedes` and `akm import
41
+ * --supersedes` go through `writeSupersededEdge` with the write result's
42
+ * `ref`, which is fully qualified).
43
+ *
44
+ * Accepting only the first spelling silently reduced every edge written by the
45
+ * current code path to nothing, so a superseded memory read back as active.
46
+ * Both normalize to the bare name; the caller re-mints the internal
47
+ * `memory:<name>` form via {@link memoryIdentityRef}, so there is still exactly
48
+ * one identity spelling downstream.
48
49
  */
49
50
  export function parseMemoryName(value) {
50
51
  if (!value)
51
52
  return undefined;
52
53
  const trimmed = value.trim();
54
+ const MEMORY_PREFIX = "memory:";
55
+ if (trimmed.startsWith(MEMORY_PREFIX)) {
56
+ const name = trimmed.slice(MEMORY_PREFIX.length);
57
+ return name.length > 0 ? name : undefined;
58
+ }
53
59
  try {
54
60
  const parsed = parseRefInput(trimmed);
55
- return parsed.type === "memory" ? parsed.name : undefined;
61
+ return parsed.type === "memory" && parsed.name.length > 0 ? parsed.name : undefined;
56
62
  }
57
63
  catch {
58
- // Legacy `[origin//]memory:<name>` — strip the origin, keep memory refs only.
59
- const boundary = trimmed.indexOf("//");
60
- const body = boundary >= 0 ? trimmed.slice(boundary + 2) : trimmed;
61
- const MEMORY_PREFIX = "memory:";
62
- return body.startsWith(MEMORY_PREFIX) ? body.slice(MEMORY_PREFIX.length) : undefined;
64
+ return undefined;
63
65
  }
64
66
  }
65
67
  /**
66
- * Normalise an arbitrary `source:` derived_from backref to the canonical 0.9.0
67
- * `memories/<name>` conceptId, or `undefined` when it is not a memory ref
68
- * (Group-C item 2 flip). Tolerant of BOTH grammars on input (see
69
- * {@link parseMemoryName}), but the NORMALISED OUTPUT is always the conceptId —
70
- * so every consumer that compares against the `derived_from` channel (the
71
- * parentRef filter, inference dedup, eligibility) speaks one grammar. The
72
- * content-migration folds the on-disk legacy spelling forward; this reader keeps
73
- * tolerating it until the 0.10.0 grammar removal.
68
+ * Parse a current `source:` backref and return its canonical memory conceptId,
69
+ * or `undefined` when it is empty, invalid, or not a memory ref.
74
70
  */
75
71
  export function parseMemoryRef(value) {
76
- const name = parseMemoryName(value);
77
- return name === undefined ? undefined : conceptIdFromTypeName("memory", name);
72
+ if (!value)
73
+ return undefined;
74
+ try {
75
+ const parsed = parseRefInput(value.trim());
76
+ return parsed.type === "memory" ? conceptIdFromTypeName("memory", parsed.name) : undefined;
77
+ }
78
+ catch {
79
+ return undefined;
80
+ }
78
81
  }
79
82
  /**
80
83
  * Format a bare memory name into the belief-edge IDENTITY channel ref
81
84
  * `memory:<name>` — the ONE implementation of that spelling.
82
85
  *
83
- * DOCUMENTED EXCEPTION (ref-grammar decision D-R3): the belief-edge / identity
86
+ * Belief-edge / identity
84
87
  * channel (`contradictedBy` / `supersededBy` / `currentBeliefRefs`, and a derived
85
- * memory's own `record.ref`) deliberately stays in `memory:<name>` grammar — it
86
- * is compared against a derived memory's own identity ref, a channel DECOUPLED
87
- * from the `derived_from` record refs that Group-C item 2 flipped to
88
- * `memories/<name>`. Both `memory-improve.ts` (`refArray`) and
88
+ * memory's own `record.ref`) uses `memory:<name>` and is compared against a
89
+ * derived memory's identity ref. This channel is separate from `source:` asset
90
+ * refs, which use `memories/<name>`. Both `memory-improve.ts` (`refArray`) and
89
91
  * `memory-contradiction-detect.ts` (`toMemoryRef`) emit through here so the
90
- * exception has exactly one home instead of three hand-rolled copies.
92
+ * identity spelling has one implementation.
91
93
  */
92
94
  export function memoryIdentityRef(name) {
93
95
  return `memory:${name}`;
@@ -101,8 +103,8 @@ export function isDerivedMemory(name, frontmatter) {
101
103
  return frontmatter.inferred === true || name.endsWith(DERIVED_SUFFIX);
102
104
  }
103
105
  /**
104
- * Resolve the parent (source) memory ref for a derived memory as the canonical
105
- * `memories/<name>` conceptId (Group-C item 2 flip), or `undefined` when none
106
+ * Resolve the parent (source) memory ref for a derived memory as a canonical
107
+ * `memories/<name>` conceptId, or `undefined` when none
106
108
  * can be determined. Precedence:
107
109
  * 1. `frontmatter.source` (normalised through {@link parseMemoryRef});
108
110
  * 2. `frontmatter.derivedFrom` (a bare memory name → `memories/<name>`);
@@ -63,7 +63,7 @@ function readEdgeList(value) {
63
63
  * present WITHOUT the demotion (e.g. a hand-written `contradictedBy:` line,
64
64
  * or a beliefState lost to a partial edit) is repaired, not skipped — an
65
65
  * edge-only guard would make such a file a permanent no-op while
66
- * consolidate's handleContradictOp reports the contradiction as applied.
66
+ * contradiction writers report the contradiction as applied.
67
67
  *
68
68
  * Never weakens a stronger demotion: `archived` ranks BELOW `contradicted`
69
69
  * (see `BELIEF_STATE_SCORE_CEILINGS` in
@@ -37,9 +37,10 @@ import fs from "node:fs";
37
37
  import path from "node:path";
38
38
  import contradictionJudgeTemplate from "../../../assets/prompts/contradiction-judge.md" with { type: "text" };
39
39
  import { mutateFrontmatter, parseFrontmatter } from "../../../core/asset/frontmatter.js";
40
+ import { parseEmbeddedJsonResponse } from "../../../core/parse.js";
40
41
  import { getDefaultLlmConfig } from "../../../integrations/agent/engine-resolution.js";
41
42
  import { materializeLlmRunnerConnection, resolveImproveProcessRunner } from "../../../integrations/agent/runner.js";
42
- import { chatCompletion, parseEmbeddedJsonResponse } from "../../../llm/client.js";
43
+ import { chatCompletion } from "../../../llm/client.js";
43
44
  import { callStructured } from "../../../llm/structured-call.js";
44
45
  import { isDerivedMemory, memoryIdentityRef, resolveParentRef } from "./derived-ref.js";
45
46
  // ── Constants ────────────────────────────────────────────────────────────────
@@ -56,8 +57,7 @@ const MAX_PAIRS_PER_RUN = 20;
56
57
  /**
57
58
  * Minimum confidence required to write a contradiction edge. Below this
58
59
  * threshold the LLM may be flagging topic-overlap rather than genuine logical
59
- * exclusivity (investigation 2026-06-18). Absent confidence fields default to
60
- * 1.0 for backward compatibility with older judge responses.
60
+ * exclusivity (investigation 2026-06-18).
61
61
  */
62
62
  const CONTRADICT_CONFIDENCE_THRESHOLD = 0.92;
63
63
  /**
@@ -230,11 +230,6 @@ export async function detectAndWriteContradictions(stashDir, config, chat = chat
230
230
  // edge already exists (no new information; avoids re-judging resolved
231
231
  // pairs across runs).
232
232
  //
233
- // Legacy mutual A↔B edges written by the pre-fix pass self-heal: the
234
- // skip fires this run, but the SCC resolver treats the 2-cycle as a sink
235
- // and refreshes both to active — DELETING both `contradictedBy` arrays
236
- // (memory-improve.ts persistBeliefStateTransition). The next detection
237
- // run then sees no edge, re-judges, and writes the single canonical edge.
238
233
  const aParsed = parseFrontmatter(fs.readFileSync(a.filePath, "utf8"));
239
234
  const bParsed = parseFrontmatter(fs.readFileSync(b.filePath, "utf8"));
240
235
  const { loser, winnerRef } = pickContradictionLoser(a, b);
@@ -274,10 +269,7 @@ export async function detectAndWriteContradictions(stashDir, config, chat = chat
274
269
  }
275
270
  if (!parsed?.contradicts)
276
271
  continue;
277
- // Confidence gate: absent field defaults to 1.0 (backward compat with
278
- // pre-confidence responses). Do NOT default to 0 — that would silently
279
- // disable all detection during the rollout period.
280
- const confidence = typeof parsed.confidence === "number" ? parsed.confidence : 1.0;
272
+ const confidence = typeof parsed.confidence === "number" ? parsed.confidence : 0;
281
273
  if (confidence < CONTRADICT_CONFIDENCE_THRESHOLD) {
282
274
  result.warnings.push(`Pair ${a.ref} / ${b.ref}: confidence ${confidence.toFixed(2)} below ${CONTRADICT_CONFIDENCE_THRESHOLD} threshold — skipped.`);
283
275
  continue;
@@ -657,11 +657,12 @@ function resolveBeliefState(frontmatter) {
657
657
  // Belief-edge refs (contradictedBy / supersededBy / currentBeliefRefs) are the
658
658
  // IDENTITY channel: they are compared against a derived memory's own
659
659
  // `memory:<name>` ref (resolveFamilyContradictions' familyRefSet,
660
- // firstExistingRef's byRef map), so they stay in `memory:<name>` grammar. This
661
- // is deliberately NOT the `memories/<name>` derived_from conceptId — Group-C
662
- // item 2 flipped only that channel. We parse the tolerant bare name and format
663
- // it back into identity grammar so both grammars on disk resolve to the ref
664
- // record.ref carries.
660
+ // firstExistingRef's byRef map), so they are NORMALIZED to `memory:<name>` here.
661
+ // On disk they arrive in either spelling — `memory:<name>` from pre-0.9.0
662
+ // writes, or the `[<bundle>//]memories/<name>` conceptId that
663
+ // `writeSupersededEdge`/`writeContradictEdge` persist today — and
664
+ // `parseMemoryName` accepts both. Reading only the first spelling silently
665
+ // dropped every edge the current write path produces.
665
666
  function refArray(value) {
666
667
  if (typeof value === "string") {
667
668
  const name = parseMemoryName(value);
@@ -1,6 +1,7 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
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
+ import { getAllAssetOutcomes, getAssetOutcome, getOutcomeScoresByRef, upsertAssetOutcome, } from "../../storage/repositories/outcome-repository.js";
4
5
  // ── Constants ─────────────────────────────────────────────────────────────────
5
6
  /**
6
7
  * EMA decay factor for the expected-retrieval rolling mean (α).
@@ -94,76 +95,32 @@ export function updateAssetOutcome(db, inputs) {
94
95
  const newScore = OUTCOME_EMA_ALPHA * rawUpdate + (1 - OUTCOME_EMA_ALPHA) * existing.outcome_score;
95
96
  // Clip to [OUTCOME_SCORE_MIN, OUTCOME_SCORE_MAX] — the ceiling is the RPE
96
97
  // saturation analog (G2): without it, long-lived popular assets accumulate
97
- // unbounded positive mass (live max was 3.13) and would dominate rank_score
98
- // the moment the outcome weight is enabled. Stored legacy scores above the
99
- // ceiling converge back under it on their next differential update.
98
+ // unbounded positive mass and would dominate rank_score when outcome weight
99
+ // is enabled.
100
100
  outcomeScore = Math.min(OUTCOME_SCORE_MAX, Math.max(OUTCOME_SCORE_MIN, newScore));
101
101
  }
102
- // Upsert the row. `review_pressure` is intentionally omitted from both the
103
- // INSERT column list and the ON CONFLICT SET clause: the column's DEFAULT 0
104
- // seeds fresh rows, and omitting it from SET leaves an existing row's value
105
- // untouched on update (never written going forward). The column itself is
106
- // dropped in migration 018.
107
- db.prepare(`INSERT INTO asset_outcome
108
- (asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate,
109
- negative_feedback_count, accepted_change_count,
110
- outcome_score, updated_at)
111
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
112
- ON CONFLICT(asset_ref) DO UPDATE SET
113
- last_retrieved_at = excluded.last_retrieved_at,
114
- retrieval_count = excluded.retrieval_count,
115
- expected_retrieval_rate= excluded.expected_retrieval_rate,
116
- negative_feedback_count= excluded.negative_feedback_count,
117
- accepted_change_count = excluded.accepted_change_count,
118
- outcome_score = excluded.outcome_score,
119
- updated_at = excluded.updated_at`).run(inputs.ref, inputs.lastRetrievedAt, inputs.currentRetrievalCount, expectedRetrievalRate, inputs.negativeFeedbackCount, inputs.acceptedChangeCount, outcomeScore, now);
102
+ // Upsert the row. See `upsertAssetOutcome` in
103
+ // storage/repositories/outcome-repository.ts (#672 part 2) for the SQL text
104
+ // and the `review_pressure` omission rationale — this call site is
105
+ // unchanged in intent, just no longer inline.
106
+ upsertAssetOutcome(db, {
107
+ ref: inputs.ref,
108
+ lastRetrievedAt: inputs.lastRetrievedAt,
109
+ retrievalCount: inputs.currentRetrievalCount,
110
+ expectedRetrievalRate,
111
+ negativeFeedbackCount: inputs.negativeFeedbackCount,
112
+ acceptedChangeCount: inputs.acceptedChangeCount,
113
+ outcomeScore,
114
+ updatedAt: now,
115
+ });
120
116
  return { outcomeScore, isNewRow };
121
117
  }
122
118
  // ── Reader ────────────────────────────────────────────────────────────────────
123
- /**
124
- * Load the outcome row for one asset, or `undefined` if not yet written.
125
- */
126
- export function getAssetOutcome(db, ref) {
127
- const row = db
128
- .prepare(`SELECT asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate,
129
- negative_feedback_count, accepted_change_count,
130
- outcome_score, updated_at
131
- FROM asset_outcome WHERE asset_ref = ?`)
132
- .get(ref);
133
- return row == null ? undefined : row;
134
- }
135
- /**
136
- * Load ALL asset_outcome rows. Used for the proxy-adequacy tripwire computation.
137
- */
138
- export function getAllAssetOutcomes(db) {
139
- return db
140
- .prepare(`SELECT asset_ref, last_retrieved_at, retrieval_count, expected_retrieval_rate,
141
- negative_feedback_count, accepted_change_count,
142
- outcome_score, updated_at
143
- FROM asset_outcome ORDER BY asset_ref`)
144
- .all();
145
- }
146
- /**
147
- * Build a Map<ref, outcome_score> for a set of refs in one query.
148
- * Used by `salience.ts` to populate `outcomeSalience`.
149
- */
150
- export function getOutcomeScoresByRef(db, refs) {
151
- const result = new Map();
152
- if (refs.length === 0)
153
- return result;
154
- const CHUNK = 500;
155
- for (let i = 0; i < refs.length; i += CHUNK) {
156
- const chunk = refs.slice(i, i + CHUNK);
157
- const placeholders = chunk.map(() => "?").join(",");
158
- const rows = db
159
- .prepare(`SELECT asset_ref, outcome_score FROM asset_outcome WHERE asset_ref IN (${placeholders})`)
160
- .all(...chunk);
161
- for (const row of rows) {
162
- result.set(row.asset_ref, row.outcome_score);
163
- }
164
- }
165
- return result;
166
- }
119
+ //
120
+ // getAssetOutcome / getAllAssetOutcomes / getOutcomeScoresByRef moved verbatim
121
+ // to storage/repositories/outcome-repository.ts (#672 part 2) — re-exported
122
+ // here so existing importers of this module resolve unchanged.
123
+ export { getAllAssetOutcomes, getAssetOutcome, getOutcomeScoresByRef };
167
124
  // ── outcomeSalience projection ────────────────────────────────────────────────
168
125
  /**
169
126
  * Convert a raw `outcome_score` (differential, may be negative) to a