akm-cli 0.9.0-beta.6 → 0.9.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/README.md +12 -4
  3. package/dist/akm +38 -0
  4. package/dist/akm-migrate-storage +38 -0
  5. package/dist/assets/help/help-improve.md +9 -6
  6. package/dist/assets/hints/cli-hints-full.md +6 -5
  7. package/dist/assets/profiles/default.json +9 -4
  8. package/dist/assets/profiles/frequent.json +1 -1
  9. package/dist/assets/profiles/memory-focus.json +1 -1
  10. package/dist/assets/profiles/proactive-maintenance.json +25 -0
  11. package/dist/assets/profiles/quick.json +1 -1
  12. package/dist/assets/profiles/recombine-only.json +21 -0
  13. package/dist/assets/profiles/reflect-distill.json +30 -0
  14. package/dist/assets/profiles/synthesize.json +15 -0
  15. package/dist/assets/profiles/thorough.json +1 -1
  16. package/dist/assets/prompts/consolidate-system.md +23 -0
  17. package/dist/assets/prompts/contradiction-judge.md +33 -0
  18. package/dist/assets/prompts/distill-knowledge-system.md +22 -0
  19. package/dist/assets/prompts/distill-lesson-system.md +36 -0
  20. package/dist/assets/prompts/extract-session.md +11 -3
  21. package/dist/assets/prompts/graph-extract-system.md +1 -0
  22. package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
  23. package/dist/assets/prompts/memory-infer-system.md +1 -0
  24. package/dist/assets/prompts/memory-infer-user.md +5 -0
  25. package/dist/assets/prompts/metadata-enhance-system.md +1 -0
  26. package/dist/assets/prompts/procedural-system.md +44 -0
  27. package/dist/assets/prompts/recombine-system.md +40 -0
  28. package/dist/assets/prompts/staleness-detect-system.md +6 -0
  29. package/dist/assets/prompts/validate-summary-judge.md +1 -0
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
  39. package/dist/assets/templates/html/health.html +281 -111
  40. package/dist/assets/wiki/ingest-workflow-template.md +45 -16
  41. package/dist/assets/wiki/schema-template.md +4 -4
  42. package/dist/cli/clack.js +56 -0
  43. package/dist/cli/config-migrate.js +7 -1
  44. package/dist/cli/confirm.js +1 -1
  45. package/dist/cli/parse-args.js +46 -1
  46. package/dist/cli/shared.js +28 -0
  47. package/dist/cli.js +25 -14
  48. package/dist/commands/agent/agent-dispatch.js +3 -2
  49. package/dist/commands/agent/agent-support.js +0 -7
  50. package/dist/commands/agent/contribute-cli.js +26 -7
  51. package/dist/commands/config-cli.js +26 -13
  52. package/dist/commands/env/child-env.js +47 -0
  53. package/dist/commands/env/env-cli.js +220 -227
  54. package/dist/commands/env/env.js +14 -67
  55. package/dist/commands/env/secret-cli.js +140 -138
  56. package/dist/commands/feedback-cli.js +153 -147
  57. package/dist/commands/graph/graph-cli.js +5 -13
  58. package/dist/commands/graph/graph.js +76 -72
  59. package/dist/commands/health/advisories.js +151 -0
  60. package/dist/commands/health/checks.js +103 -16
  61. package/dist/commands/health/html-report.js +447 -81
  62. package/dist/commands/health/improve-metrics.js +771 -0
  63. package/dist/commands/health/llm-usage.js +65 -0
  64. package/dist/commands/health/md-report.js +103 -0
  65. package/dist/commands/health/metrics.js +278 -0
  66. package/dist/commands/health/stash-exposure.js +46 -0
  67. package/dist/commands/health/surfaces.js +216 -0
  68. package/dist/commands/health/task-runs.js +135 -0
  69. package/dist/commands/health/types.js +26 -0
  70. package/dist/commands/health/windows.js +195 -0
  71. package/dist/commands/health.js +91 -1083
  72. package/dist/commands/improve/anti-collapse.js +170 -0
  73. package/dist/commands/improve/calibration.js +161 -0
  74. package/dist/commands/improve/collapse-detector.js +421 -0
  75. package/dist/commands/improve/consolidate/chunking.js +141 -0
  76. package/dist/commands/improve/consolidate/eligibility.js +64 -0
  77. package/dist/commands/improve/consolidate/merge.js +145 -0
  78. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  79. package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
  80. package/dist/commands/improve/consolidate.js +1313 -1278
  81. package/dist/commands/improve/dedup.js +482 -0
  82. package/dist/commands/improve/distill/content-repair.js +202 -0
  83. package/dist/commands/improve/distill/promote-memory.js +229 -0
  84. package/dist/commands/improve/distill/quality-gate.js +236 -0
  85. package/dist/commands/improve/distill-guards.js +127 -0
  86. package/dist/commands/improve/distill-promotion-policy.js +826 -167
  87. package/dist/commands/improve/distill.js +243 -599
  88. package/dist/commands/improve/eligibility.js +434 -0
  89. package/dist/commands/improve/encoding-salience.js +205 -0
  90. package/dist/commands/improve/extract-cli.js +179 -59
  91. package/dist/commands/improve/extract-prompt.js +55 -4
  92. package/dist/commands/improve/extract-watch.js +140 -0
  93. package/dist/commands/improve/extract.js +409 -43
  94. package/dist/commands/improve/feedback-valence.js +54 -0
  95. package/dist/commands/improve/hot-probation.js +45 -0
  96. package/dist/commands/improve/improve-auto-accept.js +160 -7
  97. package/dist/commands/improve/improve-cli.js +115 -73
  98. package/dist/commands/improve/improve-profiles.js +32 -8
  99. package/dist/commands/improve/improve-result-file.js +15 -25
  100. package/dist/commands/improve/improve-session.js +58 -0
  101. package/dist/commands/improve/improve.js +510 -2537
  102. package/dist/commands/improve/locks.js +154 -0
  103. package/dist/commands/improve/loop-stages.js +1100 -0
  104. package/dist/commands/improve/memory/memory-belief.js +14 -15
  105. package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
  106. package/dist/commands/improve/memory/memory-improve.js +27 -27
  107. package/dist/commands/improve/outcome-loop.js +270 -0
  108. package/dist/commands/improve/preparation.js +2002 -0
  109. package/dist/commands/improve/proactive-maintenance.js +115 -0
  110. package/dist/commands/improve/procedural.js +398 -0
  111. package/dist/commands/improve/recombine.js +818 -0
  112. package/dist/commands/improve/reflect-noise.js +0 -0
  113. package/dist/commands/improve/reflect.js +212 -45
  114. package/dist/commands/improve/salience.js +455 -0
  115. package/dist/commands/improve/schema-similarity-gate.js +168 -0
  116. package/dist/commands/improve/shared.js +51 -0
  117. package/dist/commands/improve/triage.js +93 -0
  118. package/dist/commands/lint/agent-linter.js +19 -24
  119. package/dist/commands/lint/base-linter.js +173 -60
  120. package/dist/commands/lint/command-linter.js +19 -24
  121. package/dist/commands/lint/env-key-rules.js +38 -1
  122. package/dist/commands/lint/fact-linter.js +39 -0
  123. package/dist/commands/lint/index.js +31 -13
  124. package/dist/commands/lint/memory-linter.js +1 -1
  125. package/dist/commands/lint/registry.js +7 -2
  126. package/dist/commands/lint/task-linter.js +3 -3
  127. package/dist/commands/lint/workflow-linter.js +26 -1
  128. package/dist/commands/observability-cli.js +4 -4
  129. package/dist/commands/proposal/drain-policies.js +13 -4
  130. package/dist/commands/proposal/drain.js +45 -51
  131. package/dist/commands/proposal/legacy-import.js +115 -0
  132. package/dist/commands/proposal/proposal-cli.js +24 -34
  133. package/dist/commands/proposal/proposal.js +7 -1
  134. package/dist/commands/proposal/propose.js +8 -3
  135. package/dist/commands/proposal/repository.js +829 -0
  136. package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
  137. package/dist/commands/proposal/validators/proposals.js +93 -882
  138. package/dist/commands/read/curate.js +419 -103
  139. package/dist/commands/read/knowledge.js +10 -3
  140. package/dist/commands/read/remember-cli.js +133 -138
  141. package/dist/commands/read/search-cli.js +15 -8
  142. package/dist/commands/read/search.js +22 -11
  143. package/dist/commands/read/show.js +106 -14
  144. package/dist/commands/registry-cli.js +76 -87
  145. package/dist/commands/remember.js +11 -12
  146. package/dist/commands/sources/add-cli.js +91 -95
  147. package/dist/commands/sources/history.js +1 -1
  148. package/dist/commands/sources/init.js +66 -18
  149. package/dist/commands/sources/installed-stashes.js +11 -3
  150. package/dist/commands/sources/schema-repair.js +44 -46
  151. package/dist/commands/sources/self-update.js +2 -2
  152. package/dist/commands/sources/source-add.js +7 -3
  153. package/dist/commands/sources/sources-cli.js +3 -3
  154. package/dist/commands/sources/stash-cli.js +29 -41
  155. package/dist/commands/sources/stash-skeleton.js +57 -8
  156. package/dist/commands/tasks/default-tasks.js +15 -2
  157. package/dist/commands/tasks/tasks-cli.js +20 -29
  158. package/dist/commands/tasks/tasks.js +39 -11
  159. package/dist/commands/wiki-cli.js +23 -38
  160. package/dist/commands/workflow-cli.js +15 -1
  161. package/dist/core/asset/asset-registry.js +3 -1
  162. package/dist/core/asset/asset-spec.js +21 -4
  163. package/dist/core/asset/frontmatter.js +188 -167
  164. package/dist/core/asset/markdown.js +8 -0
  165. package/dist/core/authoring-rules.js +92 -0
  166. package/dist/core/common.js +4 -23
  167. package/dist/core/concurrent.js +10 -1
  168. package/dist/core/config/config-io.js +10 -1
  169. package/dist/core/config/config-migration.js +18 -40
  170. package/dist/core/config/config-schema.js +389 -58
  171. package/dist/core/config/config-types.js +3 -3
  172. package/dist/core/config/config.js +67 -22
  173. package/dist/core/deep-merge.js +38 -0
  174. package/dist/core/errors.js +1 -0
  175. package/dist/core/eval/rank-metrics.js +113 -0
  176. package/dist/core/events.js +4 -7
  177. package/dist/core/improve-types.js +47 -8
  178. package/dist/core/logs-db.js +14 -75
  179. package/dist/core/parse.js +36 -16
  180. package/dist/core/paths.js +21 -18
  181. package/dist/core/standards/resolve-standards-context.js +87 -0
  182. package/dist/core/standards/resolve-stash-standards.js +99 -0
  183. package/dist/core/standards/resolve-type-conventions.js +66 -0
  184. package/dist/core/state/migrations.js +770 -0
  185. package/dist/core/state-db.js +142 -1091
  186. package/dist/core/structured.js +69 -0
  187. package/dist/core/time.js +53 -0
  188. package/dist/core/warn.js +21 -0
  189. package/dist/core/write-source.js +37 -0
  190. package/dist/indexer/db/db.js +356 -780
  191. package/dist/indexer/db/entry-mapper.js +41 -0
  192. package/dist/indexer/db/graph-db.js +129 -86
  193. package/dist/indexer/db/llm-cache.js +2 -2
  194. package/dist/indexer/db/schema.js +516 -0
  195. package/dist/indexer/ensure-index.js +103 -24
  196. package/dist/indexer/feedback/utility-policy.js +75 -0
  197. package/dist/indexer/graph/graph-boost.js +51 -41
  198. package/dist/indexer/graph/graph-extraction.js +207 -4
  199. package/dist/indexer/index-writer-lock.js +106 -0
  200. package/dist/indexer/index-written-assets.js +105 -0
  201. package/dist/indexer/indexer.js +291 -310
  202. package/dist/indexer/passes/dir-staleness.js +114 -0
  203. package/dist/indexer/passes/memory-inference.js +13 -5
  204. package/dist/indexer/passes/metadata.js +20 -0
  205. package/dist/indexer/read-preflight.js +23 -0
  206. package/dist/indexer/search/db-search.js +89 -13
  207. package/dist/indexer/search/fts-query.js +51 -0
  208. package/dist/indexer/search/ranking-contributors.js +95 -9
  209. package/dist/indexer/search/ranking.js +79 -3
  210. package/dist/indexer/search/search-fields.js +6 -0
  211. package/dist/indexer/search/search-source.js +32 -21
  212. package/dist/indexer/search/semantic-status.js +4 -0
  213. package/dist/indexer/walk/matchers.js +9 -0
  214. package/dist/indexer/walk/walker.js +21 -13
  215. package/dist/integrations/agent/builders.js +39 -13
  216. package/dist/integrations/agent/config.js +20 -59
  217. package/dist/integrations/agent/detect.js +9 -0
  218. package/dist/integrations/agent/index.js +3 -19
  219. package/dist/integrations/agent/model-aliases.js +7 -2
  220. package/dist/integrations/agent/profiles.js +7 -1
  221. package/dist/integrations/agent/prompts.js +75 -9
  222. package/dist/integrations/agent/runner-dispatch.js +59 -0
  223. package/dist/integrations/agent/runner.js +13 -9
  224. package/dist/integrations/agent/spawn.js +69 -67
  225. package/dist/integrations/harnesses/claude/agent-builder.js +1 -1
  226. package/dist/integrations/harnesses/claude/index.js +2 -0
  227. package/dist/integrations/harnesses/claude/session-log.js +11 -1
  228. package/dist/integrations/harnesses/index.js +2 -3
  229. package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
  230. package/dist/integrations/harnesses/opencode/index.js +2 -0
  231. package/dist/integrations/harnesses/opencode/session-log.js +173 -3
  232. package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
  233. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +98 -17
  234. package/dist/integrations/harnesses/types.js +1 -0
  235. package/dist/integrations/session-logs/index.js +16 -0
  236. package/dist/llm/call-ai.js +2 -2
  237. package/dist/llm/client.js +57 -15
  238. package/dist/llm/embedder.js +67 -4
  239. package/dist/llm/embedders/cache.js +3 -1
  240. package/dist/llm/embedders/deterministic.js +66 -0
  241. package/dist/llm/embedders/local.js +73 -3
  242. package/dist/llm/feature-gate.js +16 -15
  243. package/dist/llm/graph-extract.js +67 -44
  244. package/dist/llm/memory-infer-impl.js +138 -0
  245. package/dist/llm/memory-infer.js +1 -127
  246. package/dist/llm/metadata-enhance.js +44 -31
  247. package/dist/llm/structured-call.js +49 -0
  248. package/dist/migrate-storage-node.mjs +8 -0
  249. package/dist/output/context.js +5 -5
  250. package/dist/output/renderers.js +85 -14
  251. package/dist/output/shapes/curate.js +14 -2
  252. package/dist/output/shapes/helpers.js +0 -3
  253. package/dist/output/shapes/passthrough.js +2 -1
  254. package/dist/output/text/helpers.js +29 -1
  255. package/dist/output/text/workflow.js +1 -0
  256. package/dist/registry/providers/skills-sh.js +21 -147
  257. package/dist/registry/providers/static-index.js +15 -157
  258. package/dist/registry/resolve.js +27 -9
  259. package/dist/runtime.js +25 -1
  260. package/dist/scripts/migrate-storage.js +2718 -2354
  261. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +891 -597
  262. package/dist/setup/detect.js +9 -0
  263. package/dist/setup/legacy-config.js +106 -0
  264. package/dist/setup/prompt.js +57 -0
  265. package/dist/setup/providers.js +14 -0
  266. package/dist/setup/registry-stash-loader.js +12 -0
  267. package/dist/setup/semantic-assets.js +124 -0
  268. package/dist/setup/setup.js +52 -1614
  269. package/dist/setup/steps/connection.js +734 -0
  270. package/dist/setup/steps/output.js +31 -0
  271. package/dist/setup/steps/platforms.js +124 -0
  272. package/dist/setup/steps/semantic.js +27 -0
  273. package/dist/setup/steps/sources.js +222 -0
  274. package/dist/setup/steps/stashdir.js +42 -0
  275. package/dist/setup/steps/tasks.js +152 -0
  276. package/dist/sources/include.js +6 -2
  277. package/dist/sources/providers/filesystem.js +0 -1
  278. package/dist/sources/providers/git-install.js +210 -0
  279. package/dist/sources/providers/git-provider.js +234 -0
  280. package/dist/sources/providers/git-stash.js +248 -0
  281. package/dist/sources/providers/git.js +10 -661
  282. package/dist/sources/providers/npm.js +2 -6
  283. package/dist/sources/providers/provider-utils.js +13 -7
  284. package/dist/sources/providers/sync-from-ref.js +9 -1
  285. package/dist/sources/providers/tar-utils.js +16 -8
  286. package/dist/sources/providers/website.js +9 -5
  287. package/dist/sources/website-ingest.js +187 -29
  288. package/dist/sources/wiki-fetchers/registry.js +53 -0
  289. package/dist/sources/wiki-fetchers/youtube.js +239 -0
  290. package/dist/storage/database.js +45 -10
  291. package/dist/storage/managed-db.js +82 -0
  292. package/dist/storage/repositories/canaries-repository.js +107 -0
  293. package/dist/storage/repositories/consolidation-repository.js +38 -0
  294. package/dist/storage/repositories/embeddings-repository.js +72 -0
  295. package/dist/storage/repositories/events-repository.js +187 -0
  296. package/dist/storage/repositories/extract-sessions-repository.js +96 -0
  297. package/dist/storage/repositories/improve-runs-repository.js +146 -0
  298. package/dist/storage/repositories/index-db.js +14 -8
  299. package/dist/storage/repositories/proposals-repository.js +220 -0
  300. package/dist/storage/repositories/recombine-repository.js +213 -0
  301. package/dist/storage/repositories/registry-cache.js +93 -0
  302. package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
  303. package/dist/storage/repositories/task-history-repository.js +93 -0
  304. package/dist/storage/sqlite-pragmas.js +146 -0
  305. package/dist/tasks/backends/cron.js +1 -1
  306. package/dist/tasks/backends/index.js +9 -0
  307. package/dist/tasks/backends/launchd.js +1 -1
  308. package/dist/tasks/backends/schtasks.js +1 -1
  309. package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
  310. package/dist/tasks/runner.js +15 -13
  311. package/dist/text-import-hook.mjs +0 -0
  312. package/dist/wiki/wiki.js +52 -11
  313. package/dist/workflows/cli.js +1 -0
  314. package/dist/workflows/db.js +3 -4
  315. package/dist/workflows/runtime/runs.js +43 -118
  316. package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
  317. package/dist/workflows/validate-summary.js +2 -7
  318. package/docs/README.md +69 -18
  319. package/docs/data-and-telemetry.md +5 -4
  320. package/docs/migration/release-notes/0.7.0.md +1 -1
  321. package/docs/migration/release-notes/0.9.0.md +39 -0
  322. package/package.json +10 -10
  323. package/dist/assets/tasks/core/update-stashes.yml +0 -4
  324. package/dist/commands/db-cli.js +0 -23
  325. package/dist/indexer/db/db-backup.js +0 -376
  326. package/dist/indexer/passes/staleness-detect.js +0 -488
@@ -0,0 +1,151 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Improve-pipeline advisories for `akm health`: projects the computed
6
+ * {@link ImproveHealthMetrics} plus a few direct event reads into the
7
+ * ordered advisory list.
8
+ */
9
+ import { readEvents } from "../../core/events.js";
10
+ import { getLatestCycleMetrics } from "../../storage/repositories/canaries-repository.js";
11
+ import { ENRICHMENT_MINTED_FAIL_SHARE, ENRICHMENT_MINTED_WARN_SHARE, } from "./types.js";
12
+ /**
13
+ * Build the improve-pipeline advisories for the health window from the already
14
+ * computed {@link ImproveHealthMetrics} plus a few direct event reads. Pure
15
+ * projection of state → advisories; emission order is preserved so the health
16
+ * report is byte-identical to the previous inline construction.
17
+ */
18
+ export function collectImproveAdvisories(db, stateDbPath, since, improveSummary) {
19
+ const advisories = [];
20
+ // WS-2 proxy-adequacy tripwire: surface any outcome_proxy_inverted events
21
+ // in the health window as an advisory so operators know when the 0.10+
22
+ // rich in-session signal is no longer deferrable.
23
+ const proxyInvertedEvents = readEvents({ since, type: "outcome_proxy_inverted" }, { dbPath: stateDbPath }).events;
24
+ if (proxyInvertedEvents.length > 0) {
25
+ const lastEvent = proxyInvertedEvents[proxyInvertedEvents.length - 1];
26
+ const correlation = typeof lastEvent.metadata?.correlation === "number" ? lastEvent.metadata.correlation.toFixed(3) : "unknown";
27
+ advisories.push({
28
+ name: "outcome-proxy-adequacy",
29
+ status: "warn",
30
+ kind: "deterministic",
31
+ confidence: "high",
32
+ message: `WS-2 outcome proxy inverted (${proxyInvertedEvents.length} event(s) in window). ` +
33
+ `corr(outcome_score, accepted_change_rate) = ${correlation} < −0.3. ` +
34
+ "Popular assets are also the most-needing-improvement assets — " +
35
+ "the retrieval-based proxy is inverted. " +
36
+ "The 0.10+ rich in-session outcome signal is no longer deferrable. See plan §WS-2.",
37
+ });
38
+ }
39
+ // Two-tailed companion: a proxy that decays to noise (|corr| < 0.1 at scale)
40
+ // is as much a failure as an inverted one — it just fails silently.
41
+ const proxyDeadEvents = readEvents({ since, type: "outcome_proxy_dead" }, { dbPath: stateDbPath, db }).events;
42
+ if (proxyDeadEvents.length > 0) {
43
+ const lastEvent = proxyDeadEvents[proxyDeadEvents.length - 1];
44
+ const correlation = typeof lastEvent.metadata?.correlation === "number" ? lastEvent.metadata.correlation.toFixed(3) : "unknown";
45
+ advisories.push({
46
+ name: "outcome-proxy-dead",
47
+ status: "warn",
48
+ kind: "deterministic",
49
+ confidence: "high",
50
+ message: `WS-2 outcome proxy is DEAD (${proxyDeadEvents.length} event(s) in window). ` +
51
+ `|corr(outcome_score, accepted_change_rate)| = ${correlation} < 0.1 at n ≥ 500. ` +
52
+ "outcome_score is statistically unrelated to improvement outcomes — " +
53
+ "treat outcome-derived rank contributions as noise until a real usage/outcome signal lands.",
54
+ });
55
+ }
56
+ // Salience-distribution collapse: Gini below the uniform baseline means
57
+ // ranking no longer discriminates between assets.
58
+ if (improveSummary.degradation?.salienceUniformityFlagged) {
59
+ advisories.push({
60
+ name: "salience-uniformity-collapse",
61
+ status: "warn",
62
+ kind: "deterministic",
63
+ confidence: "high",
64
+ message: `Salience distribution collapsed toward uniform: top-100 retrieval_salience Gini = ` +
65
+ `${improveSummary.degradation.corpusCentroidDistance} < 0.08 (uniform baseline ≈ 0.1). ` +
66
+ "Ranking currently carries little to no discrimination between assets.",
67
+ });
68
+ }
69
+ // Enrichment-vs-minting policy: enrichment lanes edit existing assets;
70
+ // a rising minted share means a lane is generating new content instead.
71
+ const minting = improveSummary.enrichmentMinting;
72
+ if (minting && Number.isFinite(minting.share) && minting.share > ENRICHMENT_MINTED_WARN_SHARE) {
73
+ advisories.push({
74
+ name: "enrichment-lane-minting",
75
+ status: minting.share > ENRICHMENT_MINTED_FAIL_SHARE ? "fail" : "warn",
76
+ kind: "deterministic",
77
+ confidence: "high",
78
+ message: `Enrichment lanes minted ${minting.minted} NEW asset(s) vs ${minting.updated} update(s) ` +
79
+ `(${Math.round(minting.share * 100)}% minted, threshold ${Math.round(ENRICHMENT_MINTED_WARN_SHARE * 100)}%). ` +
80
+ "Enrichment-classed lanes (proactive/high-salience/high-retrieval/signal-delta) are ratified to edit " +
81
+ "existing assets only — new-asset generation belongs to the signal-gated minting lanes.",
82
+ });
83
+ }
84
+ // Churn: accepted proposals far exceeding distinct touched refs means the
85
+ // loop is repeatedly rewriting the same assets, not covering the corpus.
86
+ if (Number.isFinite(improveSummary.coverage.churnRatio) && improveSummary.coverage.churnRatio > 1.5) {
87
+ advisories.push({
88
+ name: "improve-churn-ratio",
89
+ status: "warn",
90
+ kind: "deterministic",
91
+ confidence: "high",
92
+ message: `Improve churn ratio ${improveSummary.coverage.churnRatio} > 1.5: ` +
93
+ `${improveSummary.coverage.acceptedProposals} accepted proposals touched only ` +
94
+ `${improveSummary.coverage.distinctRefs} distinct assets in the window — ` +
95
+ "repeated rewrites of the same refs count as churn, not coverage.",
96
+ });
97
+ }
98
+ // R5 collapse/churn detector: surface any collapse_detector_alert events
99
+ // in the health window, plus the latest cycle row's headline numbers so
100
+ // the operator can act without opening the DB. `unknown` when the detector
101
+ // has never produced a cycle row (no consolidate/recombine work yet).
102
+ try {
103
+ // Reuse the already-open state.db handle (readEvents supports a
104
+ // borrowed connection) — no extra open/migrate/close per health call.
105
+ const collapseAlertEvents = readEvents({ since, type: "collapse_detector_alert" }, { dbPath: stateDbPath, db }).events;
106
+ const latestCycle = getLatestCycleMetrics(db);
107
+ const cycleSummary = latestCycle
108
+ ? `Latest cycle (${latestCycle.ts}, ${latestCycle.pass}): mean canary recall ${latestCycle.mean_recall.toFixed(3)}, ` +
109
+ `distinct-content ratio ${latestCycle.distinct_content_ratio.toFixed(3)}, ` +
110
+ `${latestCycle.accepted_actions} accepted action(s).`
111
+ : "";
112
+ if (collapseAlertEvents.length > 0) {
113
+ const kinds = [...new Set(collapseAlertEvents.map((e) => String(e.metadata?.kind ?? "unknown")))];
114
+ const collapseKinds = kinds.filter((k) => k.startsWith("collapse"));
115
+ advisories.push({
116
+ name: "collapse-churn-detector",
117
+ status: "warn",
118
+ kind: "deterministic",
119
+ // Collapse kinds are measured, not inferred; churn/merge-floor
120
+ // volume thresholds are still being tuned (design doc §7).
121
+ confidence: collapseKinds.length > 0 ? "high" : "medium",
122
+ message: `R5 detector fired ${collapseAlertEvents.length} alert(s) in window (kinds: ${kinds.join(", ")}). ` +
123
+ `${cycleSummary} See docs/design/improve-collapse-churn-detector-design.md §6.3 runbook queries.`,
124
+ });
125
+ }
126
+ else if (latestCycle) {
127
+ advisories.push({
128
+ name: "collapse-churn-detector",
129
+ status: "pass",
130
+ kind: "deterministic",
131
+ confidence: "high",
132
+ message: `No collapse/churn alerts in window. ${cycleSummary}`,
133
+ });
134
+ }
135
+ else {
136
+ advisories.push({
137
+ name: "collapse-churn-detector",
138
+ status: "unknown",
139
+ kind: "deterministic",
140
+ confidence: "high",
141
+ message: "No detector cycle rows yet — the collapse/churn detector runs only on improve cycles " +
142
+ "where consolidate/recombine did work (synthesis lanes may be idle).",
143
+ });
144
+ }
145
+ }
146
+ catch {
147
+ // Table may predate migration 016 in odd mixed-version setups — advisory
148
+ // is best-effort and must never fail the health command.
149
+ }
150
+ return advisories;
151
+ }
@@ -4,6 +4,7 @@
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { loadConfig } from "../../core/config/config.js";
6
6
  import { detectAgentCliProfiles, requireAgentProfile } from "../../integrations/agent/index.js";
7
+ import { TASK_FAIL_RATE_WARN, } from "./types.js";
7
8
  const ACTIVE_RUN_WARN_MS = 15 * 60 * 1000;
8
9
  /**
9
10
  * Probe the configured agent profile. Self-contained (reads config + PATH); the
@@ -188,24 +189,62 @@ export const HEALTH_CHECKS = [
188
189
  channel: "hard",
189
190
  run: () => runAgentProbe(),
190
191
  },
192
+ {
193
+ // C2 (13-bus-factor): the cron task-failure rate was computed and rendered
194
+ // in the HTML report but never surfaced as an advisory, so a sustained
195
+ // 15–16% fail rate stayed invisible on `akm health`. Warn at/above the SAME
196
+ // 5% threshold the html-report badge uses (see TASK_FAIL_RATE_WARN).
197
+ name: "task-fail-rate",
198
+ channel: "advisory",
199
+ run: (ctx) => {
200
+ const pctStr = `${(ctx.taskFailRate * 100).toFixed(1)}%`;
201
+ const thresholdPct = `${(TASK_FAIL_RATE_WARN * 100).toFixed(0)}%`;
202
+ const warn = ctx.taskFailRate >= TASK_FAIL_RATE_WARN;
203
+ return {
204
+ name: "task-fail-rate",
205
+ kind: "deterministic",
206
+ status: warn ? "warn" : "pass",
207
+ confidence: "high",
208
+ message: ctx.taskRowCount === 0
209
+ ? `No cron tasks ran since ${ctx.since} — no task-fail-rate signal.`
210
+ : warn
211
+ ? `Cron task fail rate ${pctStr} across ${ctx.taskRowCount} task(s) since ${ctx.since} ≥ ${thresholdPct} threshold — inspect failed runs (ok=false) for early-exit/harness errors.`
212
+ : `Cron task fail rate ${pctStr} across ${ctx.taskRowCount} task(s) since ${ctx.since} (below ${thresholdPct} threshold).`,
213
+ evidence: { taskFailRate: ctx.taskFailRate, taskRowCount: ctx.taskRowCount, threshold: TASK_FAIL_RATE_WARN },
214
+ };
215
+ },
216
+ },
191
217
  {
192
218
  name: "semantic-search-runtime",
193
219
  channel: "advisory",
194
- run: (ctx) => ({
195
- name: "semantic-search-runtime",
196
- kind: "deterministic",
197
- status: !ctx.semanticStatus ||
198
- ctx.semanticStatus.status === "pending" ||
199
- ctx.semanticStatus.status === "ready-js" ||
200
- ctx.semanticStatus.status === "ready-vec"
201
- ? "pass"
202
- : "warn",
203
- confidence: "medium",
204
- message: ctx.semanticStatus
205
- ? `Semantic search status: ${ctx.semanticStatus.status}`
206
- : "No semantic-search runtime status recorded yet.",
207
- evidence: ctx.semanticStatus ? { ...ctx.semanticStatus } : undefined,
208
- }),
220
+ run: (ctx) => {
221
+ const blocked = ctx.semanticStatus?.status === "blocked";
222
+ // The generic "status: blocked" line is not actionable when the real
223
+ // problem is a configured remote embedding endpoint that is down while
224
+ // semanticSearchMode leaves semantic search enabled — every index run
225
+ // burns time failing against it and searches silently degrade to
226
+ // keyword-only. Name the endpoint and the two ways out.
227
+ const remoteReason = ctx.semanticStatus?.reason?.startsWith("remote-") === true;
228
+ const endpointAdvisory = blocked && remoteReason && ctx.embeddingEndpoint
229
+ ? `Configured embedding endpoint ${ctx.embeddingEndpoint} is failing ` +
230
+ `(${ctx.semanticStatus?.reason}${ctx.semanticStatus?.message ? `: ${ctx.semanticStatus.message}` : ""}) ` +
231
+ `while semanticSearchMode is "${ctx.semanticSearchMode ?? "auto"}". Searches fall back to keyword-only. ` +
232
+ `Restore the endpoint, or set semanticSearchMode to "off" (or remove embedding.endpoint to use the local model).`
233
+ : undefined;
234
+ return {
235
+ name: "semantic-search-runtime",
236
+ kind: "deterministic",
237
+ status: !ctx.semanticStatus || !blocked ? "pass" : "warn",
238
+ confidence: "medium",
239
+ message: endpointAdvisory ??
240
+ (ctx.semanticStatus
241
+ ? `Semantic search status: ${ctx.semanticStatus.status}`
242
+ : "No semantic-search runtime status recorded yet."),
243
+ evidence: ctx.semanticStatus
244
+ ? { ...ctx.semanticStatus, ...(ctx.embeddingEndpoint ? { embeddingEndpoint: ctx.embeddingEndpoint } : {}) }
245
+ : undefined,
246
+ };
247
+ },
209
248
  },
210
249
  {
211
250
  // session-log-failures: demoted to informational — the ERROR_PATTERNS regex
@@ -257,6 +296,54 @@ export const HEALTH_CHECKS = [
257
296
  };
258
297
  },
259
298
  },
299
+ {
300
+ // #603: pool-saturation advisory. The raw `sessionsScanned` count fired on
301
+ // normal cadence changes (the Jun 12 false alarm). Instead track the ratio
302
+ // of NEW (unseen) sessions to the total session pool extract evaluated in
303
+ // the window: a low ratio is the *expected* steady state, only a near-zero
304
+ // ratio signals a possible discovery/dedup bug.
305
+ //
306
+ // unseen ≈ `sessionsScanned` (extract only processes new sessions; already-
307
+ // seen ones are deduped into `sessionsSkipped`). total = scanned + skipped.
308
+ // This is a heuristic approximation — `sessionsSkipped` also folds in
309
+ // too-short skips — so the check is informational and never gates status.
310
+ name: "pool-saturation",
311
+ channel: "advisory",
312
+ run: (ctx) => {
313
+ const sx = ctx.sessionExtraction;
314
+ const total = sx.sessionsScanned + sx.sessionsSkipped;
315
+ const unseen = sx.sessionsScanned;
316
+ const ratio = total > 0 ? unseen / total : null;
317
+ const pct = ratio === null ? null : Math.round(ratio * 1000) / 10;
318
+ let status = "pass";
319
+ let confidence = "low";
320
+ let message;
321
+ if (!sx.ran || ratio === null) {
322
+ message = "Pool saturation: no extract activity in the window — no signal.";
323
+ }
324
+ else if (ratio < 0.02) {
325
+ status = "warn";
326
+ confidence = "medium";
327
+ message = `Session pool near-exhausted: only ${pct}% of the ${total}-session pool was new (<2%). Possible discovery/dedup bug — verify extract is still finding new sessions.`;
328
+ }
329
+ else if (ratio < 0.1) {
330
+ confidence = "medium";
331
+ message = `Session pool saturation: ${pct}% of ${total} sessions were new (<10%, steady-state expected — informational).`;
332
+ }
333
+ else {
334
+ confidence = "medium";
335
+ message = `Session pool healthy: ${pct}% of ${total} sessions were new.`;
336
+ }
337
+ return {
338
+ name: "pool-saturation",
339
+ kind: "heuristic",
340
+ status,
341
+ confidence,
342
+ message,
343
+ evidence: { totalSessions: total, unseenSessions: unseen, saturationRatio: ratio },
344
+ };
345
+ },
346
+ },
260
347
  {
261
348
  name: "auto-accept-validation",
262
349
  channel: "advisory",
@@ -268,7 +355,7 @@ export const HEALTH_CHECKS = [
268
355
  status: aa.validationFailed > 0 ? "warn" : "pass",
269
356
  confidence: aa.promoted + aa.validationFailed > 0 ? "high" : "low",
270
357
  message: aa.validationFailed > 0
271
- ? `${aa.validationFailed} proposal(s) passed confidence threshold but failed auto-accept validation (truncated description, invalid frontmatter, etc.) — they remain in the queue for manual review.`
358
+ ? `${aa.validationFailed} auto-accept validation attempt(s) failed after passing the confidence threshold (truncated description, invalid frontmatter, etc.) — the affected proposals remain pending for manual review.`
272
359
  : aa.promoted > 0
273
360
  ? `Auto-accept healthy: ${aa.promoted} proposal(s) promoted, 0 validation failures.`
274
361
  : "Auto-accept gate did not run (disabled or no proposals above threshold).",