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
@@ -3,11 +3,13 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { loadConfig } from "../../core/config/config.js";
6
+ import { ConfigError } from "../../core/errors.js";
6
7
  import { withEngineFallback } from "../../integrations/agent/engine-fallback.js";
7
8
  import { resolveEngine } from "../../integrations/agent/engine-resolution.js";
8
- import { resolveModel } from "../../integrations/agent/model-aliases.js";
9
+ import { executionEngineDefinitionsFromConfig } from "../../integrations/agent/execution-definitions.js";
10
+ import { loadModelMap, mergeModelMapLayers, parseModelMapLayer, readInstalledModelMapText, resolveModelMapAlias, userModelMapPath, } from "../../integrations/agent/model-map.js";
9
11
  import { resolveImprovePlan } from "../improve/improve-strategies.js";
10
- import { ACTIVE_RUN_WARN_MS, TASK_FAIL_RATE_WARN, } from "./types.js";
12
+ import { ACTIVE_RUN_WARN_MS, TASK_FAIL_RATE_WARN } from "./types.js";
11
13
  function credentialAvailable(credential, env) {
12
14
  return !credential?.required || credential.names.some((name) => Boolean(env[name]?.trim()));
13
15
  }
@@ -36,8 +38,21 @@ function runConfiguredEngineProbe(checkName, engineName, config, deps) {
36
38
  packageAvailable = false;
37
39
  }
38
40
  const binary = configuredEngine.bin ?? "opencode";
39
- const version = (deps.spawnSync ?? spawnSync)(binary, ["--version"], { encoding: "utf8", timeout: 5_000 });
40
- const binaryAvailable = (version.status ?? 1) === 0;
41
+ let binaryAvailable;
42
+ try {
43
+ const version = (deps.spawnSync ?? spawnSync)(binary, ["--version"], { encoding: "utf8", timeout: 5_000 });
44
+ binaryAvailable = (version.status ?? 1) === 0;
45
+ }
46
+ catch {
47
+ return {
48
+ name: checkName,
49
+ kind: "deterministic",
50
+ status: "warn",
51
+ confidence: "high",
52
+ message: `SDK engine "${engineName}" executable availability could not be checked.`,
53
+ evidence: { engine: engineName, runtimeKind: "sdk", binaryAvailable: false },
54
+ };
55
+ }
41
56
  const fallbackEngine = configuredEngine.llmEngine ?? config.defaults?.llmEngine;
42
57
  let fallback;
43
58
  let fallbackCredential;
@@ -51,8 +66,8 @@ function runConfiguredEngineProbe(checkName, engineName, config, deps) {
51
66
  catch {
52
67
  sdkRunner = undefined;
53
68
  }
54
- if (sdkRunner?.fallbackConnection) {
55
- fallback = { kind: "llm", connection: sdkRunner.fallbackConnection };
69
+ if (sdkRunner?.fallbackConnection && fallbackEngine) {
70
+ fallback = { kind: "llm", engine: fallbackEngine, connection: sdkRunner.fallbackConnection };
56
71
  fallbackCredential = sdkRunner.fallbackCredential;
57
72
  }
58
73
  else if (fallbackEngine) {
@@ -67,9 +82,7 @@ function runConfiguredEngineProbe(checkName, engineName, config, deps) {
67
82
  fallback = undefined;
68
83
  }
69
84
  }
70
- const configuredModel = configuredEngine.model
71
- ? resolveModel(configuredEngine.model, "opencode-sdk", configuredEngine.modelAliases, config.modelAliases)
72
- : undefined;
85
+ const configuredModel = configuredEngine.model;
73
86
  const effectiveModel = sdkRunner?.profile.model ?? configuredModel ?? fallback?.connection.model;
74
87
  const fallbackCredentialAvailable = credentialAvailable(fallbackCredential, env);
75
88
  const missing = [
@@ -169,6 +182,58 @@ function runConfiguredEngineProbe(checkName, engineName, config, deps) {
169
182
  };
170
183
  }
171
184
  }
185
+ function projectEngineProbe(result, name) {
186
+ return result.name === name ? result : { ...result, name };
187
+ }
188
+ function projectSelectedEngineProbe(availability, engineName, checkName) {
189
+ const result = availability.get(engineName);
190
+ if (result)
191
+ return projectEngineProbe(result, checkName);
192
+ return {
193
+ name: checkName,
194
+ kind: "deterministic",
195
+ status: "warn",
196
+ confidence: "high",
197
+ message: `Engine "${engineName}" availability could not be checked.`,
198
+ evidence: { engine: engineName },
199
+ };
200
+ }
201
+ function unconfiguredEngineProbe(name) {
202
+ return {
203
+ name,
204
+ kind: "deterministic",
205
+ status: "unknown",
206
+ confidence: "high",
207
+ message: name === "default-llm-engine" ? "No default LLM engine is configured." : "No default engine is configured.",
208
+ };
209
+ }
210
+ function configuredEnginesProjection(engineNames, availability) {
211
+ if (engineNames.length === 0) {
212
+ return {
213
+ name: "configured-engines",
214
+ kind: "deterministic",
215
+ status: "unknown",
216
+ confidence: "high",
217
+ message: "No engines are explicitly configured.",
218
+ evidence: { engines: [] },
219
+ };
220
+ }
221
+ const engines = engineNames.map((engine) => ({
222
+ engine,
223
+ status: availability.get(engine)?.status === "pass" ? "pass" : "warn",
224
+ }));
225
+ const unavailable = engines.filter((engine) => engine.status === "warn").length;
226
+ return {
227
+ name: "configured-engines",
228
+ kind: "deterministic",
229
+ status: unavailable === 0 ? "pass" : "warn",
230
+ confidence: "high",
231
+ message: unavailable === 0
232
+ ? `All ${engines.length} explicitly configured engines are available.`
233
+ : `${unavailable} of ${engines.length} explicitly configured engines ${unavailable === 1 ? "is" : "are"} unavailable.`,
234
+ evidence: { engines },
235
+ };
236
+ }
172
237
  export function runDefaultEngineProbe(deps = {}) {
173
238
  // Probe the effective view: an install with no `defaults.engine` but a usable
174
239
  // opencode binary DOES have a working default, and reporting otherwise would
@@ -180,6 +245,38 @@ export function runDefaultLlmEngineProbe(deps = {}) {
180
245
  const config = deps.loadConfig?.() ?? loadConfig();
181
246
  return runConfiguredEngineProbe("default-llm-engine", config.defaults?.llmEngine, config, deps);
182
247
  }
248
+ /** Probe every explicitly configured engine without exposing connection or model material. */
249
+ export function runConfiguredEnginesProbe(deps = {}) {
250
+ const config = deps.loadConfig?.() ?? loadConfig();
251
+ const engineNames = Object.keys(config.engines ?? {}).sort();
252
+ const availability = new Map(engineNames.map((engine) => [engine, runConfiguredEngineProbe("configured-engine", engine, config, deps)]));
253
+ return configuredEnginesProjection(engineNames, availability);
254
+ }
255
+ /**
256
+ * Build the per-health-run availability snapshot. Each distinct selected or
257
+ * explicitly configured engine is probed once; the three public checks are
258
+ * projections of that immutable result set.
259
+ */
260
+ export function runHealthEngineProbes(deps = {}) {
261
+ const configured = deps.loadConfig?.() ?? loadConfig();
262
+ const effective = withEngineFallback(configured, deps.which).config;
263
+ const defaultEngineName = effective.defaults?.engine;
264
+ const defaultLlmEngineName = configured.defaults?.llmEngine;
265
+ const explicitEngineNames = Object.keys(configured.engines ?? {}).sort();
266
+ const probeNames = [...new Set([...explicitEngineNames, defaultEngineName, defaultLlmEngineName])]
267
+ .filter((name) => name !== undefined)
268
+ .sort();
269
+ const availability = new Map(probeNames.map((engine) => [engine, runConfiguredEngineProbe("configured-engine", engine, effective, deps)]));
270
+ return Object.freeze({
271
+ defaultEngine: defaultEngineName
272
+ ? projectSelectedEngineProbe(availability, defaultEngineName, "default-engine")
273
+ : unconfiguredEngineProbe("default-engine"),
274
+ defaultLlmEngine: defaultLlmEngineName
275
+ ? projectSelectedEngineProbe(availability, defaultLlmEngineName, "default-llm-engine")
276
+ : unconfiguredEngineProbe("default-llm-engine"),
277
+ configuredEngines: configuredEnginesProjection(explicitEngineNames, availability),
278
+ });
279
+ }
183
280
  export function runActiveImproveStrategyProbe(deps = {}) {
184
281
  const config = deps.loadConfig?.() ?? loadConfig();
185
282
  const strategyName = config.defaults?.improveStrategy ?? "default";
@@ -226,6 +323,124 @@ export function runActiveImproveStrategyProbe(deps = {}) {
226
323
  };
227
324
  }
228
325
  }
326
+ /**
327
+ * Validate the immutable installed model map and optional user overlay.
328
+ * Installed corruption is a package defect (fail); a bad optional user file
329
+ * is operator-fixable configuration (warn); absence is the normal state.
330
+ */
331
+ export function runModelMapProbe(options = {}) {
332
+ let installedText;
333
+ try {
334
+ installedText = readInstalledModelMapText(options);
335
+ mergeModelMapLayers(parseModelMapLayer(installedText, "installed models.json"));
336
+ }
337
+ catch (error) {
338
+ return {
339
+ name: "model-map-files",
340
+ kind: "deterministic",
341
+ status: "fail",
342
+ confidence: "high",
343
+ message: `Installed models.json is invalid; this AKM installation cannot resolve model aliases: ${error instanceof Error ? error.message : String(error)}`,
344
+ evidence: { installedSource: "package asset" },
345
+ };
346
+ }
347
+ try {
348
+ const loaded = loadModelMap({ ...options, installedText });
349
+ return {
350
+ name: "model-map-files",
351
+ kind: "deterministic",
352
+ status: "pass",
353
+ confidence: "high",
354
+ message: loaded.userStatus === "loaded"
355
+ ? `Installed defaults and user models.json at ${loaded.userPath} are valid.`
356
+ : "Installed model defaults are valid; no optional user models.json is present.",
357
+ evidence: {
358
+ installedSource: "package asset",
359
+ userPath: loaded.userPath,
360
+ userStatus: loaded.userStatus,
361
+ aliases: Object.keys(loaded.map.aliases).sort(),
362
+ },
363
+ };
364
+ }
365
+ catch (error) {
366
+ const hint = error instanceof ConfigError ? error.hint() : undefined;
367
+ return {
368
+ name: "model-map-files",
369
+ kind: "deterministic",
370
+ status: "warn",
371
+ confidence: "high",
372
+ message: `${error instanceof Error ? error.message : String(error)}${hint ? ` ${hint}` : ""}`,
373
+ evidence: {
374
+ installedSource: "package asset",
375
+ userPath: userModelMapPath(options.env),
376
+ userStatus: "invalid",
377
+ },
378
+ };
379
+ }
380
+ }
381
+ /**
382
+ * Check model selections owned by configured engines against the common model
383
+ * map. Unknown identifiers are deliberate exact-model pass-throughs; only an
384
+ * alias known somewhere in the map but absent for the selected engine warns.
385
+ */
386
+ export function runSelectedModelAliasesProbe(deps = {}) {
387
+ const config = deps.loadConfig?.() ?? loadConfig();
388
+ const definitions = executionEngineDefinitionsFromConfig(config);
389
+ const selected = Object.entries(definitions)
390
+ .sort(([left], [right]) => left.localeCompare(right))
391
+ .flatMap(([engine, definition]) => {
392
+ const model = definition.defaults?.model;
393
+ const modelMapKey = definition.modelMapKey ?? definition.selection.platform ?? definition.selection.name;
394
+ return typeof model === "string" ? [{ engine, alias: model, modelMapKey }] : [];
395
+ });
396
+ if (selected.length === 0) {
397
+ return {
398
+ name: "selected-model-aliases",
399
+ kind: "deterministic",
400
+ status: "unknown",
401
+ confidence: "high",
402
+ message: "No configured engines select a model.",
403
+ evidence: { checked: [], missing: [] },
404
+ };
405
+ }
406
+ let modelMap;
407
+ try {
408
+ modelMap = (deps.loadModelMap ?? loadModelMap)({ env: deps.env, installedText: deps.installedText });
409
+ }
410
+ catch {
411
+ return {
412
+ name: "selected-model-aliases",
413
+ kind: "deterministic",
414
+ status: "unknown",
415
+ confidence: "high",
416
+ message: "Configured model selections could not be checked because the model map is invalid.",
417
+ evidence: { checked: [], missing: [] },
418
+ };
419
+ }
420
+ const outcomes = selected.map(({ engine, alias, modelMapKey }) => {
421
+ try {
422
+ const resolution = resolveModelMapAlias(alias, modelMapKey, modelMap.map);
423
+ return resolution.interpretation === "alias"
424
+ ? { kind: "alias", evidence: { engine, alias, modelMapKey } }
425
+ : { kind: "exact" };
426
+ }
427
+ catch {
428
+ return { kind: "missing", evidence: { engine, alias, modelMapKey } };
429
+ }
430
+ });
431
+ const checked = outcomes.flatMap((outcome) => (outcome.kind === "exact" ? [] : [outcome.evidence]));
432
+ const missing = outcomes.flatMap((outcome) => (outcome.kind === "missing" ? [outcome.evidence] : []));
433
+ return {
434
+ name: "selected-model-aliases",
435
+ kind: "deterministic",
436
+ status: missing.length === 0 ? "pass" : "warn",
437
+ confidence: "high",
438
+ message: missing.length === 0
439
+ ? `All ${selected.length} configured model selections resolve for their selected engines.`
440
+ : `${missing.length} of ${selected.length} configured model selections ${missing.length === 1 ? "has" : "have"} no mapping for ${missing.length === 1 ? "its" : "their"} selected engine${missing.length === 1 ? "" : "s"}.`,
441
+ evidence: { checked, missing },
442
+ };
443
+ }
229
444
  /**
230
445
  * The ordered health-check registry. ORDER IS LOAD-BEARING: `akmHealth`
231
446
  * iterates this array and appends to hardChecks/advisories in sequence, so the
@@ -312,12 +527,27 @@ export const HEALTH_CHECKS = [
312
527
  {
313
528
  name: "default-engine",
314
529
  channel: "hard",
315
- run: () => runDefaultEngineProbe(),
530
+ run: (ctx) => ctx.engineProbes.defaultEngine,
531
+ },
532
+ {
533
+ name: "model-map-files",
534
+ channel: "hard",
535
+ run: () => runModelMapProbe(),
536
+ },
537
+ {
538
+ name: "selected-model-aliases",
539
+ channel: "hard",
540
+ run: () => runSelectedModelAliasesProbe(),
316
541
  },
317
542
  {
318
543
  name: "default-llm-engine",
319
544
  channel: "hard",
320
- run: () => runDefaultLlmEngineProbe(),
545
+ run: (ctx) => ctx.engineProbes.defaultLlmEngine,
546
+ },
547
+ {
548
+ name: "configured-engines",
549
+ channel: "hard",
550
+ run: (ctx) => ctx.engineProbes.configuredEngines,
321
551
  },
322
552
  {
323
553
  name: "active-improve-strategy",
@@ -409,24 +639,6 @@ export const HEALTH_CHECKS = [
409
639
  };
410
640
  },
411
641
  },
412
- {
413
- // session-log-failures: demoted to informational — the ERROR_PATTERNS regex
414
- // scans pre-LLM session text and produces false positives on diagnostic
415
- // conversation. It does not gate the real extraction pipeline (akmExtract).
416
- // Never triggers warn; kept for backward-compat visibility only.
417
- name: "session-log-failures",
418
- channel: "advisory",
419
- run: (ctx) => ({
420
- name: "session-log-failures",
421
- kind: "heuristic",
422
- status: "pass",
423
- confidence: "low",
424
- message: ctx.sessionLogEntries.length === 0
425
- ? "No repeated external session-log failure patterns were detected."
426
- : `${ctx.sessionLogEntries.length} raw session-log keyword match(es) detected (pre-LLM, informational only).`,
427
- evidence: { candidates: ctx.sessionLogEntries.slice(0, 5) },
428
- }),
429
- },
430
642
  {
431
643
  name: "session-extraction",
432
644
  channel: "advisory",
@@ -369,20 +369,6 @@ function renderActionItems(vm) {
369
369
  remedy: "akm config list",
370
370
  });
371
371
  }
372
- // Session-log notes (informational, lowest priority).
373
- if (vm.sessionLogAdvisories.length > 0) {
374
- const patterns = vm.sessionLogAdvisories
375
- .slice(0, 6)
376
- .map((p) => `<li>${esc(p.topic)}</li>`)
377
- .join("");
378
- pushItem({
379
- key: "session-log-notes",
380
- prio: "P3",
381
- cls: "warn",
382
- title: `${vm.sessionLogAdvisories.length} session-log note(s) (informational)`,
383
- descHtml: `<ul style="margin:4px 0 0 16px;padding:0;">${patterns}</ul>`,
384
- });
385
- }
386
372
  items.sort((a, b) => PRIO_RANK[a.prio] - PRIO_RANK[b.prio]);
387
373
  return items.length > 0
388
374
  ? items.map(actionItemCard).join("\n")
@@ -503,6 +503,5 @@ export function buildHealthReportViewModel(result, opts) {
503
503
  sliceCandidates: computeSliceCandidates(opts.window),
504
504
  distillReasons,
505
505
  advisories: result.advisories,
506
- sessionLogAdvisories: result.sessionLogAdvisories,
507
506
  };
508
507
  }
@@ -17,14 +17,13 @@
17
17
  import { MAX_CONFIG_FILE_BYTES, readTextFileWithLimit } from "../../core/common.js";
18
18
  import { CURRENT_CONFIG_VERSION } from "../../core/config/config-schema.js";
19
19
  import { compareConfigVersion } from "../../core/config/config-version.js";
20
+ import { formatRegistryUrl } from "../../core/registry-url.js";
20
21
  /**
21
22
  * `binary-config-skew` (08-F3): warn when config.json carries a configVersion
22
23
  * NEWER than (or unorderable against) this binary's CURRENT_CONFIG_VERSION —
23
24
  * i.e. a newer/foreign akm wrote the shared config and this install is stale.
24
- * That is exactly the state where auto-migration is skipped (downgrade
25
- * protection) and the proven multi-install incident class begins. Silent for
26
- * same/older versions (auto-migration handles those) and unreadable configs
27
- * (config loading surfaces its own errors).
25
+ * That is the proven multi-install incident class. Silent for current or older
26
+ * versions and unreadable configs (config loading surfaces its own errors).
28
27
  */
29
28
  export function collectConfigSkewAdvisory(configPath) {
30
29
  let raw;
@@ -45,8 +44,8 @@ export function collectConfigSkewAdvisory(configPath) {
45
44
  status: "warn",
46
45
  confidence: "high",
47
46
  message: `config.json has configVersion ${JSON.stringify(onDisk)} but this binary knows ${CURRENT_CONFIG_VERSION} — ` +
48
- "a newer akm wrote the shared config, so this install is stale and auto-migration is skipped " +
49
- "(downgrade protection). Upgrade this install; do not keep a stale binary against the shared config/DBs.",
47
+ "a newer akm wrote the shared config, so this install is stale. Upgrade this install; do not keep a stale " +
48
+ "binary against the shared config/DBs.",
50
49
  evidence: { onDiskConfigVersion: onDisk, binaryConfigVersion: CURRENT_CONFIG_VERSION },
51
50
  };
52
51
  }
@@ -64,7 +63,7 @@ export function collectEgressAdvisory(config) {
64
63
  for (const reg of config.registries ?? []) {
65
64
  if (reg.enabled === false || !reg.url)
66
65
  continue;
67
- endpoints.push(`registry ${reg.name ?? "(unnamed)"}: ${reg.url}`);
66
+ endpoints.push(`registry ${reg.name ?? "(unnamed)"}: ${formatRegistryUrl(reg.url)}`);
68
67
  }
69
68
  for (const [key, bundle] of Object.entries(config.bundles ?? {})) {
70
69
  if (!bundle)
@@ -16,7 +16,6 @@
16
16
  * - `./types-improve` — the {@link ImproveHealthMetrics} accumulator and its
17
17
  * WS-5 sub-rollups (coverage, perf telemetry, degradation, enrichment
18
18
  * minting).
19
- * - `./types-session-log` — {@link SessionLogAdvisory}.
20
19
  * - `./types-runs` — {@link ImproveRunSummary} (`--group-by run`).
21
20
  * - `./types-windows` — {@link WindowSpec}/{@link WindowResult}/{@link DeltaEntry}
22
21
  * (`--window-compare`/`--windows`).
@@ -27,5 +26,4 @@ export * from "./types-improve.js";
27
26
  export * from "./types-metrics.js";
28
27
  export * from "./types-result.js";
29
28
  export * from "./types-runs.js";
30
- export * from "./types-session-log.js";
31
29
  export * from "./types-windows.js";
@@ -10,14 +10,14 @@ import { readEvents } from "../core/events.js";
10
10
  import { listTxnJournalsTolerant, TXN_SWEEP_GRACE_MS } from "../core/fs-txn.js";
11
11
  import { openLogsDatabase } from "../core/logs-db.js";
12
12
  import { classifyPathAccess, describeInaccessiblePath } from "../core/path-access.js";
13
- import { getConfigPath, getDataDir, getStateDbPathInDataDir } from "../core/paths.js";
13
+ import { getConfigPath, getDataDir, getDbPath, getStateDbPathInDataDir } from "../core/paths.js";
14
14
  import { listExistingTableNames, openStateDatabase } from "../core/state-db.js";
15
15
  import { DURATION_UNITS, parseDuration, parseSinceToIso } from "../core/time.js";
16
16
  import { readSemanticStatus } from "../indexer/search/semantic-status.js";
17
- import { getExecutionLogCandidates } from "../integrations/session-logs/index.js";
17
+ import { closeDatabase, openReadonlyExistingDatabase } from "../storage/repositories/index-connection.js";
18
18
  import { queryTaskHistory } from "../storage/repositories/task-history-repository.js";
19
19
  import { collectImproveAdvisories } from "./health/advisories.js";
20
- import { HEALTH_CHECKS } from "./health/checks.js";
20
+ import { HEALTH_CHECKS, runHealthEngineProbes } from "./health/checks.js";
21
21
  import { buildImproveSkipSummary, computeWallTimeStats, parseTaskMetadata, roundRate, summarizeImproveCompleted, summarizeImproveRuns, } from "./health/improve-metrics.js";
22
22
  import { emptyLlmUsageAggregate, readLlmUsageAggregate } from "./health/llm-usage.js";
23
23
  import { computeDegradationMetrics, computeDenominatorFixedCoverage, computeEnrichmentMintingRollup, probeStateDbRoundTrip, } from "./health/metrics.js";
@@ -235,6 +235,9 @@ function gatherImproveSummaryPhase(db, stateDbPath, since, now) {
235
235
  */
236
236
  function gatherAncillaryAdvisories(db, stateDbPath, since, improveSummary, options, egressConfigView) {
237
237
  const advisories = [...collectImproveAdvisories(db, stateDbPath, since, improveSummary)];
238
+ const indexStateMismatch = detectIndexStateGenerationMismatch(db);
239
+ if (indexStateMismatch)
240
+ advisories.push(indexStateMismatch);
238
241
  // 08-F1: surface a `stash-git-exposure` advisory when env/secret assets are
239
242
  // git-tracked AND a remote is configured (the leak moment). Best-effort.
240
243
  // Cheap guard: only shell out to git when the stash has its OWN `.git` (or a
@@ -268,19 +271,64 @@ function gatherAncillaryAdvisories(db, stateDbPath, since, improveSummary, optio
268
271
  }
269
272
  return advisories;
270
273
  }
271
- /** Execution-log-derived session advisories. Best-effort: any failure yields an empty list. */
272
- function gatherSessionLogAdvisories(since, now, getExecutionLogCandidatesFn) {
274
+ /**
275
+ * Detect the durable signature of an interrupted cross-database update.
276
+ *
277
+ * `usage_events.entry_ref` is the stable identity while `entry_id` names the
278
+ * current, regenerable index row. A linked event whose id is absent or resolves
279
+ * to a different ref means index.db and state.db describe adjacent generations.
280
+ * Legacy/bare refs and deliberately detached rows are excluded. The scan is
281
+ * streaming and keeps only a bounded evidence sample so health cannot mirror
282
+ * either database into the JS heap.
283
+ *
284
+ * Best-effort by design: an absent/unreadable/incompatible index has its own
285
+ * diagnostics and must not make the state health path throw.
286
+ */
287
+ function detectIndexStateGenerationMismatch(stateDb) {
288
+ let indexDb;
273
289
  try {
274
- const sinceDays = Math.max(0, Math.ceil((now() - new Date(since).getTime()) / (24 * 60 * 60 * 1000)));
275
- return getExecutionLogCandidatesFn(sinceDays).map((entry) => ({
276
- topic: entry.topic,
277
- frequency: entry.frequency,
278
- source: entry.source,
279
- isFailurePattern: entry.isFailurePattern,
280
- }));
290
+ indexDb = openReadonlyExistingDatabase(getDbPath());
291
+ if (!indexDb)
292
+ return undefined;
293
+ const byId = indexDb.prepare("SELECT item_ref FROM entries WHERE id = ?");
294
+ const rows = stateDb
295
+ .prepare("SELECT DISTINCT entry_id, entry_ref FROM usage_events " +
296
+ "WHERE entry_id IS NOT NULL AND entry_ref IS NOT NULL AND instr(entry_ref, '//') > 0")
297
+ .iterate();
298
+ let mismatches = 0;
299
+ const sample = [];
300
+ for (const row of rows) {
301
+ const indexedRef = byId.get(row.entry_id)?.item_ref ?? null;
302
+ if (indexedRef === row.entry_ref)
303
+ continue;
304
+ mismatches += 1;
305
+ if (sample.length < 5)
306
+ sample.push({ entryId: row.entry_id, entryRef: row.entry_ref, indexedRef });
307
+ }
308
+ if (mismatches === 0)
309
+ return undefined;
310
+ return {
311
+ name: "index-state-generation",
312
+ kind: "deterministic",
313
+ status: "warn",
314
+ confidence: "high",
315
+ message: `${mismatches} durable usage link(s) disagree with the current searchable index generation. ` +
316
+ "Stop concurrent writers and run 'akm index --full' to relink state to the current index.",
317
+ evidence: { mismatches, sample },
318
+ };
281
319
  }
282
320
  catch {
283
- return [];
321
+ return undefined;
322
+ }
323
+ finally {
324
+ if (indexDb) {
325
+ try {
326
+ closeDatabase(indexDb);
327
+ }
328
+ catch {
329
+ // Best-effort advisory: a close failure must not abort health.
330
+ }
331
+ }
284
332
  }
285
333
  }
286
334
  /**
@@ -370,7 +418,6 @@ function unreadableStateDbReport(detail, options) {
370
418
  llmUsage: emptyLlmUsageAggregate(),
371
419
  },
372
420
  improve: summarizeImproveCompleted([]),
373
- sessionLogAdvisories: [],
374
421
  };
375
422
  }
376
423
  export function akmHealth(options = {}) {
@@ -380,7 +427,6 @@ export function akmHealth(options = {}) {
380
427
  const stateDbPath = options.stateDbPath ?? getStateDbPathInDataDir();
381
428
  const hardChecks = [];
382
429
  const advisories = [];
383
- const getExecutionLogCandidatesFn = options.getExecutionLogCandidatesFn ?? getExecutionLogCandidates;
384
430
  // #791: an UNREADABLE state.db is the one failure `akm health` most needs to
385
431
  // be able to report, because it is the command an operator runs to find out
386
432
  // why everything else is behaving oddly. Dying here with exit 78 meant health
@@ -414,7 +460,7 @@ export function akmHealth(options = {}) {
414
460
  const { semanticStatus, semanticSearchMode, embeddingEndpoint, egressConfigView } = gatherSemanticConfigPhase();
415
461
  const { improveSummary } = gatherImproveSummaryPhase(db, stateDbPath, since, now);
416
462
  advisories.push(...gatherAncillaryAdvisories(db, stateDbPath, since, improveSummary, options, egressConfigView));
417
- const sessionLogEntries = gatherSessionLogAdvisories(since, now, getExecutionLogCandidatesFn);
463
+ const engineProbes = runHealthEngineProbes();
418
464
  // Run the ordered health-check registry. Each check projects the shared
419
465
  // context computed above into one HealthCheckResult; `channel` routes it to
420
466
  // hardChecks or advisories. Declaration order in HEALTH_CHECKS is the
@@ -437,9 +483,9 @@ export function akmHealth(options = {}) {
437
483
  semanticStatus,
438
484
  semanticSearchMode,
439
485
  embeddingEndpoint,
440
- sessionLogEntries,
441
486
  sessionExtraction: improveSummary.sessionExtraction,
442
487
  autoAccept: improveSummary.autoAccept,
488
+ engineProbes,
443
489
  };
444
490
  for (const check of HEALTH_CHECKS) {
445
491
  const result = check.run(checkContext);
@@ -475,7 +521,6 @@ export function akmHealth(options = {}) {
475
521
  advisories,
476
522
  metrics,
477
523
  improve: improveSummary,
478
- sessionLogAdvisories: sessionLogEntries,
479
524
  ...(runs ? { runs } : {}),
480
525
  ...(windowResults ? { windows: windowResults } : {}),
481
526
  ...(deltas ? { deltas } : {}),
@@ -163,10 +163,9 @@ export function refreshCanarySet(stateDb, indexDb, cfg) {
163
163
  * Name-free content fingerprint text for entropy metrics. The indexed
164
164
  * search_text EMBEDS the (unique) entry name, which would pin the
165
165
  * distinct-content ratio at 1.0 forever; convergence shows up in the
166
- * description/tags/heading fields, so those are what get hashed. (The raw body
167
- * is not in the index at all search_text covers metadata + TOC headings —
168
- * so v1 entropy is measured over the searchable surface, which is also what
169
- * generic merged assets converge on.)
166
+ * description/tags/heading fields, so those are what get hashed. Bounded body
167
+ * content is searchable but deliberately excluded from this fingerprint: the
168
+ * detector measures the structured surface generic merged assets converge on.
170
169
  */
171
170
  function contentFingerprint(entry) {
172
171
  const parts = [entry.description ?? "", (entry.tags ?? []).join(" "), (entry.toc ?? []).map((h) => h.text).join(" ")];
@@ -262,9 +261,9 @@ export function computeCycleMetrics(stateDb, indexDb, args) {
262
261
  contentHashes.add(normHash(fingerprint));
263
262
  if ((e.entry.generation ?? 0) > maxGeneration)
264
263
  overGeneration++;
265
- learningTexts.push({ key: e.entryKey, text: fingerprint });
264
+ learningTexts.push({ key: e.itemRef, text: fingerprint });
266
265
  }
267
- // Deterministic diversity sample: sort by entryKey, take every ⌈N/cap⌉-th row.
266
+ // Deterministic diversity sample: sort by item ref, take every ⌈N/cap⌉-th row.
268
267
  learningTexts.sort((a, b) => (a.key < b.key ? -1 : 1));
269
268
  const step = Math.max(1, Math.ceil(learningTexts.length / DIVERSITY_SAMPLE_CAP));
270
269
  let diversitySum = 0;