akm-cli 0.9.1 → 0.9.2-alpha.2

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 (350) hide show
  1. package/CHANGELOG.md +103 -28
  2. package/README.md +3 -1
  3. package/SECURITY.md +1 -1
  4. package/STABILITY.md +1 -1
  5. package/dist/akm +2 -2
  6. package/dist/akm-migrate +2 -2
  7. package/dist/assets/hints/cli-hints-full.md +14 -9
  8. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
  9. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  10. package/dist/assets/models.json +35 -0
  11. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
  12. package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
  13. package/dist/assets/tasks/core/extract.yml +6 -5
  14. package/dist/assets/tasks/core/improve.yml +6 -5
  15. package/dist/assets/tasks/core/index-refresh.yml +6 -5
  16. package/dist/assets/tasks/core/sync.yml +6 -5
  17. package/dist/assets/tasks/core/version-check.yml +6 -5
  18. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
  19. package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
  20. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
  21. package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
  22. package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
  23. package/dist/cli/confirm.js +2 -2
  24. package/dist/cli/parse-args.js +3 -24
  25. package/dist/cli/retired-commands.js +1 -1
  26. package/dist/cli/shared.js +2 -2
  27. package/dist/cli.js +11 -9
  28. package/dist/commands/agent/agent-dispatch.js +55 -89
  29. package/dist/commands/agent/contribute-cli.js +12 -45
  30. package/dist/commands/command/builtin-action.js +32 -0
  31. package/dist/commands/command/command-cli.js +99 -0
  32. package/dist/commands/command/command-execution.js +308 -0
  33. package/dist/commands/command/execution-source-loader.js +176 -0
  34. package/dist/commands/command/portable-template.js +60 -0
  35. package/dist/commands/config-cli.js +10 -4
  36. package/dist/commands/env/env.js +4 -2
  37. package/dist/commands/feedback-cli.js +1 -1
  38. package/dist/commands/health/checks.js +241 -29
  39. package/dist/commands/health/html-report.js +0 -14
  40. package/dist/commands/health/report-view-model.js +0 -1
  41. package/dist/commands/health/surfaces.js +6 -7
  42. package/dist/commands/health/types.js +0 -2
  43. package/dist/commands/health.js +63 -18
  44. package/dist/commands/improve/collapse-detector.js +5 -6
  45. package/dist/commands/improve/consolidate.js +251 -214
  46. package/dist/commands/improve/distill/promote-memory.js +71 -34
  47. package/dist/commands/improve/distill/quality-gate.js +17 -5
  48. package/dist/commands/improve/distill.js +232 -155
  49. package/dist/commands/improve/eligibility.js +112 -79
  50. package/dist/commands/improve/execution.js +57 -0
  51. package/dist/commands/improve/extract-cli.js +5 -5
  52. package/dist/commands/improve/extract-prompt.js +64 -22
  53. package/dist/commands/improve/extract.js +608 -360
  54. package/dist/commands/improve/improve-strategies.js +43 -14
  55. package/dist/commands/improve/improve.js +249 -29
  56. package/dist/commands/improve/loop-stages.js +11 -17
  57. package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
  58. package/dist/commands/improve/outcome-loop.js +22 -38
  59. package/dist/commands/improve/planner.js +134 -0
  60. package/dist/commands/improve/preparation.js +730 -409
  61. package/dist/commands/improve/reflect.js +386 -223
  62. package/dist/commands/improve/run-context.js +3 -4
  63. package/dist/commands/improve/salience.js +6 -58
  64. package/dist/commands/improve/session-asset.js +12 -12
  65. package/dist/commands/lint/index.js +101 -29
  66. package/dist/commands/migrate-cli.js +11 -69
  67. package/dist/commands/migration-tool.js +6 -9
  68. package/dist/commands/models-cli.js +27 -0
  69. package/dist/commands/proposal/drain.js +258 -186
  70. package/dist/commands/proposal/proposal-cli.js +32 -10
  71. package/dist/commands/proposal/proposal.js +2 -5
  72. package/dist/commands/proposal/propose.js +192 -172
  73. package/dist/commands/proposal/repository.js +54 -91
  74. package/dist/commands/proposal/validators/proposal-validators.js +9 -7
  75. package/dist/commands/read/curate.js +53 -22
  76. package/dist/commands/read/registry-search.js +25 -9
  77. package/dist/commands/read/remember-cli.js +14 -2
  78. package/dist/commands/read/search.js +10 -4
  79. package/dist/commands/read/show.js +139 -153
  80. package/dist/commands/registry-cli.js +16 -7
  81. package/dist/commands/remember.js +33 -18
  82. package/dist/commands/sources/add-cli.js +19 -178
  83. package/dist/commands/sources/bundle-cli.js +15 -3
  84. package/dist/commands/sources/dangerous-env-audit.js +135 -0
  85. package/dist/commands/sources/info.js +2 -1
  86. package/dist/commands/sources/installed-stashes.js +901 -177
  87. package/dist/commands/sources/schema-repair.js +174 -95
  88. package/dist/commands/sources/self-update.js +30 -74
  89. package/dist/commands/sources/source-add.js +3 -5
  90. package/dist/commands/sources/sources-cli.js +2 -15
  91. package/dist/commands/sources/update-transaction.js +220 -0
  92. package/dist/commands/tasks/tasks-cli.js +3 -3
  93. package/dist/commands/tasks/tasks.js +736 -317
  94. package/dist/commands/workflow-cli.js +2 -2
  95. package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
  96. package/dist/core/adapter/adapters/akm-adapter.js +85 -35
  97. package/dist/core/adapter/adapters/akm-lint.js +54 -39
  98. package/dist/core/adapter/adapters/akm-metadata.js +45 -45
  99. package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
  100. package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
  101. package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
  102. package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
  103. package/dist/core/adapter/adapters/index.js +0 -9
  104. package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
  105. package/dist/core/adapter/adapters/okf-adapter.js +4 -0
  106. package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
  107. package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
  108. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
  109. package/dist/core/adapter/execution-source.js +308 -0
  110. package/dist/core/adapter/recognize-match.js +36 -13
  111. package/dist/core/adapter/registry.js +0 -9
  112. package/dist/core/asset/stash-meta.js +94 -4
  113. package/dist/core/common.js +6 -11
  114. package/dist/core/config/config-io.js +3 -3
  115. package/dist/core/config/config-schema.js +18 -40
  116. package/dist/core/config/config-sources.js +11 -21
  117. package/dist/core/config/config-walker.js +31 -13
  118. package/dist/core/config/config.js +23 -26
  119. package/dist/core/config/schema/engines.js +8 -7
  120. package/dist/core/config/schema/improve-processes.js +29 -5
  121. package/dist/core/config/schema/index-config.js +0 -27
  122. package/dist/core/config/schema/primitives.js +1 -23
  123. package/dist/core/config/schema/sources-bundles.js +13 -16
  124. package/dist/core/errors.js +2 -0
  125. package/dist/core/events.js +68 -32
  126. package/dist/core/extra-params.js +1 -0
  127. package/dist/core/improve-result.js +315 -0
  128. package/dist/core/lesson-lint.js +0 -6
  129. package/dist/core/maintenance-barrier.js +4 -4
  130. package/dist/core/network-policy.js +152 -0
  131. package/dist/core/paths.js +1 -1
  132. package/dist/core/recognition-util.js +4 -4
  133. package/dist/core/registry-url.js +456 -0
  134. package/dist/core/state/migrations.js +161 -47
  135. package/dist/core/state-db.js +453 -80
  136. package/dist/core/system-error.js +32 -0
  137. package/dist/core/time.js +2 -12
  138. package/dist/core/write-source.js +0 -18
  139. package/dist/execution/directory-identity.js +52 -0
  140. package/dist/execution/executable-identity.js +107 -0
  141. package/dist/execution/guarded-source.js +398 -0
  142. package/dist/execution/json.js +95 -0
  143. package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
  144. package/dist/execution/record.js +55 -0
  145. package/dist/execution/resolved-request.js +730 -0
  146. package/dist/execution/source.js +320 -0
  147. package/dist/indexer/bundle-identity-guard.js +5 -4
  148. package/dist/indexer/db/graph-db.js +33 -0
  149. package/dist/indexer/graph/graph-boost.js +3 -4
  150. package/dist/indexer/graph/graph-extraction.js +562 -373
  151. package/dist/indexer/index-written-assets.js +78 -39
  152. package/dist/indexer/indexer.js +471 -432
  153. package/dist/indexer/installations.js +6 -0
  154. package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
  155. package/dist/indexer/materialize-embeddings.js +155 -0
  156. package/dist/indexer/passes/memory-inference.js +227 -174
  157. package/dist/indexer/passes/metadata.js +263 -118
  158. package/dist/indexer/scan/doc-to-entry.js +7 -10
  159. package/dist/indexer/scan/drain-dir.js +51 -23
  160. package/dist/indexer/search/db-search.js +156 -50
  161. package/dist/indexer/search/fts-query.js +40 -40
  162. package/dist/indexer/search/ranking.js +36 -1
  163. package/dist/indexer/search/search-attribution.js +3 -1
  164. package/dist/indexer/search/search-fields.js +23 -14
  165. package/dist/indexer/search/search-hit-enrichers.js +1 -1
  166. package/dist/indexer/search/search-source.js +7 -16
  167. package/dist/indexer/search/semantic-status.js +10 -1
  168. package/dist/indexer/usage/show-usage.js +105 -0
  169. package/dist/indexer/usage/usage-events.js +7 -2
  170. package/dist/indexer/walk/matchers.js +40 -10
  171. package/dist/indexer/walk/path-resolver.js +5 -2
  172. package/dist/indexer/walk/walker.js +20 -2
  173. package/dist/integrations/agent/builder-shared.js +3 -6
  174. package/dist/integrations/agent/conversation-fallback.js +16 -0
  175. package/dist/integrations/agent/engine-resolution.js +87 -87
  176. package/dist/integrations/agent/execution-cascade.js +566 -0
  177. package/dist/integrations/agent/execution-definitions.js +211 -0
  178. package/dist/integrations/agent/execution-lowering.js +811 -0
  179. package/dist/integrations/agent/execution-preparation.js +67 -0
  180. package/dist/integrations/agent/index.js +0 -2
  181. package/dist/integrations/agent/inline-execution.js +74 -0
  182. package/dist/integrations/agent/model-map.js +515 -0
  183. package/dist/integrations/agent/persona-fallback.js +30 -0
  184. package/dist/integrations/agent/request-lowering.js +186 -0
  185. package/dist/integrations/agent/runner-dispatch.js +230 -37
  186. package/dist/integrations/agent/runner.js +12 -83
  187. package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
  188. package/dist/integrations/harnesses/aider/index.js +0 -1
  189. package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
  190. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  191. package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
  192. package/dist/integrations/harnesses/claude/index.js +1 -5
  193. package/dist/integrations/harnesses/claude/session-log.js +3 -33
  194. package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
  195. package/dist/integrations/harnesses/codex/index.js +0 -1
  196. package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
  197. package/dist/integrations/harnesses/copilot/index.js +0 -1
  198. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
  199. package/dist/integrations/harnesses/gemini/index.js +0 -1
  200. package/dist/integrations/harnesses/index.js +4 -44
  201. package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
  202. package/dist/integrations/harnesses/opencode/index.js +0 -2
  203. package/dist/integrations/harnesses/opencode/session-log.js +14 -204
  204. package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
  205. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
  206. package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
  207. package/dist/integrations/harnesses/openhands/index.js +0 -1
  208. package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
  209. package/dist/integrations/harnesses/pi/index.js +0 -1
  210. package/dist/integrations/harnesses/shared.js +0 -1
  211. package/dist/integrations/harnesses/types.js +1 -3
  212. package/dist/integrations/lockfile.js +82 -79
  213. package/dist/integrations/session-logs/index.js +6 -17
  214. package/dist/integrations/session-logs/provider-base.js +1 -29
  215. package/dist/llm/client.js +10 -5
  216. package/dist/llm/embedder.js +6 -7
  217. package/dist/llm/embedders/local.js +37 -88
  218. package/dist/llm/embedders/types.js +1 -1
  219. package/dist/llm/graph-extract.js +75 -50
  220. package/dist/llm/index-passes.js +43 -5
  221. package/dist/llm/memory-infer.js +8 -6
  222. package/dist/llm/metadata-enhance.js +5 -3
  223. package/dist/llm/structured-call.js +122 -25
  224. package/dist/output/format-exempt.js +1 -1
  225. package/dist/output/render-registry.js +0 -16
  226. package/dist/output/renderers.js +12 -7
  227. package/dist/output/shapes/curate.js +1 -0
  228. package/dist/output/shapes/helpers.js +10 -2
  229. package/dist/output/shapes/passthrough.js +2 -0
  230. package/dist/output/text/command-format.js +31 -33
  231. package/dist/output/text/health-format.js +1 -29
  232. package/dist/output/text/migrate.js +6 -56
  233. package/dist/output/text/proposal-format.js +16 -1
  234. package/dist/output/text/workflow-format.js +16 -0
  235. package/dist/registry/network.js +279 -0
  236. package/dist/registry/pinned-request-helper.js +247 -0
  237. package/dist/registry/pinned-transport.js +717 -0
  238. package/dist/registry/providers/skills-sh.js +18 -6
  239. package/dist/registry/providers/static-index.js +20 -7
  240. package/dist/registry/resolve.js +53 -28
  241. package/dist/scripts/akm-migrate-node.js +19334 -52269
  242. package/dist/scripts/akm-migrate.js +19270 -51612
  243. package/dist/setup/registry-stash-loader.js +64 -20
  244. package/dist/setup/semantic-assets.js +9 -34
  245. package/dist/setup/setup.js +12 -30
  246. package/dist/setup/source-identity.js +17 -0
  247. package/dist/setup/steps/sources.js +36 -15
  248. package/dist/setup/steps/tasks.js +39 -11
  249. package/dist/sources/providers/git-provider.js +3 -3
  250. package/dist/sources/providers/npm.js +2 -2
  251. package/dist/sources/providers/provider-utils.js +4 -3
  252. package/dist/sources/providers/website.js +11 -7
  253. package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
  254. package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
  255. package/dist/sources/website-url.js +73 -0
  256. package/dist/storage/engines/sqlite-migrations.js +81 -26
  257. package/dist/storage/managed-db.js +27 -24
  258. package/dist/storage/repositories/events-repository.js +3 -0
  259. package/dist/storage/repositories/index-connection.js +42 -10
  260. package/dist/storage/repositories/index-entries-repository.js +203 -229
  261. package/dist/storage/repositories/index-entry-mapper.js +8 -12
  262. package/dist/storage/repositories/index-entry-schema.js +255 -0
  263. package/dist/storage/repositories/index-fts-repository.js +64 -71
  264. package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
  265. package/dist/storage/repositories/index-meta-repository.js +0 -11
  266. package/dist/storage/repositories/index-schema.js +74 -350
  267. package/dist/storage/repositories/index-utility-repository.js +12 -17
  268. package/dist/storage/repositories/index-vec-repository.js +56 -7
  269. package/dist/storage/repositories/proposals-repository.js +4 -127
  270. package/dist/storage/repositories/registry-cache.js +2 -1
  271. package/dist/storage/repositories/task-history-repository.js +20 -40
  272. package/dist/storage/repositories/workflow-runs-repository.js +228 -129
  273. package/dist/storage/sqlite-read-snapshot.js +148 -0
  274. package/dist/tasks/backends/cron.js +170 -42
  275. package/dist/tasks/backends/index.js +1 -1
  276. package/dist/tasks/backends/launchd.js +787 -202
  277. package/dist/tasks/backends/schtasks.js +282 -83
  278. package/dist/tasks/embedded.js +7 -7
  279. package/dist/tasks/frozen-script.js +50 -0
  280. package/dist/tasks/resolve-akm-bin.js +5 -1
  281. package/dist/tasks/runner.js +239 -251
  282. package/dist/tasks/runtime-v3.js +281 -0
  283. package/dist/tasks/scheduler-binding.js +272 -0
  284. package/dist/tasks/scheduler-invocation.js +57 -43
  285. package/dist/tasks/scheduler-sync.js +654 -0
  286. package/dist/tasks/source-v3.js +752 -0
  287. package/dist/tasks/standalone-script-entry.js +5 -0
  288. package/dist/tasks/task-id.js +29 -0
  289. package/dist/workflows/authoring/authoring.js +15 -32
  290. package/dist/workflows/exec/dispatch-redaction.js +14 -8
  291. package/dist/workflows/exec/exec-unit.js +7 -28
  292. package/dist/workflows/exec/frozen-judge.js +57 -89
  293. package/dist/workflows/exec/lowering-notices.js +23 -0
  294. package/dist/workflows/exec/native-executor.js +301 -458
  295. package/dist/workflows/exec/param-secrets.js +4 -3
  296. package/dist/workflows/exec/run-workflow.js +26 -32
  297. package/dist/workflows/exec/step-work.js +105 -109
  298. package/dist/workflows/exec/unit-dispatch.js +103 -27
  299. package/dist/workflows/exec/unit-writer.js +3 -3
  300. package/dist/workflows/exec/worktree.js +2 -2
  301. package/dist/workflows/ir/compile.js +86 -72
  302. package/dist/workflows/ir/environment-v4.js +328 -0
  303. package/dist/workflows/ir/freeze-v4.js +122 -0
  304. package/dist/workflows/ir/plan-hash.js +13 -7
  305. package/dist/workflows/ir/schema-v4.js +525 -0
  306. package/dist/workflows/ir/schema.js +25 -284
  307. package/dist/workflows/ir/source-freeze-v4.js +506 -0
  308. package/dist/workflows/parser.js +27 -24
  309. package/dist/workflows/program/schema.js +1 -2
  310. package/dist/workflows/renderer.js +42 -29
  311. package/dist/workflows/resource-limits.js +4 -5
  312. package/dist/workflows/runtime/agent-identity.js +11 -13
  313. package/dist/workflows/runtime/plan-classifier.js +8 -8
  314. package/dist/workflows/runtime/runs.js +27 -43
  315. package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
  316. package/dist/workflows/source-files.js +373 -0
  317. package/dist/workflows/source-ir/compile.js +196 -0
  318. package/dist/workflows/source-ir/github-yaml.js +577 -0
  319. package/dist/workflows/source-ir/ordering.js +38 -0
  320. package/dist/workflows/source-ir/program.js +50 -0
  321. package/dist/workflows/source-ir/result.js +26 -0
  322. package/dist/workflows/source-ir/schema.js +772 -0
  323. package/dist/workflows/source-ir/semantics.js +242 -0
  324. package/dist/workflows/source-ir/uses.js +14 -0
  325. package/docs/README.md +2 -0
  326. package/docs/migration/README.md +3 -1
  327. package/docs/migration/release-notes/0.9.2.md +55 -0
  328. package/docs/migration/release-notes/README.md +5 -0
  329. package/docs/migration/v0.8-to-v0.9.md +76 -1077
  330. package/docs/migration/v0.9.0-troubleshooting.md +104 -516
  331. package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
  332. package/docs/reference/README.md +1 -0
  333. package/docs/reference/cli.md +230 -98
  334. package/docs/reference/configuration.md +159 -36
  335. package/docs/reference/data-and-telemetry.md +19 -1
  336. package/docs/reference/supported-formats.md +23 -3
  337. package/docs/reference/tasks.md +182 -0
  338. package/docs/reference/workflow-schema.md +91 -40
  339. package/docs/reference/workflows.md +33 -6
  340. package/package.json +10 -6
  341. package/schemas/akm-config.json +372 -224
  342. package/schemas/akm-task.json +324 -80
  343. package/schemas/akm-workflow.json +6 -9
  344. package/dist/core/migration-operation.js +0 -75
  345. package/dist/integrations/agent/model-aliases.js +0 -74
  346. package/dist/tasks/parser.js +0 -380
  347. package/dist/tasks/schema.js +0 -123
  348. package/dist/tasks/validator.js +0 -80
  349. package/dist/workflows/ir/freeze.js +0 -320
  350. package/dist/workflows/runtime/document-cache.js +0 -13
@@ -64,20 +64,19 @@ import { resolveStandardsContext } from "../../core/standards/resolve-standards-
64
64
  import { withStateDb } from "../../core/state-db.js";
65
65
  import { warnVerbose } from "../../core/warn.js";
66
66
  import { resolveAssetPath } from "../../indexer/walk/path-resolver.js";
67
- import { getDefaultLlmConfig } from "../../integrations/agent/engine-resolution.js";
68
- import { materializeLlmRunnerConnection, resolveImproveProcessRunner } from "../../integrations/agent/runner.js";
69
- import { chatCompletion } from "../../llm/client.js";
70
- import { callStructured } from "../../llm/structured-call.js";
71
- import { closeDatabase, openIndexDatabase } from "../../storage/repositories/index-connection.js";
67
+ import { disposeLoweredExecutionDispatchLease, } from "../../integrations/agent/execution-lowering.js";
68
+ import { callStructured, preflightStructuredLlmRunner } from "../../llm/structured-call.js";
69
+ import { closeDatabase, openReadonlyExistingDatabase } from "../../storage/repositories/index-connection.js";
72
70
  import { getAllEntries } from "../../storage/repositories/index-entries-repository.js";
73
- import { isProposalSkipped, listProposals, proposalContent, } from "../proposal/repository.js";
71
+ import { isProposalSkipped, listProposals, listProposalsReadOnly, proposalContent, } from "../proposal/repository.js";
74
72
  import { stripFrontmatterBody as stripBodyForFidelity } from "./content-hash.js";
75
73
  import { autoRepairLessonFrontmatter, autoSwapDescriptionWhenToUse, collectLessonQualityFindings, repairLessonDescriptionTruncation, } from "./distill/content-repair.js";
76
- import { promoteMemoryToKnowledge } from "./distill/promote-memory.js";
74
+ import { memoryKnowledgePromotionRequiresDispatch, planMemoryKnowledgePromotion, promoteMemoryToKnowledge, } from "./distill/promote-memory.js";
77
75
  import { fetchTopSimilarLessons, persistOutputEncodingSalience, runLessonQualityJudge, writeQualityRejection, } from "./distill/quality-gate.js";
78
76
  import { buildClsContext, checkDistillFidelity } from "./distill-guards.js";
79
77
  import { deriveKnowledgeRef } from "./distill-promotion-policy.js";
80
78
  import { buildRefVocabulary, scoreEncodingSalience } from "./encoding-salience.js";
79
+ import { resolveImproveLlmExecution } from "./execution.js";
81
80
  import { resolveImproveStrategy, resolveProcessEnabled } from "./improve-strategies.js";
82
81
  import { emitProposal } from "./proposal-envelope.js";
83
82
  import { createRunContext, resolveRunStashDir } from "./run-context.js";
@@ -432,7 +431,7 @@ export function buildDistillPrompt(input) {
432
431
  * ref vocabulary the caller reuses when scoring the distilled OUTPUT (G4).
433
432
  */
434
433
  async function loadAndScoreInputSalience(args) {
435
- const { inputRef, durableInputRef, salienceWriteKey, stash, config, outcomeWeightEnabled, lookup, ctx } = args;
434
+ const { inputRef, durableInputRef, salienceWriteKey, stash, outcomeWeightEnabled, lookup, ctx } = args;
436
435
  // Best-effort load: when the asset is not yet indexed we still proceed —
437
436
  // the LLM is asked to distil from "available signal" (feedback alone).
438
437
  let assetContent = null;
@@ -458,20 +457,21 @@ async function loadAndScoreInputSalience(args) {
458
457
  // reuses it when scoring the distilled OUTPUT at proposal creation (G4).
459
458
  let existingRefVocabulary = new Set();
460
459
  try {
461
- const embCfg = config?.embedding;
462
- const indexDb = openIndexDatabase(getDbPath(), embCfg?.dimension ? { embeddingDim: embCfg.dimension } : undefined);
463
- try {
464
- const allRefs = getAllEntries(indexDb).map((e) => e.entryKey);
465
- existingRefVocabulary = buildRefVocabulary(allRefs);
466
- }
467
- finally {
468
- closeDatabase(indexDb);
460
+ const indexDb = openReadonlyExistingDatabase(getDbPath(), { isolatedSnapshot: true });
461
+ if (indexDb) {
462
+ try {
463
+ const allRefs = getAllEntries(indexDb).map((e) => e.itemRef);
464
+ existingRefVocabulary = buildRefVocabulary(allRefs);
465
+ }
466
+ finally {
467
+ closeDatabase(indexDb);
468
+ }
469
469
  }
470
470
  }
471
471
  catch {
472
472
  // Index not available — novelty defaults to type-floor.
473
473
  }
474
- if (assetContent && assetFilePath) {
474
+ if (args.persistSalience !== false && assetContent && assetFilePath) {
475
475
  try {
476
476
  const parsedRef = parseRefInput(inputRef);
477
477
  // G4: predictionError decays with revision count — the prior hardcoded
@@ -561,6 +561,92 @@ function refuseDisallowedDistillInput(args) {
561
561
  message,
562
562
  };
563
563
  }
564
+ async function prepareDistillExecution(args) {
565
+ const { options, config, inputRef, durableInputRef, salienceWriteKey } = args;
566
+ const stash = resolveRunStashDir(options.stashDir);
567
+ const chat = options.chat;
568
+ const executionNotices = new Map();
569
+ const collectNotices = (notices) => {
570
+ for (const notice of notices)
571
+ executionNotices.set(JSON.stringify(notice), notice);
572
+ };
573
+ const resolvedExecution = !Object.hasOwn(options, "llmRunner")
574
+ ? resolveImproveLlmExecution({
575
+ config,
576
+ profile: options.improveProfile,
577
+ process: getImproveProcessConfig("distill", options.improveProfile),
578
+ processName: "distill",
579
+ })
580
+ : null;
581
+ if (resolvedExecution)
582
+ collectNotices(resolvedExecution.notices);
583
+ const distillRunner = Object.hasOwn(options, "llmRunner")
584
+ ? (options.llmRunner ?? undefined)
585
+ : resolvedExecution?.runner;
586
+ const withNotices = (result) => executionNotices.size > 0 ? { ...result, notices: Object.freeze([...executionNotices.values()]) } : result;
587
+ const lookup = options.lookupFn ?? ((ref) => defaultLookup(ref, stash));
588
+ const readEventsImpl = options.readEventsFn ??
589
+ ((readOptions) => readEvents(readOptions, { readOnly: true }));
590
+ const outcomeWeightEnabled = config.improve?.salience?.outcomeWeightEnabled !== false;
591
+ const fetchSimilarLessonsFn = options.fetchSimilarLessonsFn ?? ((query, n) => fetchTopSimilarLessons(query, n, options.stashDir));
592
+ const assetCtx = createRunContext({
593
+ stashDir: stash,
594
+ config,
595
+ eventsCtx: options.eventsCtx ?? {},
596
+ proposalsCtx: options.ctx ?? {},
597
+ chat,
598
+ getLlmRunner: () => distillRunner ?? null,
599
+ sourceRun: options.sourceRun ?? `distill-${Date.now()}`,
600
+ dryRun: false,
601
+ signal: options.signal,
602
+ }).withFreshAssetMemo();
603
+ const initialSalience = await loadAndScoreInputSalience({
604
+ inputRef,
605
+ durableInputRef,
606
+ salienceWriteKey,
607
+ stash,
608
+ config,
609
+ outcomeWeightEnabled,
610
+ lookup,
611
+ ctx: assetCtx,
612
+ persistSalience: false,
613
+ });
614
+ const assetState = { ...initialSalience };
615
+ const persistInputSalience = async () => {
616
+ const scored = await loadAndScoreInputSalience({
617
+ inputRef,
618
+ durableInputRef,
619
+ salienceWriteKey,
620
+ stash,
621
+ config,
622
+ outcomeWeightEnabled,
623
+ lookup,
624
+ ctx: assetCtx,
625
+ });
626
+ assetState.assetContent = scored.assetContent ?? assetState.assetContent;
627
+ assetState.existingRefVocabulary = scored.existingRefVocabulary;
628
+ };
629
+ const feedbackState = readDistillFeedback({ readEventsImpl, options, durableInputRef });
630
+ const feedback = feedbackState.filteredEvents.slice(-20).map((event) => ({
631
+ ts: event.ts,
632
+ eventType: event.eventType,
633
+ ...(event.metadata !== undefined ? { metadata: event.metadata } : {}),
634
+ }));
635
+ return {
636
+ stash,
637
+ chat,
638
+ collectNotices,
639
+ distillRunner,
640
+ withNotices,
641
+ lookup,
642
+ outcomeWeightEnabled,
643
+ fetchSimilarLessonsFn,
644
+ assetState,
645
+ persistInputSalience,
646
+ feedback,
647
+ ...feedbackState,
648
+ };
649
+ }
564
650
  export async function akmDistill(options) {
565
651
  const inputRef = options.ref.trim();
566
652
  if (!inputRef) {
@@ -601,74 +687,30 @@ export async function akmDistill(options) {
601
687
  const refused = refuseDisallowedDistillInput({ options, parsedInputRef, inputRef, durableInputRef, eligMeta });
602
688
  if (refused)
603
689
  return refused;
604
- const stash = resolveRunStashDir(options.stashDir);
605
- const chat = options.chat ?? chatCompletion;
606
- const distillLlm = Object.hasOwn(options, "llmConfig")
607
- ? (options.llmConfig ?? undefined)
608
- : (() => {
609
- const runner = resolveImproveProcessRunner(options.improveProfile, "distill", config);
610
- return runner ? materializeLlmRunnerConnection(runner) : getDefaultLlmConfig(config);
611
- })();
612
- const lookup = options.lookupFn ?? ((ref) => defaultLookup(ref, stash));
613
- const readEventsImpl = options.readEventsFn ?? readEvents;
614
- // R1 opt-out must flow into every computeSalience call this command makes so
615
- // distill-written rank_score rows use the same weights as preparation's.
616
- const outcomeWeightEnabled = config.improve?.salience?.outcomeWeightEnabled !== false;
617
- // D-4 / #390: similar-lessons retrieval seam (test-injectable).
618
- const fetchSimilarLessonsFn = options.fetchSimilarLessonsFn ?? ((query, n) => fetchTopSimilarLessons(query, n, options.stashDir));
619
- const assetCtx = createRunContext({
620
- stashDir: stash,
690
+ const prepared = await prepareDistillExecution({
691
+ options,
621
692
  config,
622
- eventsCtx: options.eventsCtx ?? {},
623
- proposalsCtx: options.ctx ?? {},
624
- chat,
625
- getLlmConfig: () => distillLlm ?? null,
626
- sourceRun: options.sourceRun ?? `distill-${Date.now()}`,
627
- dryRun: false,
628
- signal: options.signal,
629
- }).withFreshAssetMemo();
630
- const { assetContent, existingRefVocabulary } = await loadAndScoreInputSalience({
631
693
  inputRef,
632
694
  durableInputRef,
633
695
  salienceWriteKey,
634
- stash,
635
- config,
636
- outcomeWeightEnabled,
637
- lookup,
638
- ctx: assetCtx,
639
- });
640
- const { filteredEvents, exclusionSet, filteredFeedbackCount, feedbackFullyFiltered } = readDistillFeedback({
641
- readEventsImpl,
642
- options,
643
- durableInputRef,
644
696
  });
645
- const feedback = filteredEvents.slice(-20).map((e) => ({
646
- ts: e.ts,
647
- eventType: e.eventType,
648
- ...(e.metadata !== undefined ? { metadata: e.metadata } : {}),
649
- }));
650
- // Memory→knowledge promotion branch (D-1/#369). When the target ref is a
651
- // reinforced memory, distill graduates it into a knowledge proposal instead
652
- // of a lesson — the whole branch (LLM contradiction-merge, quality gate,
653
- // proposal creation, event emit) lives in `promoteMemoryToKnowledge` and is
654
- // terminal when it fires. A `null` return means "not a promotion candidate";
655
- // fall through to the ordinary lesson/knowledge distillation path.
656
- const promotionResult = await promoteMemoryToKnowledge({
697
+ const { stash, chat, collectNotices, distillRunner, withNotices, lookup, outcomeWeightEnabled, fetchSimilarLessonsFn, assetState, persistInputSalience, feedback, filteredEvents, exclusionSet, filteredFeedbackCount, feedbackFullyFiltered, } = prepared;
698
+ const promotionContext = {
657
699
  targetKind,
658
700
  inputRef,
659
701
  durableInputRef,
660
702
  ...(options.itemRef ? { itemRef: options.itemRef } : {}),
661
- assetContent,
703
+ assetContent: assetState.assetContent,
662
704
  filteredEvents,
663
705
  config,
664
706
  strategy: options.improveProfile,
665
- llmConfig: distillLlm,
707
+ llmRunner: distillRunner,
666
708
  signal: options.signal,
667
709
  chat,
668
710
  stash,
669
711
  lookup,
670
712
  fetchSimilarLessonsFn,
671
- existingRefVocabulary,
713
+ existingRefVocabulary: assetState.existingRefVocabulary,
672
714
  outcomeWeightEnabled,
673
715
  eligMeta,
674
716
  eligibilitySource: options.eligibilitySource,
@@ -678,92 +720,120 @@ export async function akmDistill(options) {
678
720
  exclusionSetSize: exclusionSet.size,
679
721
  filteredFeedbackCount,
680
722
  feedbackFullyFiltered,
681
- });
682
- if (promotionResult)
683
- return promotionResult;
684
- const effectiveProposalKind = targetKind === "knowledge" ? "knowledge" : "lesson";
685
- const effectiveLessonRef = effectiveProposalKind === "knowledge" ? deriveKnowledgeRef(inputRef) : deriveLessonRef(inputRef);
686
- const messages = await buildDistillMessages({
687
- options,
688
- stash,
689
- inputRef,
690
- assetContent,
691
- feedback,
692
- effectiveProposalKind,
693
- effectiveLessonRef,
694
- fetchSimilarLessonsFn,
695
- });
696
- const { raw, fallbackReason } = await runDistillLlmCall({
697
- config,
698
- options,
699
- distillLlm,
700
- messages,
701
- effectiveProposalKind,
702
- });
703
- if (raw === null || raw.trim() === "") {
704
- return distillEmptyResponseResult({
705
- fallbackReason,
723
+ onNotices: collectNotices,
724
+ };
725
+ const promotionPlan = await planMemoryKnowledgePromotion(promotionContext);
726
+ let dispatchLease;
727
+ try {
728
+ // Memory→knowledge promotion branch (D-1/#369). When the target ref is a
729
+ // reinforced memory, distill graduates it into a knowledge proposal instead
730
+ // of a lesson — the whole branch (LLM contradiction-merge, quality gate,
731
+ // proposal creation, event emit) lives in `promoteMemoryToKnowledge` and is
732
+ // terminal when it fires. A `null` return means "not a promotion candidate";
733
+ // fall through to the ordinary lesson/knowledge distillation path.
734
+ if (promotionPlan && distillRunner && memoryKnowledgePromotionRequiresDispatch(promotionContext, promotionPlan)) {
735
+ dispatchLease = await preflightStructuredLlmRunner(distillRunner);
736
+ }
737
+ const promotionResult = await promoteMemoryToKnowledge({ ...promotionContext, ...(dispatchLease ? { lease: dispatchLease } : {}) }, promotionPlan);
738
+ if (promotionResult) {
739
+ await persistInputSalience();
740
+ return withNotices(promotionResult);
741
+ }
742
+ const effectiveProposalKind = targetKind === "knowledge" ? "knowledge" : "lesson";
743
+ const effectiveLessonRef = effectiveProposalKind === "knowledge" ? deriveKnowledgeRef(inputRef) : deriveLessonRef(inputRef);
744
+ const messages = await buildDistillMessages({
745
+ options,
746
+ stash,
747
+ inputRef,
748
+ assetContent: assetState.assetContent,
749
+ feedback,
750
+ effectiveProposalKind,
751
+ effectiveLessonRef,
752
+ fetchSimilarLessonsFn,
753
+ });
754
+ if (!dispatchLease && distillRunner)
755
+ dispatchLease = await preflightStructuredLlmRunner(distillRunner);
756
+ const { raw, fallbackReason } = await runDistillLlmCall({
757
+ config,
758
+ options,
759
+ distillRunner,
760
+ lease: dispatchLease,
761
+ messages,
762
+ effectiveProposalKind,
763
+ onNotices: collectNotices,
764
+ });
765
+ await persistInputSalience();
766
+ if (raw === null || raw.trim() === "") {
767
+ return withNotices(distillEmptyResponseResult({
768
+ fallbackReason,
769
+ inputRef,
770
+ durableInputRef,
771
+ ...(options.itemRef ? { itemRef: options.itemRef } : {}),
772
+ effectiveLessonRef,
773
+ effectiveProposalKind,
774
+ exclusionSet,
775
+ filteredFeedbackCount,
776
+ feedbackFullyFiltered,
777
+ eligMeta,
778
+ eventsCtx: options.eventsCtx,
779
+ }));
780
+ }
781
+ const { content, descriptionSwapped } = assembleAndValidateDistillContent({
782
+ raw,
783
+ effectiveProposalKind,
706
784
  inputRef,
707
785
  durableInputRef,
708
786
  ...(options.itemRef ? { itemRef: options.itemRef } : {}),
709
787
  effectiveLessonRef,
710
- effectiveProposalKind,
711
788
  exclusionSet,
712
789
  filteredFeedbackCount,
713
- feedbackFullyFiltered,
714
790
  eligMeta,
715
791
  eventsCtx: options.eventsCtx,
716
792
  });
793
+ const gate = await applyDistillQualityGate({
794
+ config,
795
+ options,
796
+ content,
797
+ assetContent: assetState.assetContent,
798
+ chat,
799
+ distillRunner,
800
+ lease: dispatchLease,
801
+ fetchSimilarLessonsFn,
802
+ stash,
803
+ inputRef,
804
+ effectiveLessonRef,
805
+ exclusionSet,
806
+ filteredFeedbackCount,
807
+ feedbackFullyFiltered,
808
+ onNotices: collectNotices,
809
+ });
810
+ if ("rejection" in gate)
811
+ return withNotices(gate.rejection);
812
+ const lessonJudgeConfidence = gate.confidence;
813
+ return withNotices(await emitDistillLessonProposal({
814
+ content,
815
+ options,
816
+ distillRunner,
817
+ assetContent: assetState.assetContent,
818
+ inputRef,
819
+ durableInputRef,
820
+ effectiveLessonRef,
821
+ effectiveProposalKind,
822
+ stash,
823
+ exclusionSet,
824
+ filteredFeedbackCount,
825
+ feedbackFullyFiltered,
826
+ lessonJudgeConfidence,
827
+ existingRefVocabulary: assetState.existingRefVocabulary,
828
+ outcomeWeightEnabled,
829
+ descriptionSwapped,
830
+ eligMeta,
831
+ }));
832
+ }
833
+ finally {
834
+ if (dispatchLease)
835
+ disposeLoweredExecutionDispatchLease(dispatchLease);
717
836
  }
718
- const { content, descriptionSwapped } = assembleAndValidateDistillContent({
719
- raw,
720
- effectiveProposalKind,
721
- inputRef,
722
- durableInputRef,
723
- ...(options.itemRef ? { itemRef: options.itemRef } : {}),
724
- effectiveLessonRef,
725
- exclusionSet,
726
- filteredFeedbackCount,
727
- eligMeta,
728
- eventsCtx: options.eventsCtx,
729
- });
730
- const gate = await applyDistillQualityGate({
731
- config,
732
- options,
733
- content,
734
- assetContent,
735
- chat,
736
- distillLlm,
737
- fetchSimilarLessonsFn,
738
- stash,
739
- inputRef,
740
- effectiveLessonRef,
741
- exclusionSet,
742
- filteredFeedbackCount,
743
- feedbackFullyFiltered,
744
- });
745
- if ("rejection" in gate)
746
- return gate.rejection;
747
- const lessonJudgeConfidence = gate.confidence;
748
- return emitDistillLessonProposal({
749
- content,
750
- options,
751
- distillLlm,
752
- assetContent,
753
- inputRef,
754
- durableInputRef,
755
- effectiveLessonRef,
756
- effectiveProposalKind,
757
- stash,
758
- exclusionSet,
759
- filteredFeedbackCount,
760
- feedbackFullyFiltered,
761
- lessonJudgeConfidence,
762
- existingRefVocabulary,
763
- outcomeWeightEnabled,
764
- descriptionSwapped,
765
- eligMeta,
766
- });
767
837
  }
768
838
  // ── Helpers ─────────────────────────────────────────────────────────────────
769
839
  /**
@@ -774,7 +844,7 @@ export async function akmDistill(options) {
774
844
  * event is byte-identical.
775
845
  */
776
846
  async function emitDistillLessonProposal(args) {
777
- const { options, distillLlm, assetContent, inputRef, durableInputRef, effectiveLessonRef, effectiveProposalKind, stash, exclusionSet, filteredFeedbackCount, feedbackFullyFiltered, lessonJudgeConfidence, existingRefVocabulary, outcomeWeightEnabled, descriptionSwapped, eligMeta, } = args;
847
+ const { options, distillRunner, assetContent, inputRef, durableInputRef, effectiveLessonRef, effectiveProposalKind, stash, exclusionSet, filteredFeedbackCount, feedbackFullyFiltered, lessonJudgeConfidence, existingRefVocabulary, outcomeWeightEnabled, descriptionSwapped, eligMeta, } = args;
778
848
  let content = args.content;
779
849
  // WS-3b: Distill→source fidelity check (step 10).
780
850
  // When fidelityCheck.enabled, check the distill proposal against its cited
@@ -820,7 +890,7 @@ async function emitDistillLessonProposal(args) {
820
890
  // (profile/config fallback included), not the raw option — a standalone
821
891
  // `akm distill` run must fingerprint under the model that actually
822
892
  // generated the content, matching the promote-memory branch.
823
- ...(distillLlm?.model ? { modelId: distillLlm.model } : {}),
893
+ ...(distillRunner?.connection.model ? { modelId: distillRunner.connection.model } : {}),
824
894
  source: "distill",
825
895
  ...(options.sourceRun !== undefined ? { sourceRun: options.sourceRun } : {}),
826
896
  payload: {
@@ -973,7 +1043,7 @@ function assembleAndValidateDistillContent(args) {
973
1043
  * the fallback reason.
974
1044
  */
975
1045
  async function runDistillLlmCall(args) {
976
- const { config, options, distillLlm, messages, effectiveProposalKind } = args;
1046
+ const { config, options, distillRunner, lease, messages, effectiveProposalKind, onNotices } = args;
977
1047
  const distillSchema = effectiveProposalKind === "knowledge" ? DISTILL_KNOWLEDGE_JSON_SCHEMA : DISTILL_LESSON_JSON_SCHEMA;
978
1048
  let fallbackReason;
979
1049
  const enabled = resolveProcessEnabled("distill", options.improveProfile ?? resolveImproveStrategy(undefined, config).config);
@@ -983,7 +1053,7 @@ async function runDistillLlmCall(args) {
983
1053
  // emitting the distill_invoked event so we don't double-emit here.
984
1054
  warnVerbose(`[akm] LLM fallback for ${feature}: ${reason}`);
985
1055
  };
986
- if (enabled && !distillLlm) {
1056
+ if (enabled && !distillRunner) {
987
1057
  // No LLM connection configured. At HEAD this threw a ConfigError inside
988
1058
  // the gated fn and tryLlmFeature routed it through the "error" fallback;
989
1059
  // reproduce that terminal state directly (the gate-disabled case above
@@ -996,16 +1066,20 @@ async function runDistillLlmCall(args) {
996
1066
  feature: "distill",
997
1067
  akmConfig: config,
998
1068
  enabled,
999
- // Safe: when the gate is open, distillLlm is defined (guard above); when
1000
- // it is closed, the transport never runs and config is never read.
1001
- config: distillLlm,
1069
+ // Safe: when the gate is open, distillRunner is defined (guard above); when
1070
+ // it is closed, the transport never runs and the runner is never read.
1071
+ runner: distillRunner,
1072
+ ...(lease ? { lease } : {}),
1002
1073
  messages,
1003
1074
  request: options.chat === undefined
1004
1075
  ? // Production path: pass the JSON schema so providers that honour
1005
1076
  // `response_format: json_schema` enforce shape upstream. Providers
1006
1077
  // that ignore the option fall through to the prompt-contract
1007
1078
  // markdown path.
1008
- { responseSchema: distillSchema }
1079
+ {
1080
+ responseSchema: distillSchema,
1081
+ ...(options.signal ? { signal: options.signal } : {}),
1082
+ }
1009
1083
  : // Test seam: keep the injected fake as the transport; fakes never
1010
1084
  // see the schema (they return markdown strings).
1011
1085
  { chat: options.chat, ...(options.signal ? { signal: options.signal } : {}) },
@@ -1019,6 +1093,7 @@ async function runDistillLlmCall(args) {
1019
1093
  },
1020
1094
  fallback: null,
1021
1095
  onFallback: (evt) => recordFallback(evt.feature, evt.reason),
1096
+ onNotices,
1022
1097
  });
1023
1098
  return { raw, fallbackReason };
1024
1099
  }
@@ -1080,7 +1155,7 @@ function distillEmptyResponseResult(args) {
1080
1155
  * from `akmDistill`.
1081
1156
  */
1082
1157
  async function applyDistillQualityGate(args) {
1083
- const { config, options, content, assetContent, chat, distillLlm, fetchSimilarLessonsFn, stash, inputRef, effectiveLessonRef, exclusionSet, filteredFeedbackCount, feedbackFullyFiltered, } = args;
1158
+ const { config, options, content, assetContent, chat, distillRunner, lease, fetchSimilarLessonsFn, stash, inputRef, effectiveLessonRef, exclusionSet, filteredFeedbackCount, feedbackFullyFiltered, onNotices, } = args;
1084
1159
  if (!(options.improveProfile?.processes?.distill?.qualityGate?.enabled ?? true)) {
1085
1160
  return { confidence: undefined };
1086
1161
  }
@@ -1088,8 +1163,10 @@ async function applyDistillQualityGate(args) {
1088
1163
  const similarLessons = await fetchSimilarLessonsFn(content.slice(0, 500), 3);
1089
1164
  const judgeResult = await runLessonQualityJudge(config, content, assetContent ?? "", chat, {
1090
1165
  ...(similarLessons.length > 0 ? { similarLessons } : {}),
1091
- ...(distillLlm ? { llmConfig: distillLlm } : {}),
1166
+ ...(distillRunner ? { llmRunner: distillRunner } : {}),
1167
+ ...(lease ? { lease } : {}),
1092
1168
  ...(options.signal ? { signal: options.signal } : {}),
1169
+ onNotices,
1093
1170
  });
1094
1171
  if (!judgeResult.pass) {
1095
1172
  if (judgeResult.reviewNeeded) {
@@ -1147,7 +1224,7 @@ async function buildDistillMessages(args) {
1147
1224
  const { options, stash, inputRef, assetContent, feedback, effectiveProposalKind, effectiveLessonRef, fetchSimilarLessonsFn, } = args;
1148
1225
  // Inject last 1–3 rejected proposals for this ref as Reflexion-style
1149
1226
  // verbal-RL context so the LLM avoids regenerating refused proposals.
1150
- const rejectedForRef = listProposals(stash, { ref: inputRef, status: "rejected", includeArchive: true })
1227
+ const rejectedForRef = listProposalsReadOnly(stash, { ref: inputRef, status: "rejected", includeArchive: true }, options.ctx)
1151
1228
  .sort((a, b) => new Date(b.updatedAt ?? 0).getTime() - new Date(a.updatedAt ?? 0).getTime())
1152
1229
  .slice(0, MAX_REJECTED_PROPOSALS)
1153
1230
  .map((p) => ({