akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4

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 (343) hide show
  1. package/CHANGELOG.md +756 -0
  2. package/dist/akm +94 -196
  3. package/dist/cli/shared.js +6 -2
  4. package/dist/cli.js +22 -9
  5. package/dist/commands/agent/agent-dispatch.js +1 -1
  6. package/dist/commands/command/command-execution.js +24 -62
  7. package/dist/commands/feedback-cli.js +0 -1
  8. package/dist/commands/health/accept-rate.js +2 -2
  9. package/dist/commands/health/checks.js +30 -75
  10. package/dist/commands/health/config-skew.js +38 -0
  11. package/dist/commands/health/egress.js +54 -0
  12. package/dist/commands/health/html-report.js +0 -38
  13. package/dist/commands/health/improve-metrics.js +123 -562
  14. package/dist/commands/health/plugin-staleness.js +53 -3
  15. package/dist/commands/health/renderers.js +12 -4
  16. package/dist/commands/health/report-view-model.js +11 -106
  17. package/dist/commands/health/types-improve.js +4 -19
  18. package/dist/commands/health/windows.js +64 -73
  19. package/dist/commands/health.js +122 -143
  20. package/dist/commands/improve/consolidate/chunking.js +25 -100
  21. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  22. package/dist/commands/improve/consolidate.js +538 -1075
  23. package/dist/commands/improve/content-hash.js +16 -24
  24. package/dist/commands/improve/distill/content-repair.js +18 -100
  25. package/dist/commands/improve/distill-guards.js +20 -81
  26. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  27. package/dist/commands/improve/distill.js +608 -1075
  28. package/dist/commands/improve/eligibility.js +126 -400
  29. package/dist/commands/improve/execution.js +3 -5
  30. package/dist/commands/improve/extract.js +487 -1046
  31. package/dist/commands/improve/feedback-valence.js +0 -25
  32. package/dist/commands/improve/improve-cli.js +29 -166
  33. package/dist/commands/improve/improve-result-file.js +10 -66
  34. package/dist/commands/improve/improve-strategies.js +12 -7
  35. package/dist/commands/improve/improve-usage-report.js +18 -64
  36. package/dist/commands/improve/improve.js +443 -1063
  37. package/dist/commands/improve/ledger.js +114 -0
  38. package/dist/commands/improve/locks.js +2 -8
  39. package/dist/commands/improve/loop-stages.js +459 -1172
  40. package/dist/commands/improve/memory/derived-ref.js +12 -77
  41. package/dist/commands/improve/memory/memory-belief.js +14 -118
  42. package/dist/commands/improve/memory/memory-improve.js +4 -3
  43. package/dist/commands/improve/outcome-loop.js +28 -156
  44. package/dist/commands/improve/planner.js +5 -10
  45. package/dist/commands/improve/preparation.js +851 -2339
  46. package/dist/commands/improve/proactive-maintenance.js +34 -101
  47. package/dist/commands/improve/reflect-noise.js +104 -280
  48. package/dist/commands/improve/reflect.js +621 -1367
  49. package/dist/commands/improve/salience.js +46 -232
  50. package/dist/commands/improve/session-asset.js +19 -100
  51. package/dist/commands/improve/stage.js +323 -0
  52. package/dist/commands/proposal/drain.js +251 -644
  53. package/dist/commands/proposal/proposal-cli.js +3 -18
  54. package/dist/commands/proposal/proposal-types.js +20 -41
  55. package/dist/commands/proposal/proposal.js +1 -2
  56. package/dist/commands/proposal/propose.js +134 -160
  57. package/dist/commands/proposal/repository.js +502 -1487
  58. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  59. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  60. package/dist/commands/proposal/validators/proposals.js +13 -89
  61. package/dist/commands/read/curate.js +63 -413
  62. package/dist/commands/read/search-cli.js +16 -33
  63. package/dist/commands/read/search.js +17 -23
  64. package/dist/commands/read/show.js +2 -13
  65. package/dist/commands/sources/bundle-cli.js +25 -2
  66. package/dist/commands/sources/bundle-config-ops.js +7 -0
  67. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  68. package/dist/commands/sources/info.js +2 -11
  69. package/dist/commands/sources/installed-stashes.js +197 -746
  70. package/dist/commands/sources/schema-repair.js +98 -129
  71. package/dist/commands/sources/source-add.js +62 -12
  72. package/dist/commands/sources/stash-cli.js +1 -1
  73. package/dist/commands/tasks/explain.js +10 -13
  74. package/dist/commands/tasks/tasks-cli.js +9 -8
  75. package/dist/commands/tasks/tasks.js +326 -930
  76. package/dist/commands/tasks/validate.js +42 -21
  77. package/dist/commands/workflow/plan.js +22 -29
  78. package/dist/commands/workflow-cli.js +4 -4
  79. package/dist/core/adapter/adapters/akm-adapter.js +0 -1
  80. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  81. package/dist/core/adapter/adapters/akm-metadata.js +11 -12
  82. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  83. package/dist/core/adapter/execution-source.js +17 -29
  84. package/dist/core/asset/resolve-ref.js +1 -1
  85. package/dist/core/bundle-id.js +42 -5
  86. package/dist/core/bundle-rename.js +291 -0
  87. package/dist/core/config/config-io.js +1 -2
  88. package/dist/core/config/config-schema.js +1 -33
  89. package/dist/core/config/config-walker.js +1 -1
  90. package/dist/core/config/config.js +163 -68
  91. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  92. package/dist/core/config/schema/embedding.js +20 -5
  93. package/dist/core/config/schema/engines.js +5 -0
  94. package/dist/core/config/schema/execution.js +1 -1
  95. package/dist/core/config/schema/experimental.js +1 -1
  96. package/dist/core/config/schema/improve-processes.js +21 -95
  97. package/dist/core/config/schema/improve.js +4 -42
  98. package/dist/core/config/schema/scheduler.js +12 -12
  99. package/dist/core/config/schema/search.js +6 -22
  100. package/dist/core/env-secret-ref.js +0 -1
  101. package/dist/core/errors.js +8 -9
  102. package/dist/core/file-lock.js +76 -173
  103. package/dist/core/logs-db.js +2 -2
  104. package/dist/core/paths.js +0 -27
  105. package/dist/core/redaction.js +109 -2
  106. package/dist/core/run-lock.js +2 -5
  107. package/dist/core/spawn-env.js +1 -1
  108. package/dist/core/state/migrations.js +108 -61
  109. package/dist/core/state-db-scope.js +2 -4
  110. package/dist/core/state-db.js +126 -692
  111. package/dist/core/type-presentation.js +1 -9
  112. package/dist/core/write-source.js +293 -1012
  113. package/dist/execution/input-contract.js +1 -1
  114. package/dist/execution/resolved-request.js +135 -689
  115. package/dist/execution/source.js +63 -257
  116. package/dist/execution/target-ref.js +1 -1
  117. package/dist/indexer/bundle-identity-guard.js +2 -2
  118. package/dist/indexer/db/graph-db.js +106 -46
  119. package/dist/indexer/ensure-index.js +44 -85
  120. package/dist/indexer/graph/graph-extraction.js +340 -562
  121. package/dist/indexer/graph/graph-related.js +130 -0
  122. package/dist/indexer/index-rebuild-lock.js +3 -11
  123. package/dist/indexer/index-writer-lock.js +8 -17
  124. package/dist/indexer/index-written-assets.js +139 -151
  125. package/dist/indexer/indexer.js +524 -846
  126. package/dist/indexer/materialize-embeddings.js +60 -397
  127. package/dist/indexer/passes/memory-inference.js +81 -90
  128. package/dist/indexer/passes/metadata.js +132 -200
  129. package/dist/indexer/read-preflight.js +0 -7
  130. package/dist/indexer/scan/doc-to-entry.js +1 -3
  131. package/dist/indexer/scan/drain-dir.js +1 -1
  132. package/dist/indexer/search/db-search.js +181 -590
  133. package/dist/indexer/search/fts-query.js +30 -41
  134. package/dist/indexer/search/ranking.js +28 -154
  135. package/dist/indexer/search/search-attribution.js +12 -32
  136. package/dist/indexer/search/search-fields.js +11 -15
  137. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  138. package/dist/indexer/search/search-source.js +1 -4
  139. package/dist/indexer/usage/usage-events.js +2 -7
  140. package/dist/integrations/agent/engine-fallback.js +23 -40
  141. package/dist/integrations/agent/engine-resolution.js +93 -183
  142. package/dist/integrations/agent/execution.js +507 -0
  143. package/dist/integrations/agent/model-map.js +28 -156
  144. package/dist/integrations/agent/request-lowering.js +66 -141
  145. package/dist/integrations/agent/runner-dispatch.js +143 -321
  146. package/dist/integrations/agent/runner.js +54 -14
  147. package/dist/integrations/lockfile.js +53 -101
  148. package/dist/llm/embedders/deterministic.js +2 -3
  149. package/dist/llm/embedders/profile.js +71 -0
  150. package/dist/llm/embedders/remote.js +10 -15
  151. package/dist/llm/graph-extract.js +3 -12
  152. package/dist/llm/index-passes.js +3 -5
  153. package/dist/llm/memory-infer.js +1 -2
  154. package/dist/llm/metadata-enhance.js +1 -2
  155. package/dist/llm/structured-call.js +5 -24
  156. package/dist/output/generic-render.js +23 -11
  157. package/dist/output/html-render.js +13 -10
  158. package/dist/output/render-registry.js +3 -32
  159. package/dist/output/shapes/helpers.js +2 -34
  160. package/dist/output/shapes/passthrough.js +1 -9
  161. package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
  162. package/dist/output/text/command-format.js +60 -23
  163. package/dist/output/text/helpers.js +1 -1
  164. package/dist/output/text/migrate.js +5 -14
  165. package/dist/output/text/proposal-format.js +1 -2
  166. package/dist/output/text/workflow-format.js +0 -32
  167. package/dist/output/text.js +2 -0
  168. package/dist/registry/factory.js +4 -19
  169. package/dist/registry/network.js +66 -220
  170. package/dist/registry/providers/index.js +0 -2
  171. package/dist/registry/providers/skills-sh.js +3 -14
  172. package/dist/registry/providers/static-index.js +24 -26
  173. package/dist/registry/resolve.js +55 -131
  174. package/dist/scripts/akm-migrate-node.js +43937 -93313
  175. package/dist/scripts/akm-migrate.js +43697 -93071
  176. package/dist/setup/registry-stash-loader.js +4 -13
  177. package/dist/setup/semantic-assets.js +3 -44
  178. package/dist/setup/setup.js +1 -1
  179. package/dist/setup/steps/tasks.js +25 -15
  180. package/dist/sources/provider-factory.js +17 -18
  181. package/dist/sources/providers/filesystem.js +2 -3
  182. package/dist/sources/providers/git-install.js +7 -1
  183. package/dist/sources/providers/git-provider.js +0 -3
  184. package/dist/sources/providers/git-stash.js +0 -17
  185. package/dist/sources/providers/npm.js +2 -4
  186. package/dist/sources/providers/provider-utils.js +5 -10
  187. package/dist/sources/providers/website.js +0 -2
  188. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  189. package/dist/sources/website-url.js +2 -2
  190. package/dist/storage/database.js +9 -35
  191. package/dist/storage/repositories/improve-ledger-repository.js +168 -0
  192. package/dist/storage/repositories/index-connection.js +34 -70
  193. package/dist/storage/repositories/index-entries-repository.js +69 -111
  194. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  195. package/dist/storage/repositories/index-entry-schema.js +83 -269
  196. package/dist/storage/repositories/index-fts-repository.js +86 -256
  197. package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
  198. package/dist/storage/repositories/index-meta-repository.js +6 -4
  199. package/dist/storage/repositories/index-schema.js +192 -220
  200. package/dist/storage/repositories/index-utility-repository.js +8 -29
  201. package/dist/storage/repositories/index-vec-repository.js +133 -414
  202. package/dist/storage/repositories/outcome-repository.js +2 -1
  203. package/dist/storage/repositories/proposals-repository.js +35 -0
  204. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  205. package/dist/storage/repositories/task-history-repository.js +26 -4
  206. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  207. package/dist/storage/sqlite-migrations.js +136 -0
  208. package/dist/storage/sqlite-pragmas.js +11 -9
  209. package/dist/storage/sqlite-transaction.js +170 -0
  210. package/dist/storage/state-db-integrity.js +34 -27
  211. package/dist/tasks/activation-config.js +134 -62
  212. package/dist/tasks/backends/cron.js +129 -277
  213. package/dist/tasks/backends/exec-utils.js +2 -5
  214. package/dist/tasks/backends/launchd.js +125 -745
  215. package/dist/tasks/backends/schtasks.js +101 -620
  216. package/dist/tasks/prepare/prepare-support.js +5 -15
  217. package/dist/tasks/prepare/prepare.js +0 -2
  218. package/dist/tasks/resolve-akm-bin.js +20 -79
  219. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  220. package/dist/tasks/scheduler-binding.js +18 -238
  221. package/dist/tasks/scheduler-invocation.js +52 -52
  222. package/dist/tasks/scheduler-lock.js +53 -0
  223. package/dist/tasks/scheduler-sync.js +363 -679
  224. package/dist/tasks/source/parse-task-source.js +160 -10
  225. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  226. package/dist/tasks/source/task-to-v4.js +2 -2
  227. package/dist/workflows/authoring/authoring.js +3 -12
  228. package/dist/workflows/compile.js +211 -0
  229. package/dist/workflows/concurrency-policy.js +13 -74
  230. package/dist/workflows/exec/child-invocation.js +3 -17
  231. package/dist/workflows/exec/child-workflow.js +32 -141
  232. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  233. package/dist/workflows/exec/environment.js +98 -0
  234. package/dist/workflows/exec/exec-unit.js +33 -140
  235. package/dist/workflows/exec/frozen-judge.js +7 -59
  236. package/dist/workflows/exec/native-executor.js +82 -341
  237. package/dist/workflows/exec/param-secrets.js +29 -47
  238. package/dist/workflows/exec/run-workflow.js +154 -387
  239. package/dist/workflows/exec/scheduler.js +9 -36
  240. package/dist/workflows/exec/step-work.js +127 -430
  241. package/dist/workflows/exec/unit-dispatch.js +11 -63
  242. package/dist/workflows/exec/unit-writer.js +8 -52
  243. package/dist/workflows/exec/worktree.js +39 -273
  244. package/dist/workflows/freeze/child-output-references.js +4 -15
  245. package/dist/workflows/freeze/environment.js +99 -92
  246. package/dist/workflows/freeze/freeze.js +172 -0
  247. package/dist/workflows/freeze/step-values.js +19 -21
  248. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  249. package/dist/workflows/freeze/targets/command.js +10 -33
  250. package/dist/workflows/freeze/targets/script.js +5 -12
  251. package/dist/workflows/freeze/targets/shell.js +3 -6
  252. package/dist/workflows/freeze/targets/task.js +25 -80
  253. package/dist/workflows/freeze/task-bindings.js +20 -67
  254. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  255. package/dist/workflows/ir/params.js +6 -51
  256. package/dist/workflows/ir/plan-hash.js +2 -34
  257. package/dist/workflows/parser.js +140 -43
  258. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  259. package/dist/workflows/renderer.js +36 -69
  260. package/dist/workflows/resource-limits.js +12 -120
  261. package/dist/workflows/runtime/agent-identity.js +8 -40
  262. package/dist/workflows/runtime/run-outputs.js +3 -6
  263. package/dist/workflows/runtime/run-plan.js +316 -0
  264. package/dist/workflows/runtime/runs.js +48 -200
  265. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  266. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  267. package/dist/workflows/validate-summary.js +2 -7
  268. package/docs/integration/bundling-akm.md +49 -42
  269. package/docs/migration/README.md +1 -0
  270. package/docs/migration/release-notes/0.9.17.md +41 -0
  271. package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
  272. package/docs/reference/cli.md +182 -125
  273. package/docs/reference/configuration.md +49 -56
  274. package/docs/reference/data-and-telemetry.md +19 -20
  275. package/docs/reference/tasks.md +86 -38
  276. package/docs/reference/workflow-schema.md +14 -18
  277. package/docs/reference/workflows.md +6 -9
  278. package/package.json +1 -1
  279. package/schemas/akm-config.json +87 -406
  280. package/dist/commands/health/advisories.js +0 -150
  281. package/dist/commands/health/metrics.js +0 -329
  282. package/dist/commands/health/surfaces.js +0 -102
  283. package/dist/commands/improve/anti-collapse.js +0 -83
  284. package/dist/commands/improve/collapse-detector.js +0 -432
  285. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  286. package/dist/commands/improve/consolidate/merge.js +0 -146
  287. package/dist/commands/improve/distill/promote-memory.js +0 -329
  288. package/dist/commands/improve/distill/quality-gate.js +0 -500
  289. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  290. package/dist/commands/improve/proposal-envelope.js +0 -31
  291. package/dist/commands/improve/run-context.js +0 -123
  292. package/dist/commands/improve/shared.js +0 -21
  293. package/dist/commands/improve/source-identity.js +0 -28
  294. package/dist/commands/improve/triage.js +0 -96
  295. package/dist/commands/proposal/drain-policies.js +0 -151
  296. package/dist/commands/sources/update-transaction.js +0 -220
  297. package/dist/core/action-contributors.js +0 -28
  298. package/dist/core/config/config-version-shim.js +0 -101
  299. package/dist/core/config/retired-experimental-keys-shim.js +0 -62
  300. package/dist/core/fs-txn.js +0 -405
  301. package/dist/core/lexical-score.js +0 -25
  302. package/dist/core/maintenance-barrier.js +0 -167
  303. package/dist/execution/executable-identity.js +0 -105
  304. package/dist/execution/guarded-source.js +0 -427
  305. package/dist/indexer/graph/graph-boost.js +0 -427
  306. package/dist/indexer/graph/graph-dedup.js +0 -95
  307. package/dist/indexer/search/name-match.js +0 -35
  308. package/dist/indexer/search/ranking-contributors.js +0 -515
  309. package/dist/indexer/walk/project-context.js +0 -192
  310. package/dist/integrations/agent/execution-cascade.js +0 -566
  311. package/dist/integrations/agent/execution-definitions.js +0 -202
  312. package/dist/integrations/agent/execution-lowering.js +0 -841
  313. package/dist/integrations/agent/execution-preparation.js +0 -98
  314. package/dist/integrations/agent/inline-execution.js +0 -74
  315. package/dist/registry/create-provider-registry.js +0 -29
  316. package/dist/registry/pinned-request-helper.js +0 -247
  317. package/dist/registry/pinned-transport.js +0 -717
  318. package/dist/sources/providers/index.js +0 -14
  319. package/dist/storage/engines/sqlite-migrations.js +0 -271
  320. package/dist/storage/repositories/canaries-repository.js +0 -107
  321. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  322. package/dist/storage/repositories/registry-cache.js +0 -113
  323. package/dist/tasks/scheduler-sync-preview.js +0 -52
  324. package/dist/workflows/freeze/resolve-steps.js +0 -86
  325. package/dist/workflows/freeze/source-freeze.js +0 -64
  326. package/dist/workflows/ir/compile.js +0 -321
  327. package/dist/workflows/ir/environment-v4.js +0 -330
  328. package/dist/workflows/ir/freeze-v4.js +0 -153
  329. package/dist/workflows/ir/schema-v4.js +0 -745
  330. package/dist/workflows/ir/schema.js +0 -354
  331. package/dist/workflows/program/schema.js +0 -78
  332. package/dist/workflows/runtime/checkin.js +0 -57
  333. package/dist/workflows/runtime/plan-classifier.js +0 -196
  334. package/dist/workflows/runtime/unit-checkin.js +0 -45
  335. package/dist/workflows/runtime/unit-phases.js +0 -20
  336. package/dist/workflows/schema.js +0 -4
  337. package/dist/workflows/source-ir/compile.js +0 -200
  338. package/dist/workflows/source-ir/program.js +0 -50
  339. package/dist/workflows/source-ir/result.js +0 -26
  340. package/dist/workflows/source-ir/schema.js +0 -786
  341. package/dist/workflows/source-ir/triggers.js +0 -79
  342. package/dist/workflows/source-ir/uses.js +0 -40
  343. package/dist/workflows/validator.js +0 -60
@@ -1,61 +1,22 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * The single, keyed-on-ref implementation of "is this a derived memory?" and
6
- * "which parent does it derive from?" (R12).
7
- *
8
- * Two divergent copies previously lived side by side — the CONSUMER
9
- * (`memory-improve.ts`, keyed on the memory name) and the PRODUCER
10
- * (`memory-contradiction-detect.ts`, keyed on the file path). The producer's
11
- * copy was strictly narrower: it ignored `derivedFrom` entirely and matched
12
- * `source:` through a separate parser. That let the producer and consumer
13
- * disagree on a memory's parent — the exact defect plan §6 calls out
14
- * ("producer/consumer cannot disagree").
15
- *
16
- * Both sides now share this one impl, keyed on the memory NAME (the stash-
17
- * relative path without the `.md` extension, e.g. `nested/foo.derived`). The
18
- * producer converts its file path to a name via `toMemoryRef` before calling
19
- * in. Adopting it on the producer side is an INTENTIONAL widening, pinned by
20
- * `tests/commands/improve/derived-ref.test.ts`:
21
- * - `derivedFrom`-keyed families now resolve a parent (and so participate in
22
- * contradiction detection); and
23
- * - `source:` is parsed through `parseRefInput` so current bundle-qualified
24
- * refs resolve consistently.
25
- *
26
- * Resolution order (source → derivedFrom → `.derived` suffix) matches the
27
- * consumer's prior behaviour exactly, so the consumer side is a pure move.
28
- */
4
+ /** The one implementation of "is this a derived memory, and what is its parent?" (R12), keyed on the memory name. */
29
5
  import { conceptIdFromTypeName, parseRefInput } from "../../../core/asset/resolve-ref.js";
30
6
  import { asNonEmptyString } from "../../../core/common.js";
31
7
  import { DERIVED_SUFFIX } from "../../../core/recognition-util.js";
32
8
  /**
33
- * Parse a belief edge (`supersededBy` / `contradictedBy` / `currentBeliefRefs`)
34
- * to the bare memory name the identity channel keys on.
35
- *
36
- * Accepts BOTH spellings, because both reach this function:
37
- * - `memory:<name>` — the internal identity spelling, and what belief edges
38
- * written before 0.9.0 carry on disk;
39
- * - `memories/<name>` / `<bundle>//memories/<name>` — the conceptId grammar
40
- * the current writers emit (`akm remember --supersedes` and `akm import
41
- * --supersedes` go through `writeSupersededEdge` with the write result's
42
- * `ref`, which is fully qualified).
43
- *
44
- * Accepting only the first spelling silently reduced every edge written by the
45
- * current code path to nothing, so a superseded memory read back as active.
46
- * Both normalize to the bare name; the caller re-mints the internal
47
- * `memory:<name>` form via {@link memoryIdentityRef}, so there is still exactly
48
- * one identity spelling downstream.
9
+ * A belief edge (`supersededBy` / `contradictedBy` / `currentBeliefRefs`) as a
10
+ * bare memory name. Both spellings occur: `memory:<name>` (pre-0.9 edges) and
11
+ * `[bundle//]memories/<name>` (what `--supersedes` writes today); accepting only
12
+ * the first once read every superseded memory back as active.
49
13
  */
50
14
  export function parseMemoryName(value) {
51
15
  if (!value)
52
16
  return undefined;
53
17
  const trimmed = value.trim();
54
- const MEMORY_PREFIX = "memory:";
55
- if (trimmed.startsWith(MEMORY_PREFIX)) {
56
- const name = trimmed.slice(MEMORY_PREFIX.length);
57
- return name.length > 0 ? name : undefined;
58
- }
18
+ if (trimmed.startsWith("memory:"))
19
+ return trimmed.slice("memory:".length) || undefined;
59
20
  try {
60
21
  const parsed = parseRefInput(trimmed);
61
22
  return parsed.type === "memory" && parsed.name.length > 0 ? parsed.name : undefined;
@@ -64,10 +25,7 @@ export function parseMemoryName(value) {
64
25
  return undefined;
65
26
  }
66
27
  }
67
- /**
68
- * Parse a current `source:` backref and return its canonical memory conceptId,
69
- * or `undefined` when it is empty, invalid, or not a memory ref.
70
- */
28
+ /** A `source:` backref as a memory conceptId, or `undefined` when it is not a memory ref. */
71
29
  export function parseMemoryRef(value) {
72
30
  if (!value)
73
31
  return undefined;
@@ -79,37 +37,15 @@ export function parseMemoryRef(value) {
79
37
  return undefined;
80
38
  }
81
39
  }
82
- /**
83
- * Format a bare memory name into the belief-edge IDENTITY channel ref
84
- * `memory:<name>` — the ONE implementation of that spelling.
85
- *
86
- * Belief-edge / identity
87
- * channel (`contradictedBy` / `supersededBy` / `currentBeliefRefs`, and a derived
88
- * memory's own `record.ref`) uses `memory:<name>` and is compared against a
89
- * derived memory's identity ref. This channel is separate from `source:` asset
90
- * refs, which use `memories/<name>`. Both `memory-improve.ts` (`refArray`) and
91
- * `memory-contradiction-detect.ts` (`toMemoryRef`) emit through here so the
92
- * identity spelling has one implementation.
93
- */
40
+ /** The belief-edge identity spelling, `memory:<name>` (separate from `source:` asset refs). */
94
41
  export function memoryIdentityRef(name) {
95
42
  return `memory:${name}`;
96
43
  }
97
- /**
98
- * True when the named memory is a derived/inferred child — either it carries
99
- * `inferred: true` in its frontmatter or its name ends with the structural
100
- * `.derived` suffix.
101
- */
44
+ /** Inferred (`inferred: true`) or named with the `.derived` suffix. */
102
45
  export function isDerivedMemory(name, frontmatter) {
103
46
  return frontmatter.inferred === true || name.endsWith(DERIVED_SUFFIX);
104
47
  }
105
- /**
106
- * Resolve the parent (source) memory ref for a derived memory as a canonical
107
- * `memories/<name>` conceptId, or `undefined` when none
108
- * can be determined. Precedence:
109
- * 1. `frontmatter.source` (normalised through {@link parseMemoryRef});
110
- * 2. `frontmatter.derivedFrom` (a bare memory name → `memories/<name>`);
111
- * 3. the `.derived` name suffix, stripped → `memories/<name>`.
112
- */
48
+ /** A derived memory's parent conceptId: from `source`, else `derivedFrom`, else the name minus `.derived`. */
113
49
  export function resolveParentRef(name, frontmatter) {
114
50
  const fromSource = parseMemoryRef(asNonEmptyString(frontmatter.source));
115
51
  if (fromSource)
@@ -117,8 +53,7 @@ export function resolveParentRef(name, frontmatter) {
117
53
  const derivedFrom = asNonEmptyString(frontmatter.derivedFrom);
118
54
  if (derivedFrom)
119
55
  return conceptIdFromTypeName("memory", derivedFrom);
120
- if (name.endsWith(DERIVED_SUFFIX)) {
56
+ if (name.endsWith(DERIVED_SUFFIX))
121
57
  return conceptIdFromTypeName("memory", name.slice(0, -DERIVED_SUFFIX.length));
122
- }
123
58
  return undefined;
124
59
  }
@@ -2,141 +2,37 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * Shared memory belief-state machinery (C-3 / #382).
6
- *
7
- * Extracted from `memory-improve.ts` so both `akmConsolidate` and
8
- * `analyzeMemoryCleanup` can emit `MemoryBeliefTransitionLogRecord` entries
9
- * through a unified state-transition model.
10
- *
11
- * # Design
12
- *
13
- * The 4-state belief lifecycle (active → superseded | contradicted → archived)
14
- * was previously encoded only in `memory-improve.ts`. `akmConsolidate` used a
15
- * flat merge/delete/promote model with no belief states, causing the two engines
16
- * to diverge. This module:
17
- *
18
- * 1. Re-exports the belief-state types from `memory-improve.ts` so callers
19
- * can import from one canonical location.
20
- * 2. Provides `writeContradictEdge` — a shared primitive that both engines
21
- * use when an LLM (or heuristic) identifies a contradiction between two
22
- * memories. This is the bridge between `akmConsolidate`'s LLM-detected
23
- * contradictions and `resolveFamilyContradictions`' SCC resolver.
24
- *
25
- * # References
26
- *
27
- * - Zep / Graphiti (arXiv:2501.13956 §3) — unified belief-revision pipeline
28
- * - MemOS (arXiv:2507.03724) — formal archive/merge/transition with shared state model
5
+ * Belief-state edge writer (#382): append a `supersededBy` edge to an asset's
6
+ * frontmatter and demote its `beliefState`, metadata only. Idempotent (a
7
+ * present edge AND demotion is a no-op; an edge without its demotion is
8
+ * repaired) and never weakens a stronger demotion — severity is
9
+ * superseded > contradicted > archived, per the ranker's `beliefStateBoost`.
10
+ * The SCC resolver in memory-improve.ts is a state-transition writer (it
11
+ * replaces and clears edges) and deliberately does not use this (#885).
29
12
  */
30
13
  import { mutateFrontmatter } from "../../../core/asset/frontmatter.js";
31
- // ── Shared edge-list reader ───────────────────────────────────────────────────
32
14
  /**
33
- * Read a frontmatter edge value (`supersededBy` / `contradictedBy`) as a
34
- * string list, promoting a scalar string to a one-element list.
35
- *
36
- * Scalar edges are LIVE data: the indexer's `normalizeNonEmptyStringList`
37
- * accepts them and lint deliberately never flags them. An Array.isArray-only
38
- * read treats a scalar as "no existing edges" and silently destroys the edge
39
- * on the next merge — mirror `mergeXrefsIntoContent`'s scalar promotion
40
- * instead.
15
+ * An edge value as a list. A scalar string is live data (the indexer accepts
16
+ * it), so it is promoted rather than dropped on the next write.
41
17
  */
42
18
  function readEdgeList(value) {
43
- if (Array.isArray(value)) {
19
+ if (Array.isArray(value))
44
20
  return value.filter((v) => typeof v === "string" && v.trim().length > 0);
45
- }
46
21
  if (typeof value === "string" && value.trim())
47
22
  return [value.trim()];
48
23
  return [];
49
24
  }
50
- // ── Contradiction edge writer ─────────────────────────────────────────────────
51
- /**
52
- * Write `contradictedBy` and `beliefState: contradicted` edges to a memory
53
- * file's frontmatter (C-3 / #382).
54
- *
55
- * The shared primitive for APPENDING one contradiction edge. Used by
56
- * `memory-contradiction-detect.ts`'s automated contradiction pass.
57
- *
58
- * NOT used by `persistBeliefStateTransition` in `memory-improve.ts`, and that
59
- * is deliberate (#885): the SCC resolver is a state-TRANSITION writer, not an
60
- * edge appender. It replaces `contradictedBy` wholesale from recomputed
61
- * `currentBeliefRefs`, deletes the key when a memory transitions away from
62
- * `contradicted`, and moves a memory to any target state including back to
63
- * active. An append-only primitive that never weakens a demotion cannot
64
- * express those, and routing it through this would break the resolver's
65
- * ability to clear an edge.
66
- *
67
- * Idempotent: if the `contradictedByRef` is already in `contradictedBy` AND
68
- * the file already carries the demotion state, the file is not rewritten. The
69
- * guard is state-aware like its sibling {@link writeSupersededEdge}: an edge
70
- * present WITHOUT the demotion (e.g. a hand-written `contradictedBy:` line,
71
- * or a beliefState lost to a partial edit) is repaired, not skipped — an
72
- * edge-only guard would make such a file a permanent no-op while
73
- * contradiction writers report the contradiction as applied.
74
- *
75
- * Never weakens a stronger demotion: `archived` ranks BELOW `contradicted`
76
- * (see `BELIEF_STATE_SCORE_CEILINGS` in
77
- * src/indexer/search/ranking-contributors.ts), so contradicting an archived
78
- * memory keeps `archived` and only appends the edge.
79
- *
80
- * @param filePath - Absolute path to the memory markdown file.
81
- * @param contradictedByRef - The ref that contradicts this memory.
82
- * @returns `true` when the file was rewritten, `false` when the edge and the
83
- * demotion were already present (the idempotent no-op). Callers count
84
- * edges written from this.
85
- */
86
- export function writeContradictEdge(filePath, contradictedByRef) {
87
- return mutateFrontmatter(filePath, (parsed) => {
88
- const existing = readEdgeList(parsed.data.contradictedBy);
89
- const currentState = parsed.data.beliefState;
90
- const nextState = currentState === "archived" ? currentState : "contradicted";
91
- if (existing.includes(contradictedByRef) && currentState === nextState) {
92
- return null; // Already written — idempotent.
93
- }
94
- const nextContradictedBy = [...new Set([...existing, contradictedByRef])].sort();
95
- return {
96
- ...parsed.data,
97
- contradictedBy: nextContradictedBy,
98
- beliefState: nextState,
99
- };
100
- });
101
- }
102
- // ── Supersession edge writer ─────────────────────────────────────────────────
103
- /**
104
- * Write `supersededBy` and `beliefState: superseded` edges to an asset file's
105
- * frontmatter (SPEC-5, stash-conventions-code-spec.md).
106
- *
107
- * Sibling of {@link writeContradictEdge}: the shared primitive for the
108
- * conventions' corrections pattern — when a new asset supersedes an old one,
109
- * the old asset gets a METADATA-ONLY demotion edit (every other frontmatter
110
- * key and the body are preserved) so the ranker's beliefStateBoost demotes the
111
- * stale incumbent and `--belief current` hides it. Used by
112
- * `akm remember --supersedes` / `akm import --supersedes`.
113
- *
114
- * Idempotent: if `supersededByRef` is already in `supersededBy` and the file
115
- * is already demoted, the file is not rewritten. Multiple corrections
116
- * sorted-set-append their refs.
117
- *
118
- * Never WEAKENS an existing demotion: `contradicted` and `archived` rank
119
- * BELOW `superseded` (severity order deprecated > superseded > contradicted >
120
- * archived — see `BELIEF_STATE_SCORE_CEILINGS` in
121
- * src/indexer/search/ranking-contributors.ts), so superseding an already
122
- * contradicted/archived asset keeps the stronger state and only appends the
123
- * `supersededBy` edge.
124
- *
125
- * @param filePath - Absolute path to the asset markdown file.
126
- * @param supersededByRef - The ref of the correction that supersedes this asset.
127
- */
25
+ /** Mark an asset superseded by a correction (`akm remember|import --supersedes`). */
128
26
  export function writeSupersededEdge(filePath, supersededByRef) {
129
27
  mutateFrontmatter(filePath, (parsed) => {
130
28
  const existing = readEdgeList(parsed.data.supersededBy);
131
29
  const currentState = parsed.data.beliefState;
132
30
  const nextState = currentState === "contradicted" || currentState === "archived" ? currentState : "superseded";
133
- if (existing.includes(supersededByRef) && currentState === nextState) {
134
- return null; // Already written — idempotent.
135
- }
136
- const nextSupersededBy = [...new Set([...existing, supersededByRef])].sort();
31
+ if (existing.includes(supersededByRef) && currentState === nextState)
32
+ return null;
137
33
  return {
138
34
  ...parsed.data,
139
- supersededBy: nextSupersededBy,
35
+ supersededBy: [...new Set([...existing, supersededByRef])].sort(),
140
36
  beliefState: nextState,
141
37
  };
142
38
  });
@@ -12,6 +12,7 @@ import { DERIVED_SUFFIX } from "../../../core/recognition-util.js";
12
12
  import { warn } from "../../../core/warn.js";
13
13
  import { recordWrittenPath } from "../../../core/write-provenance.js";
14
14
  import { walkMarkdownFiles } from "../../../indexer/walk/walker.js";
15
+ import { contentHash } from "../content-hash.js";
15
16
  import { isDerivedMemory, memoryIdentityRef, parseMemoryName, resolveParentRef } from "./derived-ref.js";
16
17
  export function analyzeMemoryCleanup(stashDir, options = {}) {
17
18
  const records = collectDerivedMemories(stashDir, options.parentRef);
@@ -676,7 +677,7 @@ function resolveBeliefState(frontmatter) {
676
677
  // firstExistingRef's byRef map), so they are NORMALIZED to `memory:<name>` here.
677
678
  // On disk they arrive in either spelling — `memory:<name>` from pre-0.9.0
678
679
  // writes, or the `[<bundle>//]memories/<name>` conceptId that
679
- // `writeSupersededEdge`/`writeContradictEdge` persist today — and
680
+ // `writeSupersededEdge` persists today — and
680
681
  // `parseMemoryName` accepts both. Reading only the first spelling silently
681
682
  // dropped every edge the current write path produces.
682
683
  function refArray(value) {
@@ -697,13 +698,13 @@ function refArray(value) {
697
698
  return [...refs].sort();
698
699
  }
699
700
  function buildFingerprint(title, description, tags, searchHints, body) {
700
- return JSON.stringify({
701
+ return contentHash(JSON.stringify({
701
702
  title: normalizeSignal(title),
702
703
  description: normalizeSignal(description),
703
704
  tags: normalizeList(tags),
704
705
  searchHints: normalizeList(searchHints),
705
706
  body: normalizeBody(body),
706
- });
707
+ }));
707
708
  }
708
709
  function normalizeBody(value) {
709
710
  return value
@@ -2,85 +2,37 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { getAllAssetOutcomes, getAssetOutcome, getOutcomeScoresByRef, upsertAssetOutcome, } from "../../storage/repositories/outcome-repository.js";
5
- // ── Constants ─────────────────────────────────────────────────────────────────
6
- /**
7
- * EMA decay factor for the expected-retrieval rolling mean (α).
8
- * New expected = α × new_count + (1−α) × old_expected.
9
- * At α = 0.3 the window is ≈ 3 cycles.
10
- */
5
+ /** EMA factor for both the score and the expected retrieval delta (≈ a 3-cycle window). */
11
6
  export const OUTCOME_EMA_ALPHA = 0.3;
12
- /**
13
- * Warm-start cap: the maximum `outcome_score` a brand-new row can be seeded with
14
- * (from the utility EMA). Prevents a `[0,1]`-range utility value from generating
15
- * a score that the first negative delta could catastrophically invert. Clipped to
16
- * the maximum plausible first differential update: `max(0, 1 − 0) = 1`, so cap
17
- * at a modest 0.3 to avoid spurious rank-flip on first cycle.
18
- */
7
+ /** The most a new row can be seeded with, so the first negative delta cannot flip the rank. */
19
8
  export const WARM_START_CAP = 0.3;
20
- /**
21
- * Penalty cap: the minimum outcome_score is capped at this value so a single
22
- * very-negative run can't send the score to −∞.
23
- */
24
9
  export const OUTCOME_SCORE_MIN = -1.0;
25
- /**
26
- * Saturation ceiling: the maximum outcome_score. Biological RPE saturates —
27
- * a fully predicted reward produces zero response, not an ever-growing one —
28
- * so a long-lived popular asset must not accrue unbounded outcome mass that
29
- * would dominate ranking once the outcome weight is enabled (analysis G2).
30
- * 1.5 comfortably exceeds the max plausible single-cycle raw update while
31
- * keeping the normalised outcomeSalience spread meaningful.
32
- */
10
+ /** Saturation: a long-popular asset must not accrue unbounded outcome mass. */
33
11
  export const OUTCOME_SCORE_MAX = 1.5;
34
- /**
35
- * Diversity floor: `outcomeSalience` for any asset is at least this fraction
36
- * of the maximum observed `outcome_score` in the table, so rare-but-correct
37
- * assets cannot be permanently outcompeted. 0 = disabled (pure competition).
38
- */
12
+ /** `outcomeSalience` never drops below this fraction of the stash-wide maximum. */
39
13
  export const DIVERSITY_FLOOR_FRACTION = 0.1;
40
- /**
41
- * Project the next outcome values without touching storage. Dry planning and
42
- * the live writer both call this function, so rank inputs cannot drift merely
43
- * because one caller persists the projection and the other does not.
44
- */
14
+ export { getAllAssetOutcomes, getAssetOutcome, getOutcomeScoresByRef };
15
+ /** The next outcome values, without storage — dry planning and the writer share it. */
45
16
  export function projectAssetOutcome(existing, inputs) {
46
- const valence = inputs.valence ?? 0;
47
- const isNewRow = existing === undefined;
48
- let outcomeScore;
49
- let expectedRetrievalRate;
50
- if (isNewRow) {
51
- const seedScore = Math.min(WARM_START_CAP, Math.max(0, inputs.utilityScore ?? 0));
52
- outcomeScore = seedScore;
53
- expectedRetrievalRate = 0;
17
+ if (existing === undefined) {
18
+ return {
19
+ outcomeScore: Math.min(WARM_START_CAP, Math.max(0, inputs.utilityScore ?? 0)),
20
+ expectedRetrievalRate: 0,
21
+ isNewRow: true,
22
+ };
54
23
  }
55
- else {
56
- const retrievalDelta = Math.max(0, inputs.currentRetrievalCount - existing.retrieval_count);
57
- const expectedDelta = existing.expected_retrieval_rate;
58
- const predictionError = retrievalDelta - expectedDelta;
59
- expectedRetrievalRate =
60
- OUTCOME_EMA_ALPHA * retrievalDelta + (1 - OUTCOME_EMA_ALPHA) * existing.expected_retrieval_rate;
61
- const rawUpdate = predictionError + valence;
62
- const newScore = OUTCOME_EMA_ALPHA * rawUpdate + (1 - OUTCOME_EMA_ALPHA) * existing.outcome_score;
63
- outcomeScore = Math.min(OUTCOME_SCORE_MAX, Math.max(OUTCOME_SCORE_MIN, newScore));
64
- }
65
- return { outcomeScore, expectedRetrievalRate, isNewRow };
24
+ const retrievalDelta = Math.max(0, inputs.currentRetrievalCount - existing.retrieval_count);
25
+ const rawUpdate = retrievalDelta - existing.expected_retrieval_rate + (inputs.valence ?? 0);
26
+ const newScore = OUTCOME_EMA_ALPHA * rawUpdate + (1 - OUTCOME_EMA_ALPHA) * existing.outcome_score;
27
+ return {
28
+ outcomeScore: Math.min(OUTCOME_SCORE_MAX, Math.max(OUTCOME_SCORE_MIN, newScore)),
29
+ expectedRetrievalRate: OUTCOME_EMA_ALPHA * retrievalDelta + (1 - OUTCOME_EMA_ALPHA) * existing.expected_retrieval_rate,
30
+ isNewRow: false,
31
+ };
66
32
  }
67
- /**
68
- * Upsert one asset's outcome row.
69
- *
70
- * On first call for a ref (no prior row): warm-starts from `utilityScore`.
71
- * On subsequent calls: applies the differential update formula.
72
- *
73
- * Returns the resulting `outcome_score` so the caller can pass it to
74
- * `computeSalience` without a second read.
75
- */
33
+ /** Upsert one asset's outcome row; returns the score for the salience vector. */
76
34
  export function updateAssetOutcome(db, inputs) {
77
- const now = inputs.now ?? Date.now();
78
- const existing = getAssetOutcome(db, inputs.ref);
79
- const projection = projectAssetOutcome(existing, inputs);
80
- // Upsert the row. See `upsertAssetOutcome` in
81
- // storage/repositories/outcome-repository.ts (#672 part 2) for the SQL text
82
- // and the `review_pressure` omission rationale — this call site is
83
- // unchanged in intent, just no longer inline.
35
+ const projection = projectAssetOutcome(getAssetOutcome(db, inputs.ref), inputs);
84
36
  upsertAssetOutcome(db, {
85
37
  ref: inputs.ref,
86
38
  lastRetrievedAt: inputs.lastRetrievedAt,
@@ -89,97 +41,17 @@ export function updateAssetOutcome(db, inputs) {
89
41
  negativeFeedbackCount: inputs.negativeFeedbackCount,
90
42
  acceptedChangeCount: inputs.acceptedChangeCount,
91
43
  outcomeScore: projection.outcomeScore,
92
- updatedAt: now,
44
+ updatedAt: inputs.now ?? Date.now(),
93
45
  });
94
46
  return { outcomeScore: projection.outcomeScore, isNewRow: projection.isNewRow };
95
47
  }
96
- // ── Reader ────────────────────────────────────────────────────────────────────
97
- //
98
- // getAssetOutcome / getAllAssetOutcomes / getOutcomeScoresByRef moved verbatim
99
- // to storage/repositories/outcome-repository.ts (#672 part 2) — re-exported
100
- // here so existing importers of this module resolve unchanged.
101
- export { getAllAssetOutcomes, getAssetOutcome, getOutcomeScoresByRef };
102
- // ── outcomeSalience projection ────────────────────────────────────────────────
103
48
  /**
104
- * Convert a raw `outcome_score` (differential, may be negative) to a
105
- * `outcomeSalience` value in [0, 1] suitable for use in the salience projection.
106
- *
107
- * Approach:
108
- * 1. Clip negative scores to 0 (a negative outcome just means "below expected",
109
- * not "irrelevant"; it should not harm the base retrieval/encoding ranking).
110
- * 2. Apply the diversity floor so rare-but-correct assets always retain a
111
- * minimum `outcomeSalience` relative to the stash-wide maximum.
112
- * 3. Normalise by `maxScore` (the stash-wide max outcome_score) so the term
113
- * lives in [0, 1]. When maxScore ≤ 0 (all seeds, nothing observed yet),
114
- * return the floor (or 0 if DIVERSITY_FLOOR_FRACTION = 0).
115
- *
116
- * @param outcomeScore - Raw outcome_score from asset_outcome.
117
- * @param maxScore - Maximum outcome_score across ALL rows (≥ 0 after clip).
118
- * Callers must compute this once per batch and pass it in.
49
+ * A raw outcome score as salience in [0, 1]: negatives clip to 0 (below
50
+ * expected is not irrelevant), normalized by the stash-wide maximum, never
51
+ * below the diversity floor.
119
52
  */
120
53
  export function outcomeScoreToSalience(outcomeScore, maxScore) {
121
- const clipped = Math.max(0, outcomeScore);
122
- if (maxScore <= 0) {
123
- // No positive scores observed yet — return diversity floor.
54
+ if (maxScore <= 0)
124
55
  return DIVERSITY_FLOOR_FRACTION;
125
- }
126
- const normalised = clipped / maxScore;
127
- // Apply diversity floor.
128
- return Math.max(DIVERSITY_FLOOR_FRACTION, normalised);
129
- }
130
- // ── Proxy-adequacy tripwire ───────────────────────────────────────────────────
131
- /**
132
- * Dead-proxy threshold: |corr| below this means outcome_score carries no
133
- * information about improvement need (pure noise).
134
- */
135
- export const PROXY_DEAD_CORR_THRESHOLD = 0.1;
136
- /**
137
- * Minimum sample size before the dead-proxy check fires. Below this, a
138
- * near-zero correlation is indistinguishable from small-sample noise.
139
- */
140
- export const PROXY_DEAD_MIN_N = 500;
141
- /**
142
- * Compute `corr(outcome_score, accepted_change_rate)` across all asset_outcome
143
- * rows. Returns `{correlation: NaN, n, isInverted: false}` when there is
144
- * insufficient data (fewer than 3 rows or zero variance in either variable).
145
- *
146
- * A NEGATIVE correlation means: assets with a HIGH outcome_score have a LOW
147
- * accepted_change_rate — i.e. the assets the proxy rates as "doing well"
148
- * (frequently retrieved) are precisely the ones that rarely yield an accepted
149
- * improvement. That inverts the proxy: high outcome_score ≠ "doing well", so the
150
- * coarse retrieval-delta signal is no longer trustworthy and the 0.10+ rich
151
- * signal is due. (`isInverted = correlation < -0.3`.)
152
- */
153
- export function computeProxyAdequacy(rows) {
154
- const n = rows.length;
155
- if (n < 3)
156
- return { correlation: Number.NaN, n, isInverted: false, isDead: false };
157
- // accepted_change_rate per row.
158
- const xs = rows.map((r) => r.outcome_score);
159
- const ys = rows.map((r) => r.accepted_change_count / Math.max(1, r.retrieval_count));
160
- const meanX = xs.reduce((a, b) => a + b, 0) / n;
161
- const meanY = ys.reduce((a, b) => a + b, 0) / n;
162
- let covXY = 0;
163
- let varX = 0;
164
- let varY = 0;
165
- for (let i = 0; i < n; i++) {
166
- const dx = xs[i] - meanX;
167
- const dy = ys[i] - meanY;
168
- covXY += dx * dy;
169
- varX += dx * dx;
170
- varY += dy * dy;
171
- }
172
- covXY /= n;
173
- varX /= n;
174
- varY /= n;
175
- const denom = Math.sqrt(varX) * Math.sqrt(varY);
176
- if (denom < 1e-12)
177
- return { correlation: Number.NaN, n, isInverted: false, isDead: false };
178
- const correlation = covXY / denom;
179
- // Inverted proxy: negative correlation between outcome and accepted_change_rate
180
- // means high-outcome assets are also high-need — the opposite of "useful".
181
- const isInverted = correlation < -0.3;
182
- // Dead proxy: near-zero correlation at scale — the score is noise.
183
- const isDead = n >= PROXY_DEAD_MIN_N && Math.abs(correlation) < PROXY_DEAD_CORR_THRESHOLD;
184
- return { correlation, n, isInverted, isDead };
56
+ return Math.max(DIVERSITY_FLOOR_FRACTION, Math.max(0, outcomeScore) / maxScore);
185
57
  }
@@ -42,10 +42,7 @@ export function projectMemoryCleanup(input) {
42
42
  },
43
43
  };
44
44
  }
45
- /**
46
- * Apply the final global cap to an already-ranked candidate snapshot.
47
- * Replay remains additive to the ordinary cap, matching the live #610 rule.
48
- */
45
+ /** Apply the final global cap to an already-ranked candidate snapshot. */
49
46
  export function selectEffectiveImproveRefs(args) {
50
47
  const distillOnlySet = new Set(args.distillOnlyRefs.map((entry) => entry.ref));
51
48
  const reflectAndDistill = args.rankedRefs.filter((entry) => !distillOnlySet.has(entry.ref));
@@ -53,10 +50,7 @@ export function selectEffectiveImproveRefs(args) {
53
50
  // Preserve the established live ordering: ordinary reflect-path refs first,
54
51
  // then distill-only refs, with the rank order stable inside each partition.
55
52
  const allLoopRefs = [...reflectAndDistill, ...distillOnly];
56
- const replay = allLoopRefs.filter((entry) => entry.eligibilitySource === "replay");
57
- const ordinary = allLoopRefs.filter((entry) => entry.eligibilitySource !== "replay");
58
- const selectedOrdinary = args.limit === undefined ? ordinary : ordinary.slice(0, args.limit);
59
- const loopRefs = [...selectedOrdinary, ...replay.slice(0, args.replayBudget)];
53
+ const loopRefs = args.limit === undefined ? allLoopRefs : allLoopRefs.slice(0, args.limit);
60
54
  return {
61
55
  loopRefs,
62
56
  distillOnlyRefs: distillOnly,
@@ -82,8 +76,9 @@ export function buildImproveExecutionPlan(input) {
82
76
  limits: {
83
77
  configured: { ...input.configuredLimits },
84
78
  ...(input.effectiveLimit !== undefined ? { effective: input.effectiveLimit } : {}),
85
- additiveReplayAllowance: input.replayBudget,
86
- ...(input.effectiveLimit !== undefined ? { totalCeiling: input.effectiveLimit + input.replayBudget } : {}),
79
+ // The replay lane is gone; the published plan keeps a zero allowance.
80
+ additiveReplayAllowance: 0,
81
+ ...(input.effectiveLimit !== undefined ? { totalCeiling: input.effectiveLimit } : {}),
87
82
  },
88
83
  gates: input.gates.map((gate) => ({ ...gate })),
89
84
  effectiveRefs,