akm-cli 0.9.16 → 0.9.17-alpha.10

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 (403) hide show
  1. package/CHANGELOG.md +2101 -0
  2. package/STABILITY.md +11 -10
  3. package/dist/akm +124 -193
  4. package/dist/akm-migrate +38 -19
  5. package/dist/assets/hints/cli-hints-full.md +6 -7
  6. package/dist/assets/improve-strategies/catchup.json +0 -3
  7. package/dist/assets/improve-strategies/consolidate.json +0 -1
  8. package/dist/assets/improve-strategies/default.json +1 -2
  9. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
  10. package/dist/assets/improve-strategies/quick.json +1 -2
  11. package/dist/assets/improve-strategies/reflect-distill.json +1 -2
  12. package/dist/assets/improve-strategies/thorough.json +0 -3
  13. package/dist/assets/prompts/consolidate-pair.md +20 -0
  14. package/dist/assets/prompts/consolidate-system.md +4 -11
  15. package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
  17. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
  18. package/dist/assets/templates/html/health.html +3 -5
  19. package/dist/cli/retired-commands.js +1 -1
  20. package/dist/cli/shared.js +6 -2
  21. package/dist/cli/unknown-flags.js +24 -1
  22. package/dist/cli.js +68 -10
  23. package/dist/commands/agent/agent-dispatch.js +1 -1
  24. package/dist/commands/command/command-execution.js +24 -62
  25. package/dist/commands/feedback-cli.js +0 -1
  26. package/dist/commands/health/accept-rate.js +6 -0
  27. package/dist/commands/health/archive-usage.js +92 -0
  28. package/dist/commands/health/checks.js +83 -74
  29. package/dist/commands/health/config-skew.js +38 -0
  30. package/dist/commands/health/data-dir-usage.js +25 -13
  31. package/dist/commands/health/egress.js +54 -0
  32. package/dist/commands/health/html-report.js +1 -42
  33. package/dist/commands/health/improve-metrics.js +136 -591
  34. package/dist/commands/health/md-report.js +1 -6
  35. package/dist/commands/health/plugin-staleness.js +53 -3
  36. package/dist/commands/health/renderers.js +12 -4
  37. package/dist/commands/health/report-view-model.js +14 -120
  38. package/dist/commands/health/types-improve.js +4 -19
  39. package/dist/commands/health/windows.js +64 -74
  40. package/dist/commands/health.js +145 -143
  41. package/dist/commands/improve/consolidate/chunking.js +26 -117
  42. package/dist/commands/improve/consolidate/continuity-check.js +137 -0
  43. package/dist/commands/improve/consolidate/pair-pass.js +791 -0
  44. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  45. package/dist/commands/improve/consolidate.js +589 -1127
  46. package/dist/commands/improve/content-hash.js +16 -24
  47. package/dist/commands/improve/distill/content-repair.js +18 -100
  48. package/dist/commands/improve/distill-guards.js +20 -81
  49. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  50. package/dist/commands/improve/distill.js +608 -1041
  51. package/dist/commands/improve/eligibility.js +126 -390
  52. package/dist/commands/improve/execution.js +8 -10
  53. package/dist/commands/improve/extract-prompt.js +1 -2
  54. package/dist/commands/improve/extract.js +487 -1046
  55. package/dist/commands/improve/feedback-valence.js +0 -25
  56. package/dist/commands/improve/improve-cli.js +75 -169
  57. package/dist/commands/improve/improve-result-file.js +10 -66
  58. package/dist/commands/improve/improve-strategies.js +52 -4
  59. package/dist/commands/improve/improve-usage-report.js +18 -64
  60. package/dist/commands/improve/improve.js +480 -1074
  61. package/dist/commands/improve/ledger.js +119 -0
  62. package/dist/commands/improve/locks.js +2 -8
  63. package/dist/commands/improve/loop-stages.js +415 -1073
  64. package/dist/commands/improve/memory/derived-ref.js +12 -77
  65. package/dist/commands/improve/memory/memory-belief.js +16 -118
  66. package/dist/commands/improve/memory/memory-improve.js +266 -14
  67. package/dist/commands/improve/outcome-loop.js +28 -156
  68. package/dist/commands/improve/planner.js +5 -15
  69. package/dist/commands/improve/preparation.js +779 -2319
  70. package/dist/commands/improve/proactive-maintenance.js +34 -101
  71. package/dist/commands/improve/reflect-noise.js +104 -280
  72. package/dist/commands/improve/reflect.js +642 -1353
  73. package/dist/commands/improve/retrieval-gate.js +127 -0
  74. package/dist/commands/improve/retrieval-scope.js +92 -0
  75. package/dist/commands/improve/salience.js +41 -240
  76. package/dist/commands/improve/session-asset.js +19 -100
  77. package/dist/commands/improve/stage.js +322 -0
  78. package/dist/commands/lint/base-linter.js +37 -15
  79. package/dist/commands/proposal/drain.js +261 -578
  80. package/dist/commands/proposal/proposal-cli.js +19 -20
  81. package/dist/commands/proposal/proposal-types.js +31 -24
  82. package/dist/commands/proposal/proposal.js +38 -8
  83. package/dist/commands/proposal/propose.js +134 -160
  84. package/dist/commands/proposal/repository.js +1097 -1394
  85. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  86. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  87. package/dist/commands/proposal/validators/proposals.js +22 -89
  88. package/dist/commands/read/curate.js +105 -462
  89. package/dist/commands/read/knowledge.js +3 -2
  90. package/dist/commands/read/search-cli.js +16 -33
  91. package/dist/commands/read/search.js +17 -23
  92. package/dist/commands/read/show.js +57 -108
  93. package/dist/commands/sources/bundle-cli.js +25 -2
  94. package/dist/commands/sources/bundle-config-ops.js +4 -0
  95. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  96. package/dist/commands/sources/info.js +127 -29
  97. package/dist/commands/sources/installed-stashes.js +197 -746
  98. package/dist/commands/sources/schema-repair.js +98 -129
  99. package/dist/commands/sources/source-add.js +62 -12
  100. package/dist/commands/sources/source-manage.js +9 -2
  101. package/dist/commands/sources/stash-cli.js +24 -4
  102. package/dist/commands/tasks/explain.js +10 -13
  103. package/dist/commands/tasks/tasks-cli.js +12 -13
  104. package/dist/commands/tasks/tasks.js +350 -936
  105. package/dist/commands/tasks/validate.js +26 -24
  106. package/dist/commands/workflow/plan.js +22 -29
  107. package/dist/commands/workflow-cli.js +4 -4
  108. package/dist/core/adapter/adapters/akm-adapter.js +2 -1
  109. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  110. package/dist/core/adapter/adapters/akm-metadata.js +42 -12
  111. package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
  112. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  113. package/dist/core/adapter/execution-source.js +17 -29
  114. package/dist/core/asset/asset-placement.js +4 -13
  115. package/dist/core/asset/frontmatter.js +106 -1
  116. package/dist/core/asset/resolve-ref.js +1 -1
  117. package/dist/core/bundle-id.js +42 -5
  118. package/dist/core/bundle-rename.js +285 -0
  119. package/dist/core/config/config-io.js +1 -2
  120. package/dist/core/config/config-schema.js +9 -34
  121. package/dist/core/config/config-walker.js +1 -1
  122. package/dist/core/config/config.js +184 -111
  123. package/dist/core/config/engine-semantics.js +0 -2
  124. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  125. package/dist/core/config/schema/embedding.js +20 -5
  126. package/dist/core/config/schema/engines.js +5 -0
  127. package/dist/core/config/schema/execution.js +1 -1
  128. package/dist/core/config/schema/experimental.js +1 -1
  129. package/dist/core/config/schema/improve-processes.js +54 -125
  130. package/dist/core/config/schema/improve.js +4 -42
  131. package/dist/core/config/schema/index-config.js +9 -48
  132. package/dist/core/config/schema/scheduler.js +12 -12
  133. package/dist/core/config/schema/search.js +6 -22
  134. package/dist/core/env-secret-ref.js +0 -1
  135. package/dist/core/errors.js +8 -9
  136. package/dist/core/file-change.js +13 -5
  137. package/dist/core/file-lock.js +76 -173
  138. package/dist/core/improve-result.js +35 -7
  139. package/dist/core/improve-types.js +0 -1
  140. package/dist/core/logs-db.js +2 -2
  141. package/dist/core/loopback.js +7 -12
  142. package/dist/core/non-task-input.js +20 -0
  143. package/dist/core/parse.js +13 -16
  144. package/dist/core/paths.js +0 -24
  145. package/dist/core/redaction.js +109 -2
  146. package/dist/core/run-lock.js +2 -5
  147. package/dist/core/spawn-env.js +1 -1
  148. package/dist/core/state/migrations.js +123 -61
  149. package/dist/core/state-db-scope.js +2 -4
  150. package/dist/core/state-db.js +126 -692
  151. package/dist/core/time.js +0 -20
  152. package/dist/core/type-presentation.js +1 -9
  153. package/dist/core/write-source.js +294 -1005
  154. package/dist/execution/input-contract.js +1 -1
  155. package/dist/execution/resolved-request.js +135 -689
  156. package/dist/execution/source.js +63 -257
  157. package/dist/execution/target-ref.js +1 -1
  158. package/dist/indexer/bundle-identity-guard.js +2 -2
  159. package/dist/indexer/db/llm-cache.js +2 -2
  160. package/dist/indexer/ensure-index.js +77 -73
  161. package/dist/indexer/index-rebuild-lock.js +3 -11
  162. package/dist/indexer/index-writer-lock.js +8 -17
  163. package/dist/indexer/index-written-assets.js +141 -154
  164. package/dist/indexer/indexer.js +400 -1124
  165. package/dist/indexer/links/declared-links.js +90 -0
  166. package/dist/indexer/materialize-embeddings.js +60 -397
  167. package/dist/indexer/passes/memory-inference.js +96 -90
  168. package/dist/indexer/passes/metadata.js +132 -219
  169. package/dist/indexer/read-preflight.js +0 -7
  170. package/dist/indexer/scan/doc-to-entry.js +2 -3
  171. package/dist/indexer/scan/drain-dir.js +1 -1
  172. package/dist/indexer/search/db-search.js +190 -590
  173. package/dist/indexer/search/fts-query.js +30 -41
  174. package/dist/indexer/search/ranking.js +28 -154
  175. package/dist/indexer/search/search-attribution.js +12 -32
  176. package/dist/indexer/search/search-fields.js +11 -15
  177. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  178. package/dist/indexer/search/search-source.js +1 -4
  179. package/dist/indexer/usage/usage-events.js +36 -7
  180. package/dist/indexer/walk/walker.js +3 -4
  181. package/dist/integrations/agent/engine-fallback.js +23 -40
  182. package/dist/integrations/agent/engine-resolution.js +93 -183
  183. package/dist/integrations/agent/execution.js +507 -0
  184. package/dist/integrations/agent/model-map.js +28 -156
  185. package/dist/integrations/agent/request-lowering.js +66 -141
  186. package/dist/integrations/agent/runner-dispatch.js +143 -321
  187. package/dist/integrations/agent/runner.js +54 -14
  188. package/dist/integrations/lockfile.js +53 -101
  189. package/dist/llm/client.js +18 -6
  190. package/dist/llm/embedders/deterministic.js +2 -3
  191. package/dist/llm/embedders/profile.js +71 -0
  192. package/dist/llm/embedders/remote.js +11 -17
  193. package/dist/llm/feature-gate.js +0 -8
  194. package/dist/llm/index-passes.js +3 -5
  195. package/dist/llm/memory-infer.js +1 -2
  196. package/dist/llm/structured-call.js +5 -24
  197. package/dist/output/generic-render.js +23 -11
  198. package/dist/output/html-render.js +13 -10
  199. package/dist/output/render-registry.js +3 -32
  200. package/dist/output/shapes/helpers.js +25 -38
  201. package/dist/output/shapes/passthrough.js +1 -9
  202. package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
  203. package/dist/output/text/command-format.js +69 -31
  204. package/dist/output/text/helpers.js +1 -1
  205. package/dist/output/text/migrate.js +5 -14
  206. package/dist/output/text/proposal-format.js +48 -3
  207. package/dist/output/text/show-format.js +13 -17
  208. package/dist/output/text/workflow-format.js +0 -32
  209. package/dist/output/text.js +2 -0
  210. package/dist/registry/factory.js +4 -19
  211. package/dist/registry/network.js +66 -220
  212. package/dist/registry/providers/index.js +0 -2
  213. package/dist/registry/providers/skills-sh.js +3 -14
  214. package/dist/registry/providers/static-index.js +24 -26
  215. package/dist/registry/resolve.js +55 -131
  216. package/dist/scripts/akm-migrate-node.js +42948 -92369
  217. package/dist/scripts/akm-migrate.js +42935 -92354
  218. package/dist/setup/registry-stash-loader.js +4 -13
  219. package/dist/setup/semantic-assets.js +3 -44
  220. package/dist/setup/setup.js +1 -1
  221. package/dist/setup/steps/connection.js +5 -6
  222. package/dist/setup/steps/platforms.js +2 -2
  223. package/dist/setup/steps/tasks.js +25 -15
  224. package/dist/sources/provider-factory.js +17 -18
  225. package/dist/sources/providers/filesystem.js +2 -3
  226. package/dist/sources/providers/git-install.js +7 -1
  227. package/dist/sources/providers/git-provider.js +0 -3
  228. package/dist/sources/providers/git-stash.js +83 -21
  229. package/dist/sources/providers/npm.js +2 -4
  230. package/dist/sources/providers/provider-utils.js +5 -10
  231. package/dist/sources/providers/website.js +0 -2
  232. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  233. package/dist/sources/website-url.js +2 -2
  234. package/dist/storage/database.js +9 -35
  235. package/dist/storage/repositories/improve-ledger-repository.js +209 -0
  236. package/dist/storage/repositories/index-connection.js +39 -72
  237. package/dist/storage/repositories/index-entries-repository.js +131 -129
  238. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  239. package/dist/storage/repositories/index-entry-schema.js +101 -268
  240. package/dist/storage/repositories/index-fts-repository.js +86 -256
  241. package/dist/storage/repositories/index-links-repository.js +143 -0
  242. package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
  243. package/dist/storage/repositories/index-meta-repository.js +6 -4
  244. package/dist/storage/repositories/index-schema.js +257 -325
  245. package/dist/storage/repositories/index-utility-repository.js +8 -29
  246. package/dist/storage/repositories/index-vec-repository.js +133 -414
  247. package/dist/storage/repositories/outcome-repository.js +2 -1
  248. package/dist/storage/repositories/proposals-repository.js +104 -1
  249. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  250. package/dist/storage/repositories/salience-repository.js +1 -19
  251. package/dist/storage/repositories/task-history-repository.js +26 -4
  252. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  253. package/dist/storage/sqlite-migrations.js +136 -0
  254. package/dist/storage/sqlite-pragmas.js +11 -9
  255. package/dist/storage/sqlite-transaction.js +170 -0
  256. package/dist/storage/state-db-integrity.js +130 -0
  257. package/dist/tasks/activation-config.js +134 -62
  258. package/dist/tasks/backends/cron.js +191 -302
  259. package/dist/tasks/backends/exec-utils.js +2 -5
  260. package/dist/tasks/backends/launchd.js +141 -748
  261. package/dist/tasks/backends/schtasks.js +119 -623
  262. package/dist/tasks/prepare/prepare-support.js +5 -15
  263. package/dist/tasks/prepare/prepare.js +0 -2
  264. package/dist/tasks/resolve-akm-bin.js +20 -79
  265. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  266. package/dist/tasks/run/load-task.js +1 -1
  267. package/dist/tasks/scheduler-binding.js +20 -238
  268. package/dist/tasks/scheduler-invocation.js +136 -244
  269. package/dist/tasks/scheduler-lock.js +53 -0
  270. package/dist/tasks/scheduler-sync.js +368 -679
  271. package/dist/tasks/source/parse-task-source.js +55 -9
  272. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  273. package/dist/tasks/source/task-to-v4.js +464 -88
  274. package/dist/workflows/authoring/authoring.js +3 -12
  275. package/dist/workflows/compile.js +211 -0
  276. package/dist/workflows/concurrency-policy.js +13 -74
  277. package/dist/workflows/exec/child-invocation.js +3 -17
  278. package/dist/workflows/exec/child-workflow.js +32 -141
  279. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  280. package/dist/workflows/exec/environment.js +98 -0
  281. package/dist/workflows/exec/exec-unit.js +33 -140
  282. package/dist/workflows/exec/frozen-judge.js +7 -59
  283. package/dist/workflows/exec/native-executor.js +82 -341
  284. package/dist/workflows/exec/param-secrets.js +29 -47
  285. package/dist/workflows/exec/run-workflow.js +154 -387
  286. package/dist/workflows/exec/scheduler.js +9 -36
  287. package/dist/workflows/exec/step-work.js +127 -430
  288. package/dist/workflows/exec/unit-dispatch.js +11 -63
  289. package/dist/workflows/exec/unit-writer.js +8 -52
  290. package/dist/workflows/exec/worktree.js +39 -273
  291. package/dist/workflows/freeze/child-output-references.js +4 -15
  292. package/dist/workflows/freeze/environment.js +99 -92
  293. package/dist/workflows/freeze/freeze.js +172 -0
  294. package/dist/workflows/freeze/step-values.js +19 -21
  295. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  296. package/dist/workflows/freeze/targets/command.js +10 -33
  297. package/dist/workflows/freeze/targets/script.js +5 -12
  298. package/dist/workflows/freeze/targets/shell.js +3 -6
  299. package/dist/workflows/freeze/targets/task.js +25 -80
  300. package/dist/workflows/freeze/task-bindings.js +20 -67
  301. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  302. package/dist/workflows/ir/params.js +6 -51
  303. package/dist/workflows/ir/plan-hash.js +2 -34
  304. package/dist/workflows/parser.js +140 -43
  305. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  306. package/dist/workflows/renderer.js +36 -69
  307. package/dist/workflows/resource-limits.js +12 -120
  308. package/dist/workflows/runtime/agent-identity.js +8 -40
  309. package/dist/workflows/runtime/run-outputs.js +3 -6
  310. package/dist/workflows/runtime/run-plan.js +316 -0
  311. package/dist/workflows/runtime/runs.js +48 -200
  312. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  313. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  314. package/dist/workflows/validate-summary.js +2 -7
  315. package/docs/integration/bundling-akm.md +49 -42
  316. package/docs/migration/README.md +1 -0
  317. package/docs/migration/release-notes/0.9.17.md +43 -0
  318. package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
  319. package/docs/reference/cli.md +232 -135
  320. package/docs/reference/configuration.md +71 -57
  321. package/docs/reference/data-and-telemetry.md +20 -21
  322. package/docs/reference/tasks.md +105 -39
  323. package/docs/reference/workflow-schema.md +14 -18
  324. package/docs/reference/workflows.md +6 -9
  325. package/package.json +1 -1
  326. package/schemas/akm-config.json +115 -738
  327. package/schemas/akm-workflow.json +1 -0
  328. package/dist/assets/improve-strategies/graph-refresh.json +0 -15
  329. package/dist/assets/prompts/contradiction-judge.md +0 -33
  330. package/dist/assets/prompts/graph-extract-system.md +0 -1
  331. package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
  332. package/dist/assets/prompts/metadata-enhance-system.md +0 -1
  333. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
  334. package/dist/commands/health/advisories.js +0 -150
  335. package/dist/commands/health/metrics.js +0 -329
  336. package/dist/commands/health/surfaces.js +0 -102
  337. package/dist/commands/improve/anti-collapse.js +0 -83
  338. package/dist/commands/improve/collapse-detector.js +0 -432
  339. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  340. package/dist/commands/improve/consolidate/merge.js +0 -149
  341. package/dist/commands/improve/distill/promote-memory.js +0 -291
  342. package/dist/commands/improve/distill/quality-gate.js +0 -337
  343. package/dist/commands/improve/eval-cases.js +0 -52
  344. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  345. package/dist/commands/improve/proposal-envelope.js +0 -31
  346. package/dist/commands/improve/run-context.js +0 -123
  347. package/dist/commands/improve/shared.js +0 -31
  348. package/dist/commands/improve/source-identity.js +0 -28
  349. package/dist/commands/improve/triage.js +0 -96
  350. package/dist/commands/proposal/drain-policies.js +0 -151
  351. package/dist/commands/sources/update-transaction.js +0 -220
  352. package/dist/core/action-contributors.js +0 -28
  353. package/dist/core/config/config-version-shim.js +0 -101
  354. package/dist/core/fs-txn.js +0 -405
  355. package/dist/core/lexical-score.js +0 -25
  356. package/dist/core/maintenance-barrier.js +0 -167
  357. package/dist/execution/executable-identity.js +0 -105
  358. package/dist/execution/guarded-source.js +0 -427
  359. package/dist/indexer/db/graph-db.js +0 -444
  360. package/dist/indexer/graph/graph-boost.js +0 -427
  361. package/dist/indexer/graph/graph-dedup.js +0 -95
  362. package/dist/indexer/graph/graph-extraction.js +0 -1108
  363. package/dist/indexer/search/name-match.js +0 -35
  364. package/dist/indexer/search/ranking-contributors.js +0 -515
  365. package/dist/indexer/search/ranking-types.js +0 -4
  366. package/dist/indexer/walk/project-context.js +0 -192
  367. package/dist/integrations/agent/execution-cascade.js +0 -566
  368. package/dist/integrations/agent/execution-definitions.js +0 -202
  369. package/dist/integrations/agent/execution-lowering.js +0 -841
  370. package/dist/integrations/agent/execution-preparation.js +0 -98
  371. package/dist/integrations/agent/inline-execution.js +0 -74
  372. package/dist/llm/graph-extract.js +0 -728
  373. package/dist/llm/metadata-enhance.js +0 -96
  374. package/dist/registry/create-provider-registry.js +0 -29
  375. package/dist/registry/pinned-request-helper.js +0 -247
  376. package/dist/registry/pinned-transport.js +0 -717
  377. package/dist/sources/providers/index.js +0 -14
  378. package/dist/storage/engines/sqlite-migrations.js +0 -271
  379. package/dist/storage/repositories/canaries-repository.js +0 -107
  380. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  381. package/dist/storage/repositories/registry-cache.js +0 -113
  382. package/dist/tasks/scheduler-sync-preview.js +0 -52
  383. package/dist/tasks/source/task-to-v3.js +0 -507
  384. package/dist/workflows/freeze/resolve-steps.js +0 -86
  385. package/dist/workflows/freeze/source-freeze.js +0 -64
  386. package/dist/workflows/ir/compile.js +0 -321
  387. package/dist/workflows/ir/environment-v4.js +0 -330
  388. package/dist/workflows/ir/freeze-v4.js +0 -153
  389. package/dist/workflows/ir/schema-v4.js +0 -745
  390. package/dist/workflows/ir/schema.js +0 -354
  391. package/dist/workflows/program/schema.js +0 -77
  392. package/dist/workflows/runtime/checkin.js +0 -57
  393. package/dist/workflows/runtime/plan-classifier.js +0 -196
  394. package/dist/workflows/runtime/unit-checkin.js +0 -45
  395. package/dist/workflows/runtime/unit-phases.js +0 -20
  396. package/dist/workflows/schema.js +0 -4
  397. package/dist/workflows/source-ir/compile.js +0 -200
  398. package/dist/workflows/source-ir/program.js +0 -50
  399. package/dist/workflows/source-ir/result.js +0 -26
  400. package/dist/workflows/source-ir/schema.js +0 -786
  401. package/dist/workflows/source-ir/triggers.js +0 -79
  402. package/dist/workflows/source-ir/uses.js +0 -40
  403. package/dist/workflows/validator.js +0 -60
@@ -11,13 +11,13 @@ const CONFIG_HINTS = {
11
11
  STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update the default bundle path.",
12
12
  DATA_DIR_UNREADABLE: "The data directory is not readable by the user running akm. Check its owner and mode, or point AKM_DATA_DIR / XDG_DATA_HOME somewhere this user owns.",
13
13
  INDEX_SCHEMA_INCOMPATIBLE: "Run `akm index --full` to rebuild the derived index from the currently materialized sources.",
14
- EMBEDDING_NOT_CONFIGURED: 'Run `akm config set embedding \'{"endpoint":"...","model":"..."}\'` to enable embeddings.',
15
14
  LLM_NOT_CONFIGURED: 'Run `akm setup` or configure an `engines` entry with `kind: "llm"`, then select it with `defaults.llmEngine`.',
16
15
  TEST_ISOLATION_MISSING: "Under bun test, when AKM_BUNDLE_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
17
16
  UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The bundle directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
18
17
  UNKNOWN_IMPROVE_STRATEGY: "Pass one of the listed strategy names to `--strategy`, or define it under `improve.strategies`. Names are case-sensitive.",
19
18
  EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry.",
20
19
  SECRET_REFERENCE_UNRESOLVED: "Check the secret exists (`akm secret list`) and the name after `secret://` matches, or run `akm secret set <name> <value>` to store it.",
20
+ REGISTRY_URL_INVALID: "Registry URLs must be credential-free http(s) URLs. Fix the entry with `akm registry list` / `akm registry add`, or the AKM_REGISTRY_URL / AKM_NPM_REGISTRY variable that supplied it.",
21
21
  };
22
22
  // Code-review finding: COMPOSITION_INVALID covers several unrelated causes
23
23
  // (a rejected with:, a multi-job source, a composition cycle/depth/size
@@ -56,7 +56,7 @@ const USAGE_HINTS = {
56
56
  //
57
57
  // Code-review finding: this default is reached ONLY by with:-rejection
58
58
  // throw sites (the ones above, plus task.ts's noDeclaredInputsError and
59
- // resolve-steps.ts's rejectNonTaskBindingWith) — every other
59
+ // freeze.ts's resolveStep) — every other
60
60
  // COMPOSITION_INVALID throw site (multi-job source, composition
61
61
  // cycle/depth/size, invalid child-output reference, an env: on a
62
62
  // composing step) passes its own explicit constructor hint instead of
@@ -72,19 +72,17 @@ const USAGE_HINTS = {
72
72
  WORKFLOW_SOURCE_INVALID: "Run `akm lint` to see the failing source location, or `akm workflow plan <ref>` to compile it without writing.",
73
73
  INPUT_BINDING_INVALID: "Check the step's with: keys against the target's declared inputs.",
74
74
  TASK_TARGET_UNSUPPORTED: "Task definitions support command, script, workflow, and shell (run:) targets; akm/command is layered by callers.",
75
- // P3a (docs/plans/specs/p3a-plan-v5-child-freeze.md §3.2, A-N2): the
76
- // complete-or-abandon policy for a stored pre-irVersion-5 run.
77
- WORKFLOW_IR_VERSION_UNSUPPORTED: "Abandon the run with `akm workflow abandon <id>`, then start it again from the workflow source — a frozen plan this akm cannot execute is not re-executable in place.",
78
- // P3b (docs/plans/specs/p3b-child-executor.md §4.3).
79
- WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes.",
80
75
  };
81
76
  /** Default hint for each TransientErrorCode. */
82
77
  const TRANSIENT_HINTS = {
83
- RUN_LEASE_HELD: "Wait for the named engine invocation to finish or for the lease to expire, then retry. `akm workflow status <id>` shows the current lease.",
78
+ RUN_LEASE_HELD: "Wait for the akm process driving this run (the named pid) to finish, then retry.",
84
79
  STATE_DB_CONTENDED: "Another akm process is writing state.db right now. Wait a few seconds and retry; commands that support --skip-if-locked can skip instead of failing.",
85
80
  INDEX_DB_CONTENDED: "Another akm process is writing index.db; retry shortly, or pass --skip-if-locked on scheduled runs.",
86
- MAINTENANCE_BARRIER_BUSY: "Another akm process is registering a lock or lease right now. Retry shortly, or pass --skip-if-locked on scheduled index/improve/workflow runs.",
87
81
  IMPROVE_LOCK_HELD: "Another akm improve run holds the whole-run lock right now. Wait for it to finish and retry, or pass --skip-if-locked on scheduled runs.",
82
+ LOCKFILE_CONTENDED: "Another akm process is updating its bundle lockfile right now. Wait a few seconds and retry.",
83
+ ASSET_MUTATION_LEASE_HELD: "Another akm process is writing bundle content right now. Wait for it to finish and retry.",
84
+ SCHEDULER_LOCK_HELD: "Another `akm task sync`, `add`, `enable`, `disable` or `prune` is writing the scheduler right now. Wait for it to finish and retry.",
85
+ REGISTRY_UNREACHABLE: "The registry did not answer in time. Check the network and the registry URL (`akm registry list`), then retry.",
88
86
  };
89
87
  /** Default hint for each NotFoundError code. */
90
88
  const NOT_FOUND_HINTS = {
@@ -97,6 +95,7 @@ const NOT_FOUND_HINTS = {
97
95
  PROPOSAL_NOT_FOUND: "Run `akm proposal list` to see pending proposals and their ids.",
98
96
  FILE_NOT_FOUND: "Check the path exists and is readable.",
99
97
  IMPROVE_RUN_NOT_FOUND: "Run `akm improve` first, or `akm improve report --since 30d` to see recent run ids in `runIds`.",
98
+ REGISTRY_NOT_FOUND: "Check the ref's spelling and version; `akm search <query> --from registry` lists installable refs.",
100
99
  };
101
100
  /**
102
101
  * Base class for all akm-thrown, classified errors. Carries the `kind`
@@ -4,13 +4,21 @@
4
4
  /**
5
5
  * The content of a proposal's PRIMARY change (WI-6.2 envelope read path).
6
6
  *
7
- * By construction `changes[0].after === payload.content`; consumers read
8
- * through this accessor so the single-content assumption lives in ONE place
9
- * once multi-file proposals (consolidate ops) ride the envelope. Typed
10
- * structurally (not against `Proposal`) so this module stays dependency-free.
7
+ * By construction `changes[0].after === payload.content` for a `create` or
8
+ * `update` change; consumers read through this accessor so the
9
+ * single-content assumption lives in ONE place. A `delete` primary change (a
10
+ * consolidate retire proposal, alpha.9) writes no content by definition, so
11
+ * it reads as `""` here rather than throwing — every generic proposal scan
12
+ * (dedup-by-body-hash, the triage drain's diff-size filter, the quality
13
+ * validators) can call this on ANY pending proposal, retire included,
14
+ * without special-casing the op first. Typed structurally (not against
15
+ * `Proposal`) so this module stays dependency-free.
11
16
  */
12
17
  export function proposalContent(p) {
13
- const content = p.changes[0]?.after;
18
+ const primary = p.changes[0];
19
+ if (primary?.op === "delete")
20
+ return "";
21
+ const content = primary?.after;
14
22
  if (content === undefined)
15
23
  throw new Error("Proposal primary change has no content.");
16
24
  return content;
@@ -1,11 +1,20 @@
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
+ /**
5
+ * PID-stamped exclusive lock files.
6
+ *
7
+ * A lock is one file created with `O_EXCL` (`wx`), which the filesystem
8
+ * makes atomic: exactly one creator wins, so no further mutex or barrier is
9
+ * needed around acquisition. The payload records the holder's PID (and the
10
+ * launcher PID under a scheduler) so a probe can tell a live holder from a
11
+ * dead one; only a verifiably dead holder — or, when the caller opts in via
12
+ * `staleAfterMs`, an over-age one — is ever reclaimed. Reclaim moves the
13
+ * stale file aside, re-verifies it is the very file that was probed, and only
14
+ * then unlinks it, so two reclaimers cannot both "win" the same stale lock.
15
+ */
4
16
  import { randomUUID } from "node:crypto";
5
17
  import fs from "node:fs";
6
- import path from "node:path";
7
- import { sleepSync } from "../runtime.js";
8
- import { openDatabase } from "../storage/database.js";
9
18
  import { isProcessAlive, MAX_LOCK_METADATA_BYTES, readTextFileDescriptorWithLimit } from "./common.js";
10
19
  function readLockSnapshot(lockPath) {
11
20
  let fd;
@@ -32,51 +41,16 @@ function readLockSnapshot(lockPath) {
32
41
  function sameIdentity(left, right) {
33
42
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
34
43
  }
35
- function operationMutexPath(lockPath) {
36
- // `.sensitive` is an established non-asset suffix across stash walkers. The
37
- // mutex may sit beside a secret/env lock and must never surface as an asset.
38
- return path.join(path.dirname(lockPath), `.${path.basename(lockPath)}.operations.sensitive`);
39
- }
40
- /**
41
- * Serialize every mutation of one canonical lock path. SQLite's write lock is
42
- * released by the OS when a process dies, so this mutex needs no stale-owner
43
- * deletion protocol (which would reproduce the same check/rename race it is
44
- * meant to prevent).
45
- */
46
- function withLockOperationMutex(lockPath, run) {
47
- const db = openDatabase(operationMutexPath(lockPath));
48
- let began = false;
44
+ function releaseLockRaw(lockPath) {
49
45
  try {
50
- db.exec("PRAGMA busy_timeout = 30000");
51
- for (let attempt = 0; attempt < 5 && !began; attempt += 1) {
52
- db.exec("BEGIN IMMEDIATE");
53
- began = db.inTransaction;
54
- if (!began)
55
- sleepSync(2 ** attempt);
56
- }
57
- if (!began)
58
- throw new Error(`Could not acquire lock operation mutex for ${lockPath}.`);
59
- const result = run();
60
- db.exec("COMMIT");
61
- began = false;
62
- return result;
63
- }
64
- catch (error) {
65
- if (began && db.inTransaction) {
66
- try {
67
- db.exec("ROLLBACK");
68
- }
69
- catch {
70
- // Preserve the operation failure.
71
- }
72
- }
73
- throw error;
46
+ fs.unlinkSync(lockPath);
74
47
  }
75
- finally {
76
- db.close();
48
+ catch {
49
+ // Already gone.
77
50
  }
78
51
  }
79
- function tryAcquireLockRaw(lockPath, payload) {
52
+ /** Create the lock file atomically; `undefined` when another holder already has it. */
53
+ export function tryAcquireLockSync(lockPath, payload) {
80
54
  try {
81
55
  fs.writeFileSync(lockPath, payload, { flag: "wx" });
82
56
  }
@@ -99,35 +73,6 @@ function tryAcquireLockRaw(lockPath, payload) {
99
73
  }
100
74
  return { lockPath, ...snapshot };
101
75
  }
102
- function releaseLockRaw(lockPath) {
103
- try {
104
- fs.unlinkSync(lockPath);
105
- }
106
- catch {
107
- // Sentinel already gone — fine.
108
- }
109
- }
110
- /**
111
- * Atomically create a sentinel at `lockPath` with `payload` as the body.
112
- * Returns an exact ownership handle if we now own the lock, or undefined if a sentinel already
113
- * exists (EEXIST). Throws any other error (permissions, missing parent
114
- * dir, etc.) — callers must ensure the parent directory exists.
115
- *
116
- * `payload` is typically `String(process.pid)` for the simple cases or
117
- * a small JSON envelope for callers that want richer metadata
118
- * (improve.ts records pid + startedAt so audit can correlate runs).
119
- */
120
- export function tryAcquireLockSync(lockPath, payload) {
121
- return withLockOperationMutex(lockPath, () => tryAcquireLockRaw(lockPath, payload));
122
- }
123
- /**
124
- * Best-effort launcher pid from `AKM_LAUNCHER_PID` (set by
125
- * `scripts/node-runtime/akm`/`akm-migrate`, #956) — undefined when unset,
126
- * empty, or not a positive integer (never trust an ambient env var blindly
127
- * into a lock message). Also the gate the parent-death watchdog
128
- * (`core/parent-watchdog.ts`) uses to stay inert outside a launcher-managed
129
- * run.
130
- */
131
76
  export function launcherPidFromEnv() {
132
77
  const raw = process.env.AKM_LAUNCHER_PID;
133
78
  if (!raw)
@@ -135,13 +80,6 @@ export function launcherPidFromEnv() {
135
80
  const pid = Number.parseInt(raw, 10);
136
81
  return Number.isInteger(pid) && pid > 0 ? pid : undefined;
137
82
  }
138
- /**
139
- * Build a PID-bearing payload with a unique token for one acquisition attempt.
140
- * Adds `launcherPid` (#956) whenever this process is running under the
141
- * published launcher, so a lock's holder can be identified by the pid every
142
- * process listing and task log actually shows (the launcher's) as well as
143
- * the pid that holds the lock (the bun/node child).
144
- */
145
83
  export function createLockPayload(metadata = {}) {
146
84
  const launcherPid = launcherPidFromEnv();
147
85
  return JSON.stringify({
@@ -151,26 +89,12 @@ export function createLockPayload(metadata = {}) {
151
89
  lockId: randomUUID(),
152
90
  });
153
91
  }
154
- /**
155
- * Inspect an existing sentinel at `lockPath` without modifying it.
156
- * Returns:
157
- * - `absent` if the file does not exist.
158
- * - `stale` if the file is present but should be reclaimed (the holding
159
- * PID is dead, the content is unparseable, or the lock has exceeded
160
- * `staleAfterMs`). Includes the failure reason so callers can log it.
161
- * - `held` if the lock has a live holder and is not yet age-expired.
162
- *
163
- * Does NOT remove the file. Callers decide recovery policy.
164
- */
165
92
  export function probeLock(lockPath, opts) {
166
93
  let snapshot;
167
94
  try {
168
95
  snapshot = readLockSnapshot(lockPath);
169
96
  }
170
97
  catch (error) {
171
- // A permission error means the lock may be genuinely HELD by someone we
172
- // cannot see. Reporting it as stale would invite a caller to steal a live
173
- // lease (#791) — `unreadable` stays for the corrupt/undecodable case.
174
98
  const code = error?.code;
175
99
  if (code === "EACCES" || code === "EPERM")
176
100
  return { state: "inaccessible", code };
@@ -193,102 +117,81 @@ export function probeLock(lockPath, opts) {
193
117
  return { state: "held", holderPid, launcherPid, ageMs, rawContent, identity };
194
118
  }
195
119
  /**
196
- * Revalidate and quarantine the probed sentinel while holding the same operation
197
- * mutex used by acquisitions. A newer owner therefore cannot be renamed in the
198
- * check/quarantine window, and a third contender cannot acquire until cleanup
199
- * has completed.
120
+ * Remove a lock that `probeLock` reported stale. Returns `false` when the file
121
+ * changed since the probe (someone else reclaimed or re-acquired it) so the
122
+ * caller re-probes instead of assuming the path is free.
200
123
  */
201
124
  export function reclaimStaleLock(lockPath, probe, options) {
202
125
  if (probe.rawContent === undefined || probe.identity === undefined)
203
126
  return false;
204
127
  const expectedContent = probe.rawContent;
205
128
  const expectedIdentity = probe.identity;
206
- return withLockOperationMutex(lockPath, () => {
207
- let current;
208
- try {
209
- current = readLockSnapshot(lockPath);
210
- }
211
- catch {
212
- return false;
213
- }
214
- if (!current || current.rawContent !== expectedContent || !sameIdentity(current.identity, expectedIdentity)) {
129
+ let current;
130
+ try {
131
+ current = readLockSnapshot(lockPath);
132
+ }
133
+ catch {
134
+ return false;
135
+ }
136
+ if (!current || current.rawContent !== expectedContent || !sameIdentity(current.identity, expectedIdentity)) {
137
+ return false;
138
+ }
139
+ const quarantinePath = `${lockPath}.stale-${process.pid}-${randomUUID()}`;
140
+ try {
141
+ fs.renameSync(lockPath, quarantinePath);
142
+ }
143
+ catch (err) {
144
+ if (err.code === "ENOENT")
215
145
  return false;
216
- }
217
- const quarantinePath = `${lockPath}.stale-${process.pid}-${randomUUID()}`;
146
+ throw err;
147
+ }
148
+ let quarantined;
149
+ try {
150
+ quarantined = readLockSnapshot(quarantinePath);
151
+ }
152
+ catch {
153
+ quarantined = undefined;
154
+ }
155
+ if (!quarantined ||
156
+ quarantined.rawContent !== expectedContent ||
157
+ !sameIdentity(quarantined.identity, expectedIdentity)) {
158
+ // The file we moved aside is not the one we probed: a fresh holder took
159
+ // the path in between. Put it back and report no reclaim.
218
160
  try {
219
- fs.renameSync(lockPath, quarantinePath);
161
+ fs.linkSync(quarantinePath, lockPath);
220
162
  }
221
163
  catch (err) {
222
- if (err.code === "ENOENT")
223
- return false;
224
- throw err;
164
+ if (err.code !== "EEXIST")
165
+ throw err;
225
166
  }
226
- let quarantined;
227
- try {
228
- quarantined = readLockSnapshot(quarantinePath);
229
- }
230
- catch {
231
- quarantined = undefined;
232
- }
233
- if (!quarantined ||
234
- quarantined.rawContent !== expectedContent ||
235
- !sameIdentity(quarantined.identity, expectedIdentity)) {
236
- try {
237
- // Restore without replacing a non-cooperating lock installed after quarantine.
238
- fs.linkSync(quarantinePath, lockPath);
239
- }
240
- catch (err) {
241
- if (err.code !== "EEXIST")
242
- throw err;
243
- }
244
- releaseLockRaw(quarantinePath);
167
+ releaseLockRaw(quarantinePath);
168
+ return false;
169
+ }
170
+ options?.afterQuarantineVerified?.();
171
+ try {
172
+ fs.unlinkSync(quarantinePath);
173
+ return true;
174
+ }
175
+ catch (err) {
176
+ if (err.code === "ENOENT")
245
177
  return false;
246
- }
247
- options?.afterQuarantineVerified?.();
248
- try {
249
- fs.unlinkSync(quarantinePath);
250
- return true;
251
- }
252
- catch (err) {
253
- if (err.code === "ENOENT")
254
- return false;
255
- throw err;
256
- }
257
- });
178
+ throw err;
179
+ }
258
180
  }
259
- /**
260
- * Release only the exact sentinel returned by `tryAcquireLockSync`. Content and
261
- * file identity are revalidated while holding the acquisition operation mutex,
262
- * so a stale holder cannot remove a successor. Synchronous and idempotent so it
263
- * is safe in both `finally` blocks and process exit handlers.
264
- */
181
+ /** Unlink the lock only while it is still the exact file this owner created. */
265
182
  export function releaseLock(ownership) {
266
183
  const { lockPath } = ownership;
267
- if (!fs.existsSync(lockPath) && !fs.existsSync(operationMutexPath(lockPath)))
184
+ let current;
185
+ try {
186
+ current = readLockSnapshot(lockPath);
187
+ }
188
+ catch {
268
189
  return;
269
- withLockOperationMutex(lockPath, () => {
270
- let current;
271
- try {
272
- current = readLockSnapshot(lockPath);
273
- }
274
- catch {
275
- // Absent or unreadable — nothing of ours to release.
276
- return;
277
- }
278
- if (current && current.rawContent === ownership.rawContent && sameIdentity(current.identity, ownership.identity)) {
279
- releaseLockRaw(lockPath);
280
- }
281
- });
190
+ }
191
+ if (current && current.rawContent === ownership.rawContent && sameIdentity(current.identity, ownership.identity)) {
192
+ releaseLockRaw(lockPath);
193
+ }
282
194
  }
283
- /**
284
- * Extract a holder pid, and (#956) a launcher pid when the payload recorded
285
- * one, from a sentinel body. Accepts the two shapes used across the
286
- * codebase: a bare numeric string (config-io, vault, lockfile — never
287
- * carries a `launcherPid`) and a JSON object with `pid`/`launcherPid` fields
288
- * (`createLockPayload`). `holderPid` is undefined when the body is
289
- * unparseable or yields a non-positive integer; `launcherPid` is undefined
290
- * whenever the payload has none, independent of whether `holderPid` parsed.
291
- */
292
195
  function extractLockIdentity(content) {
293
196
  const trimmed = content.trim();
294
197
  if (!trimmed)
@@ -19,6 +19,7 @@ const COMMON_FIELDS = [
19
19
  "plan",
20
20
  "actions",
21
21
  "skippedProcesses",
22
+ "engineProbe",
22
23
  "distillSkipped",
23
24
  "validationFailures",
24
25
  "schemaRepairs",
@@ -27,14 +28,22 @@ const COMMON_FIELDS = [
27
28
  "lintSummary",
28
29
  "memoryIndexHealth",
29
30
  "coverageGaps",
31
+ // R10: no longer written (the write-only eval-cases path was removed),
32
+ // but kept in the allow-list so `decodeImproveResult` still reads
33
+ // improve-result envelopes a prior release wrote with this field —
34
+ // AGENTS.md "Reading persisted data".
30
35
  "evalCasesWritten",
31
36
  "deadUrls",
32
37
  "deadUrlCoverage",
33
38
  "reflectsWithErrorContext",
34
39
  "memoryInference",
40
+ // 0.9.17-alpha.9: no longer written (the LLM entity-graph extraction that
41
+ // wrote these was retired), kept readable for the same reason as
42
+ // `evalCasesWritten` above.
35
43
  "graphExtraction",
36
44
  "memoryInferenceDurationMs",
37
45
  "graphExtractionDurationMs",
46
+ "ensureIndexDurationMs",
38
47
  "orphansPurged",
39
48
  "proposalsExpired",
40
49
  "reflectCooldownActions",
@@ -113,7 +122,7 @@ function validateConsolidationPlan(value) {
113
122
  ]));
114
123
  if (!isRecord(value.configured))
115
124
  fail("plan.consolidation.configured must be an object");
116
- requireExactFields(value.configured, new Set(["enabled", "minPoolSize", "limit", "maxChunkSize", "incrementalSince"]));
125
+ requireExactFields(value.configured, new Set(["enabled", "minPoolSize", "limit", "maxChunkSize"]));
117
126
  if (value.configured.enabled !== undefined && typeof value.configured.enabled !== "boolean") {
118
127
  fail("plan.consolidation.configured.enabled must be a boolean");
119
128
  }
@@ -122,9 +131,6 @@ function validateConsolidationPlan(value) {
122
131
  fail(`plan.consolidation.configured.${field} must be a number`);
123
132
  }
124
133
  }
125
- if (value.configured.incrementalSince !== undefined && typeof value.configured.incrementalSince !== "string") {
126
- fail("plan.consolidation.configured.incrementalSince must be a string");
127
- }
128
134
  if (!isRecord(value.effective))
129
135
  fail("plan.consolidation.effective must be an object");
130
136
  requireExactFields(value.effective, new Set(["enabled", "minPoolSize", "limit", "chunkSize"]));
@@ -194,7 +200,15 @@ function validateProcessRoutingRows(value) {
194
200
  fail("plan.processes entries must be objects");
195
201
  requireExactFields(row, new Set(["process", "enabled", "engine", "model", "engineKind", "notices", "unavailable", "eligibleRefs"]));
196
202
  if (typeof row.process !== "string" ||
197
- !(canonicalNames.includes(row.process) || row.process === "triage.judgment")) {
203
+ !(canonicalNames.includes(row.process) ||
204
+ row.process === "triage.judgment" ||
205
+ // 0.9.17-alpha.9: "graphExtraction" is no longer a process a fresh
206
+ // plan can route (the LLM entity-graph extraction it named was
207
+ // retired), but every pre-alpha.9 run recorded one here — kept
208
+ // readable, same as `stageNames`' "graph-extraction" above and
209
+ // `graphExtraction` in COMMON_FIELDS, so a historical run still
210
+ // decodes for `akm health` instead of failing this row outright.
211
+ row.process === "graphExtraction")) {
198
212
  fail("plan.processes.process is invalid");
199
213
  }
200
214
  if (seen.has(row.process))
@@ -300,6 +314,8 @@ function validateImprovePlan(value, dryRun, plannedRefNames) {
300
314
  fail("plan.limits.totalCeiling must equal plan.limits.effective + plan.limits.additiveReplayAllowance");
301
315
  }
302
316
  const gateNames = new Set(["profile", "cleanup", "validation", "signal", "disk", "limit"]);
317
+ // Plans stored before 0.9.17-alpha.7 (#986) have no retrieval gate.
318
+ const optionalGateNames = new Set(["retrieval"]);
303
319
  if (!Array.isArray(value.gates))
304
320
  fail("plan.gates must be an array");
305
321
  const gateRemovedByName = new Map();
@@ -307,8 +323,9 @@ function validateImprovePlan(value, dryRun, plannedRefNames) {
307
323
  if (!isRecord(gate))
308
324
  fail("plan.gates entries must be objects");
309
325
  requireExactFields(gate, new Set(["name", "removed", "reason"]));
310
- if (typeof gate.name !== "string" || !gateNames.has(gate.name))
326
+ if (typeof gate.name !== "string" || !(gateNames.has(gate.name) || optionalGateNames.has(gate.name))) {
311
327
  fail("plan.gates.name is invalid");
328
+ }
312
329
  requireCount(gate, "removed", "plan.gates entry");
313
330
  if (typeof gate.reason !== "string")
314
331
  fail("plan.gates.reason must be a string");
@@ -376,10 +393,18 @@ function validateImprovePlan(value, dryRun, plannedRefNames) {
376
393
  if (value.limits.totalCeiling !== undefined && value.effectiveRefs.length > value.limits.totalCeiling) {
377
394
  fail("plan.effectiveRefs cannot exceed plan.limits.totalCeiling");
378
395
  }
379
- validateProcessRoutingRows(value.processes);
396
+ // #947 added plan.processes (2026-09-09T09:03:19Z); every run recorded
397
+ // before it legitimately stored `plan` with no `processes` key at all —
398
+ // validate the rows only when present, same as `proactive` below, so a
399
+ // pre-#947 envelope still decodes (AGENTS.md "Reading persisted data").
400
+ if (value.processes !== undefined)
401
+ validateProcessRoutingRows(value.processes);
380
402
  if (value.proactive !== undefined)
381
403
  validateProactivePlan(value.proactive);
382
404
  validateConsolidationPlan(value.consolidation);
405
+ // "graph-extraction" is no longer a stage a fresh plan can name — retired
406
+ // 0.9.17-alpha.9 — but stays here so a historical envelope that captured a
407
+ // dry-run plan before the retirement still decodes.
383
408
  const stageNames = new Set(["consolidation", "extract", "graph-extraction", "memory-inference"]);
384
409
  if (!Array.isArray(value.stages))
385
410
  fail("plan.stages must be an array");
@@ -442,6 +467,7 @@ function validateCommon(value) {
442
467
  for (const field of [
443
468
  "actions",
444
469
  "skippedProcesses",
470
+ "engineProbe",
445
471
  "validationFailures",
446
472
  "schemaRepairs",
447
473
  "extract",
@@ -457,10 +483,12 @@ function validateCommon(value) {
457
483
  }
458
484
  for (const field of [
459
485
  "cyclesRun",
486
+ // R10: retired write, kept readable — see the COMMON_FIELDS comment above.
460
487
  "evalCasesWritten",
461
488
  "reflectsWithErrorContext",
462
489
  "memoryInferenceDurationMs",
463
490
  "graphExtractionDurationMs",
491
+ "ensureIndexDurationMs",
464
492
  "orphansPurged",
465
493
  "proposalsExpired",
466
494
  "reflectCooldownActions",
@@ -32,7 +32,6 @@ export function classifyImproveAction(mode) {
32
32
  case "reflect":
33
33
  case "distill":
34
34
  case "memory-inference":
35
- case "graph-extraction":
36
35
  return "accepted";
37
36
  case "reflect-cooldown":
38
37
  case "reflect-skipped":
@@ -33,13 +33,13 @@
33
33
  * ## Schema evolution
34
34
  *
35
35
  * Same migration-safety contract as state.db: append-only `MIGRATIONS` applied
36
- * through the shared runner in src/storage/engines/sqlite-migrations.ts.
36
+ * through the shared runner in src/storage/sqlite-migrations.ts.
37
37
  *
38
38
  * @module logs-db
39
39
  */
40
40
  import path from "node:path";
41
- import { assertMigrationRegistry, runMigrations as runSqliteMigrations, } from "../storage/engines/sqlite-migrations.js";
42
41
  import { openManagedDatabase } from "../storage/managed-db.js";
42
+ import { assertMigrationRegistry, runMigrations as runSqliteMigrations, } from "../storage/sqlite-migrations.js";
43
43
  import { getDataDir } from "./paths.js";
44
44
  // ── Path helper ──────────────────────────────────────────────────────────────
45
45
  /**
@@ -20,10 +20,11 @@
20
20
  *
21
21
  * The ONE local-vs-remote answer for concurrency defaults — the workflow
22
22
  * engine's frozen engine concurrency (`workflows/concurrency-policy.ts`) and
23
- * the indexer's LLM pool (`indexer/indexer.ts` `getDefaultLlmConcurrency`)
24
- * both classify through here. NOT shared with the website snapshot fetcher's
25
- * SSRF policy (`sources/snapshot-fetchers/host-guard.ts`), which deliberately
26
- * draws different lines for a different threat model.
23
+ * the embedding pool (`resolveEmbeddingConcurrency`,
24
+ * `src/llm/embedders/remote.ts`) both classify through here. NOT shared with
25
+ * the website snapshot fetcher's SSRF policy
26
+ * (`sources/snapshot-fetchers/host-guard.ts`), which deliberately draws
27
+ * different lines for a different threat model.
27
28
  *
28
29
  * @module core/loopback
29
30
  */
@@ -92,14 +93,8 @@ export function isLoopbackEndpoint(endpoint) {
92
93
  * endpoint: 1 for a loopback endpoint (a local model server serves one
93
94
  * inference at a time; concurrent requests thrash it — reload thrash, HTTP
94
95
  * 500 "Model reloaded"), 2 for a remote one (enough to overlap request
95
- * latency without hammering a rate-limited API). A leaf helper so both
96
- * callers — the indexer's LLM enrichment pool (`getDefaultLlmConcurrency`,
97
- * `src/indexer/indexer.ts`) and the embedding pool
98
- * (`resolveEmbeddingConcurrency`, `src/llm/embedders/remote.ts`) — share one
99
- * definition instead of mirroring it; `src/llm/embedders/remote.ts` cannot
100
- * import `getDefaultLlmConcurrency` directly (`src/indexer/indexer.ts`
101
- * already depends on this module transitively through
102
- * materialize-embeddings.ts).
96
+ * latency without hammering a rate-limited API). Used by the embedding pool
97
+ * (`resolveEmbeddingConcurrency`, `src/llm/embedders/remote.ts`).
103
98
  */
104
99
  export function defaultConcurrencyForEndpoint(endpoint) {
105
100
  return isLoopbackEndpoint(endpoint) ? 1 : 2;
@@ -0,0 +1,20 @@
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
+ /** The line of `src/assets/stash-skeleton/README.md` that reaches curate verbatim as a query. */
5
+ const STASH_README_LINE = "This is an **AKM stash** — a structured knowledge repository that stores reusable";
6
+ /**
7
+ * What the (trimmed) curate input is when it is not a task, else undefined.
8
+ * Harness and tool envelopes (`<task-notification>…`, `<system-reminder>…`,
9
+ * `<cross-session-message …>…`) start with a tag and close one, and the stash
10
+ * README line arrives verbatim; on the retrieval suite neither shape occurs in
11
+ * a real query. Length is not a signal: prompts over 2,000 characters found
12
+ * relevant assets at about the rate of shorter long prompts.
13
+ */
14
+ export function nonTaskInput(query) {
15
+ if (query.startsWith("<") && query.includes("</"))
16
+ return "a harness or tool envelope";
17
+ if (query === STASH_README_LINE)
18
+ return "the akm stash README boilerplate";
19
+ return undefined;
20
+ }