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
@@ -2,20 +2,14 @@
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
- * Top-level `improve` config section (utility decay, salience, collapse
6
- * detector, strategies). Extracted verbatim from the former `config-schema.ts`
7
- * monolith — no behavior change.
5
+ * Top-level `improve` config section (salience, state GC, strategies). Retired
6
+ * keys (`salience.replayBudget`, `collapseDetector`, `utilityDecay`) are
7
+ * tolerated as unknown keys.
8
8
  */
9
9
  import { z } from "zod";
10
10
  import { ImproveProfileConfigSchema } from "./improve-processes.js";
11
11
  import { engineName, nonNegativeNumber } from "./primitives.js";
12
- // ── Improve top-level (utility decay, event retention) ─────────────────────
13
- const ImproveUtilityDecaySchema = z
14
- .object({
15
- halfLifeDays: z.number().finite().min(0.1).optional(),
16
- feedbackStabilityBoost: z.number().finite().min(1).optional(),
17
- })
18
- .passthrough();
12
+ // ── Improve top-level (event retention, salience, state GC) ────────────────
19
13
  const ImproveSalienceSchema = z
20
14
  .object({
21
15
  /**
@@ -34,36 +28,6 @@ const ImproveSalienceSchema = z
34
28
  * Default 0.75. Set to 1.0 to disable the lane entirely.
35
29
  */
36
30
  salienceThreshold: z.number().min(0).max(1).optional(),
37
- /**
38
- * Per-run additive replay budget (#610). Up to this many top-salience refs are
39
- * revisited even with no reactive signal and regardless of cooldown. Additive
40
- * on top of --limit. Default 0 = no replay.
41
- */
42
- replayBudget: z.number().int().min(0).optional(),
43
- })
44
- .passthrough();
45
- // R5 — longitudinal collapse detector (observe-only; deterministic,
46
- // fail-open, runs only on cycles where consolidate did work).
47
- // Default ON; opt out via `improve.collapseDetector.enabled: false`.
48
- // See docs/architecture/specs/improve-collapse-churn-detector-design.md.
49
- // The design's CHURN alert class was removed (never fired in production —
50
- // its accepted-change-volume input was always a hardcoded 0), so this schema
51
- // no longer carries `churnMinAcceptedActions`.
52
- const ImproveCollapseDetectorSchema = z
53
- .object({
54
- enabled: z.boolean().optional(),
55
- // Canary set size minted on first run (owner-approved 30–50 range; default 40).
56
- canaryCount: z.number().int().min(3).max(200).optional(),
57
- // Top-K cutoff for canary recall/nDCG (default 10).
58
- k: z.number().int().min(1).max(100).optional(),
59
- // Trend window in qualifying cycles (default 5).
60
- windowCycles: z.number().int().min(2).max(50).optional(),
61
- // Absolute mean-recall drop vs window median that fires collapse (default 0.15).
62
- recallDropThreshold: z.number().min(0).max(1).optional(),
63
- // distinct-content-ratio decline over the window that fires collapse (default 0.05).
64
- entropyDropThreshold: z.number().min(0).max(1).optional(),
65
- // improve_cycle_metrics retention (default 365 days, owner-approved).
66
- retentionDays: z.number().int().min(1).optional(),
67
31
  })
68
32
  .passthrough();
69
33
  // #733 — orphan-GC pass (Workstream C, lean by design: one config gate).
@@ -85,10 +49,8 @@ const ImproveStateGcSchema = z
85
49
  export const ImproveConfigSchema = z
86
50
  .object({
87
51
  strategies: z.record(engineName, ImproveProfileConfigSchema).optional(),
88
- utilityDecay: ImproveUtilityDecaySchema.optional(),
89
52
  eventRetentionDays: nonNegativeNumber.optional(),
90
53
  salience: ImproveSalienceSchema.optional(),
91
- collapseDetector: ImproveCollapseDetectorSchema.optional(),
92
54
  stateGc: ImproveStateGcSchema.optional(),
93
55
  })
94
56
  .passthrough();
@@ -3,18 +3,18 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { z } from "zod";
5
5
  import { nonEmptyString } from "./primitives.js";
6
- /** One host-local grant allowing an authored asset to create scheduler bindings. */
7
- export const SchedulerActivationSchema = z
8
- .object({
9
- kind: z.enum(["task", "workflow"]),
10
- ref: nonEmptyString,
11
- /** Identity of the configured source this host approved, not merely its mutable bundle name. */
12
- sourceId: z.string().regex(/^sha256:[0-9a-f]{64}$/),
13
- })
14
- .strict();
15
- /** Absence from this allow-list means disabled. */
6
+ /** A 0.9.17-alpha `{kind, ref, sourceId}` activation, read as its ref. */
7
+ const LegacySchedulerActivationSchema = z
8
+ .object({ ref: nonEmptyString })
9
+ .passthrough()
10
+ .transform((activation) => activation.ref);
16
11
  export const SchedulerConfigSchema = z
17
12
  .object({
18
- enabled: z.array(SchedulerActivationSchema).default([]),
13
+ /**
14
+ * Fully-qualified refs (`bundle//tasks/x`, `bundle//workflows/y`) this host
15
+ * schedules. Absent when the host has never chosen: `akm task sync` then
16
+ * takes the akm-written rows already installed as the choice and writes it.
17
+ */
18
+ enabled: z.array(z.union([nonEmptyString, LegacySchedulerActivationSchema])).optional(),
19
19
  })
20
- .strict();
20
+ .passthrough();
@@ -2,29 +2,15 @@
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
- * `search` config section (graph-boost tuning). Extracted verbatim from the
6
- * former `config-schema.ts` monolith — no behavior change.
5
+ * `search` config section: default type exclusion and the optional curate
6
+ * reranker.
7
7
  */
8
8
  import { z } from "zod";
9
- import { httpUrl, nonEmptyString, nonNegativeNumber, positiveInt, symbolicOrWarnApiKey } from "./primitives.js";
9
+ import { httpUrl, nonEmptyString, positiveInt, symbolicOrWarnApiKey } from "./primitives.js";
10
10
  // ── Search ──────────────────────────────────────────────────────────────────
11
- const SearchGraphBoostSchema = z
12
- .object({
13
- directBoostPerEntity: nonNegativeNumber.optional(),
14
- directBoostCap: nonNegativeNumber.optional(),
15
- hopBoostPerEntity: nonNegativeNumber.optional(),
16
- hopBoostCap: nonNegativeNumber.optional(),
17
- /** Hard-capped at 3; values > 3 hard-error so users see the typo. */
18
- maxHops: positiveInt.max(3).optional(),
19
- /** Only "blend" is exercised; "off"/"multiply" were never set in practice and were removed. */
20
- confidenceMode: z.enum(["blend"]).default("blend").optional(),
21
- /** Range [0, 1]; values > 1 hard-error (no silent clamp). */
22
- confidenceWeight: z.number().finite().min(0).max(1).default(0.2).optional(),
23
- })
24
- .passthrough();
25
11
  /**
26
12
  * `search.curateRerank` (#951) — an optional cross-encoder rerank pass over
27
- * `akm curate`'s already-selected candidates.
13
+ * `akm curate`'s top fused candidates.
28
14
  *
29
15
  * Deliberately its own small config arm rather than a third member of the
30
16
  * `engines` map (`EngineConfigSchema` in ./engines.ts): that union's "llm" /
@@ -48,15 +34,13 @@ export const CurateRerankConfigSchema = z
48
34
  model: nonEmptyString.optional(),
49
35
  apiKey: symbolicOrWarnApiKey("search.curateRerank.apiKey").optional(),
50
36
  timeoutMs: positiveInt.optional(),
51
- /** How many of curate's already-ranked candidates to send to the reranker. Default 8. */
37
+ /** How many of the top fused search candidates curate sends to the reranker. Default 30. */
52
38
  topN: positiveInt.max(50).optional(),
53
39
  })
54
- .strict();
40
+ .passthrough();
55
41
  export const SearchConfigSchema = z
56
42
  .object({
57
- minScore: nonNegativeNumber.optional(),
58
43
  defaultExcludeTypes: z.array(nonEmptyString).optional(),
59
- graphBoost: SearchGraphBoostSchema.optional(),
60
44
  curateRerank: CurateRerankConfigSchema.optional(),
61
45
  })
62
46
  .passthrough();
@@ -271,7 +271,6 @@ export function resolveSecretWriteTarget(ref, writeTarget, create) {
271
271
  */
272
272
  export function withEnvSecretWrite(target, ref, op, paths, mutate) {
273
273
  return withWriteTargetMutation(target, paths, {
274
- ignored: "local-only",
275
274
  purpose: `${ref.type}-${op.toLowerCase()}`,
276
275
  message: `${op} ${formatRefForMessage({ type: ref.type, name: ref.name, origin: target.source.name })}`,
277
276
  }, mutate);
@@ -11,13 +11,13 @@ const CONFIG_HINTS = {
11
11
  STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update the default bundle path.",
12
12
  DATA_DIR_UNREADABLE: "The data directory is not readable by the user running akm. Check its owner and mode, or point AKM_DATA_DIR / XDG_DATA_HOME somewhere this user owns.",
13
13
  INDEX_SCHEMA_INCOMPATIBLE: "Run `akm index --full` to rebuild the derived index from the currently materialized sources.",
14
- EMBEDDING_NOT_CONFIGURED: 'Run `akm config set embedding \'{"endpoint":"...","model":"..."}\'` to enable embeddings.',
15
14
  LLM_NOT_CONFIGURED: 'Run `akm setup` or configure an `engines` entry with `kind: "llm"`, then select it with `defaults.llmEngine`.',
16
15
  TEST_ISOLATION_MISSING: "Under bun test, when AKM_BUNDLE_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
17
16
  UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The bundle directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
18
17
  UNKNOWN_IMPROVE_STRATEGY: "Pass one of the listed strategy names to `--strategy`, or define it under `improve.strategies`. Names are case-sensitive.",
19
18
  EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry.",
20
19
  SECRET_REFERENCE_UNRESOLVED: "Check the secret exists (`akm secret list`) and the name after `secret://` matches, or run `akm secret set <name> <value>` to store it.",
20
+ REGISTRY_URL_INVALID: "Registry URLs must be credential-free http(s) URLs. Fix the entry with `akm registry list` / `akm registry add`, or the AKM_REGISTRY_URL / AKM_NPM_REGISTRY variable that supplied it.",
21
21
  };
22
22
  // Code-review finding: COMPOSITION_INVALID covers several unrelated causes
23
23
  // (a rejected with:, a multi-job source, a composition cycle/depth/size
@@ -56,7 +56,7 @@ const USAGE_HINTS = {
56
56
  //
57
57
  // Code-review finding: this default is reached ONLY by with:-rejection
58
58
  // throw sites (the ones above, plus task.ts's noDeclaredInputsError and
59
- // resolve-steps.ts's rejectNonTaskBindingWith) — every other
59
+ // freeze.ts's resolveStep) — every other
60
60
  // COMPOSITION_INVALID throw site (multi-job source, composition
61
61
  // cycle/depth/size, invalid child-output reference, an env: on a
62
62
  // composing step) passes its own explicit constructor hint instead of
@@ -72,19 +72,17 @@ const USAGE_HINTS = {
72
72
  WORKFLOW_SOURCE_INVALID: "Run `akm lint` to see the failing source location, or `akm workflow plan <ref>` to compile it without writing.",
73
73
  INPUT_BINDING_INVALID: "Check the step's with: keys against the target's declared inputs.",
74
74
  TASK_TARGET_UNSUPPORTED: "Task definitions support command, script, workflow, and shell (run:) targets; akm/command is layered by callers.",
75
- // P3a (docs/plans/specs/p3a-plan-v5-child-freeze.md §3.2, A-N2): the
76
- // complete-or-abandon policy for a stored pre-irVersion-5 run.
77
- WORKFLOW_IR_VERSION_UNSUPPORTED: "Abandon the run with `akm workflow abandon <id>`, then start it again from the workflow source — a frozen plan this akm cannot execute is not re-executable in place.",
78
- // P3b (docs/plans/specs/p3b-child-executor.md §4.3).
79
- WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes.",
80
75
  };
81
76
  /** Default hint for each TransientErrorCode. */
82
77
  const TRANSIENT_HINTS = {
83
- RUN_LEASE_HELD: "Wait for the named engine invocation to finish or for the lease to expire, then retry. `akm workflow status <id>` shows the current lease.",
78
+ RUN_LEASE_HELD: "Wait for the akm process driving this run (the named pid) to finish, then retry.",
84
79
  STATE_DB_CONTENDED: "Another akm process is writing state.db right now. Wait a few seconds and retry; commands that support --skip-if-locked can skip instead of failing.",
85
80
  INDEX_DB_CONTENDED: "Another akm process is writing index.db; retry shortly, or pass --skip-if-locked on scheduled runs.",
86
- MAINTENANCE_BARRIER_BUSY: "Another akm process is registering a lock or lease right now. Retry shortly, or pass --skip-if-locked on scheduled index/improve/workflow runs.",
87
81
  IMPROVE_LOCK_HELD: "Another akm improve run holds the whole-run lock right now. Wait for it to finish and retry, or pass --skip-if-locked on scheduled runs.",
82
+ LOCKFILE_CONTENDED: "Another akm process is updating its bundle lockfile right now. Wait a few seconds and retry.",
83
+ ASSET_MUTATION_LEASE_HELD: "Another akm process is writing bundle content right now. Wait for it to finish and retry.",
84
+ SCHEDULER_LOCK_HELD: "Another `akm task sync`, `add`, `enable`, `disable` or `prune` is writing the scheduler right now. Wait for it to finish and retry.",
85
+ REGISTRY_UNREACHABLE: "The registry did not answer in time. Check the network and the registry URL (`akm registry list`), then retry.",
88
86
  };
89
87
  /** Default hint for each NotFoundError code. */
90
88
  const NOT_FOUND_HINTS = {
@@ -97,6 +95,7 @@ const NOT_FOUND_HINTS = {
97
95
  PROPOSAL_NOT_FOUND: "Run `akm proposal list` to see pending proposals and their ids.",
98
96
  FILE_NOT_FOUND: "Check the path exists and is readable.",
99
97
  IMPROVE_RUN_NOT_FOUND: "Run `akm improve` first, or `akm improve report --since 30d` to see recent run ids in `runIds`.",
98
+ REGISTRY_NOT_FOUND: "Check the ref's spelling and version; `akm search <query> --from registry` lists installable refs.",
100
99
  };
101
100
  /**
102
101
  * Base class for all akm-thrown, classified errors. Carries the `kind`
@@ -1,11 +1,20 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * PID-stamped exclusive lock files.
6
+ *
7
+ * A lock is one file created with `O_EXCL` (`wx`), which the filesystem
8
+ * makes atomic: exactly one creator wins, so no further mutex or barrier is
9
+ * needed around acquisition. The payload records the holder's PID (and the
10
+ * launcher PID under a scheduler) so a probe can tell a live holder from a
11
+ * dead one; only a verifiably dead holder — or, when the caller opts in via
12
+ * `staleAfterMs`, an over-age one — is ever reclaimed. Reclaim moves the
13
+ * stale file aside, re-verifies it is the very file that was probed, and only
14
+ * then unlinks it, so two reclaimers cannot both "win" the same stale lock.
15
+ */
4
16
  import { randomUUID } from "node:crypto";
5
17
  import fs from "node:fs";
6
- import path from "node:path";
7
- import { sleepSync } from "../runtime.js";
8
- import { openDatabase } from "../storage/database.js";
9
18
  import { isProcessAlive, MAX_LOCK_METADATA_BYTES, readTextFileDescriptorWithLimit } from "./common.js";
10
19
  function readLockSnapshot(lockPath) {
11
20
  let fd;
@@ -32,51 +41,16 @@ function readLockSnapshot(lockPath) {
32
41
  function sameIdentity(left, right) {
33
42
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
34
43
  }
35
- function operationMutexPath(lockPath) {
36
- // `.sensitive` is an established non-asset suffix across stash walkers. The
37
- // mutex may sit beside a secret/env lock and must never surface as an asset.
38
- return path.join(path.dirname(lockPath), `.${path.basename(lockPath)}.operations.sensitive`);
39
- }
40
- /**
41
- * Serialize every mutation of one canonical lock path. SQLite's write lock is
42
- * released by the OS when a process dies, so this mutex needs no stale-owner
43
- * deletion protocol (which would reproduce the same check/rename race it is
44
- * meant to prevent).
45
- */
46
- function withLockOperationMutex(lockPath, run) {
47
- const db = openDatabase(operationMutexPath(lockPath));
48
- let began = false;
44
+ function releaseLockRaw(lockPath) {
49
45
  try {
50
- db.exec("PRAGMA busy_timeout = 30000");
51
- for (let attempt = 0; attempt < 5 && !began; attempt += 1) {
52
- db.exec("BEGIN IMMEDIATE");
53
- began = db.inTransaction;
54
- if (!began)
55
- sleepSync(2 ** attempt);
56
- }
57
- if (!began)
58
- throw new Error(`Could not acquire lock operation mutex for ${lockPath}.`);
59
- const result = run();
60
- db.exec("COMMIT");
61
- began = false;
62
- return result;
63
- }
64
- catch (error) {
65
- if (began && db.inTransaction) {
66
- try {
67
- db.exec("ROLLBACK");
68
- }
69
- catch {
70
- // Preserve the operation failure.
71
- }
72
- }
73
- throw error;
46
+ fs.unlinkSync(lockPath);
74
47
  }
75
- finally {
76
- db.close();
48
+ catch {
49
+ // Already gone.
77
50
  }
78
51
  }
79
- function tryAcquireLockRaw(lockPath, payload) {
52
+ /** Create the lock file atomically; `undefined` when another holder already has it. */
53
+ export function tryAcquireLockSync(lockPath, payload) {
80
54
  try {
81
55
  fs.writeFileSync(lockPath, payload, { flag: "wx" });
82
56
  }
@@ -99,35 +73,6 @@ function tryAcquireLockRaw(lockPath, payload) {
99
73
  }
100
74
  return { lockPath, ...snapshot };
101
75
  }
102
- function releaseLockRaw(lockPath) {
103
- try {
104
- fs.unlinkSync(lockPath);
105
- }
106
- catch {
107
- // Sentinel already gone — fine.
108
- }
109
- }
110
- /**
111
- * Atomically create a sentinel at `lockPath` with `payload` as the body.
112
- * Returns an exact ownership handle if we now own the lock, or undefined if a sentinel already
113
- * exists (EEXIST). Throws any other error (permissions, missing parent
114
- * dir, etc.) — callers must ensure the parent directory exists.
115
- *
116
- * `payload` is typically `String(process.pid)` for the simple cases or
117
- * a small JSON envelope for callers that want richer metadata
118
- * (improve.ts records pid + startedAt so audit can correlate runs).
119
- */
120
- export function tryAcquireLockSync(lockPath, payload) {
121
- return withLockOperationMutex(lockPath, () => tryAcquireLockRaw(lockPath, payload));
122
- }
123
- /**
124
- * Best-effort launcher pid from `AKM_LAUNCHER_PID` (set by
125
- * `scripts/node-runtime/akm`/`akm-migrate`, #956) — undefined when unset,
126
- * empty, or not a positive integer (never trust an ambient env var blindly
127
- * into a lock message). Also the gate the parent-death watchdog
128
- * (`core/parent-watchdog.ts`) uses to stay inert outside a launcher-managed
129
- * run.
130
- */
131
76
  export function launcherPidFromEnv() {
132
77
  const raw = process.env.AKM_LAUNCHER_PID;
133
78
  if (!raw)
@@ -135,13 +80,6 @@ export function launcherPidFromEnv() {
135
80
  const pid = Number.parseInt(raw, 10);
136
81
  return Number.isInteger(pid) && pid > 0 ? pid : undefined;
137
82
  }
138
- /**
139
- * Build a PID-bearing payload with a unique token for one acquisition attempt.
140
- * Adds `launcherPid` (#956) whenever this process is running under the
141
- * published launcher, so a lock's holder can be identified by the pid every
142
- * process listing and task log actually shows (the launcher's) as well as
143
- * the pid that holds the lock (the bun/node child).
144
- */
145
83
  export function createLockPayload(metadata = {}) {
146
84
  const launcherPid = launcherPidFromEnv();
147
85
  return JSON.stringify({
@@ -151,26 +89,12 @@ export function createLockPayload(metadata = {}) {
151
89
  lockId: randomUUID(),
152
90
  });
153
91
  }
154
- /**
155
- * Inspect an existing sentinel at `lockPath` without modifying it.
156
- * Returns:
157
- * - `absent` if the file does not exist.
158
- * - `stale` if the file is present but should be reclaimed (the holding
159
- * PID is dead, the content is unparseable, or the lock has exceeded
160
- * `staleAfterMs`). Includes the failure reason so callers can log it.
161
- * - `held` if the lock has a live holder and is not yet age-expired.
162
- *
163
- * Does NOT remove the file. Callers decide recovery policy.
164
- */
165
92
  export function probeLock(lockPath, opts) {
166
93
  let snapshot;
167
94
  try {
168
95
  snapshot = readLockSnapshot(lockPath);
169
96
  }
170
97
  catch (error) {
171
- // A permission error means the lock may be genuinely HELD by someone we
172
- // cannot see. Reporting it as stale would invite a caller to steal a live
173
- // lease (#791) — `unreadable` stays for the corrupt/undecodable case.
174
98
  const code = error?.code;
175
99
  if (code === "EACCES" || code === "EPERM")
176
100
  return { state: "inaccessible", code };
@@ -193,102 +117,81 @@ export function probeLock(lockPath, opts) {
193
117
  return { state: "held", holderPid, launcherPid, ageMs, rawContent, identity };
194
118
  }
195
119
  /**
196
- * Revalidate and quarantine the probed sentinel while holding the same operation
197
- * mutex used by acquisitions. A newer owner therefore cannot be renamed in the
198
- * check/quarantine window, and a third contender cannot acquire until cleanup
199
- * has completed.
120
+ * Remove a lock that `probeLock` reported stale. Returns `false` when the file
121
+ * changed since the probe (someone else reclaimed or re-acquired it) so the
122
+ * caller re-probes instead of assuming the path is free.
200
123
  */
201
124
  export function reclaimStaleLock(lockPath, probe, options) {
202
125
  if (probe.rawContent === undefined || probe.identity === undefined)
203
126
  return false;
204
127
  const expectedContent = probe.rawContent;
205
128
  const expectedIdentity = probe.identity;
206
- return withLockOperationMutex(lockPath, () => {
207
- let current;
208
- try {
209
- current = readLockSnapshot(lockPath);
210
- }
211
- catch {
212
- return false;
213
- }
214
- if (!current || current.rawContent !== expectedContent || !sameIdentity(current.identity, expectedIdentity)) {
129
+ let current;
130
+ try {
131
+ current = readLockSnapshot(lockPath);
132
+ }
133
+ catch {
134
+ return false;
135
+ }
136
+ if (!current || current.rawContent !== expectedContent || !sameIdentity(current.identity, expectedIdentity)) {
137
+ return false;
138
+ }
139
+ const quarantinePath = `${lockPath}.stale-${process.pid}-${randomUUID()}`;
140
+ try {
141
+ fs.renameSync(lockPath, quarantinePath);
142
+ }
143
+ catch (err) {
144
+ if (err.code === "ENOENT")
215
145
  return false;
216
- }
217
- const quarantinePath = `${lockPath}.stale-${process.pid}-${randomUUID()}`;
146
+ throw err;
147
+ }
148
+ let quarantined;
149
+ try {
150
+ quarantined = readLockSnapshot(quarantinePath);
151
+ }
152
+ catch {
153
+ quarantined = undefined;
154
+ }
155
+ if (!quarantined ||
156
+ quarantined.rawContent !== expectedContent ||
157
+ !sameIdentity(quarantined.identity, expectedIdentity)) {
158
+ // The file we moved aside is not the one we probed: a fresh holder took
159
+ // the path in between. Put it back and report no reclaim.
218
160
  try {
219
- fs.renameSync(lockPath, quarantinePath);
161
+ fs.linkSync(quarantinePath, lockPath);
220
162
  }
221
163
  catch (err) {
222
- if (err.code === "ENOENT")
223
- return false;
224
- throw err;
164
+ if (err.code !== "EEXIST")
165
+ throw err;
225
166
  }
226
- let quarantined;
227
- try {
228
- quarantined = readLockSnapshot(quarantinePath);
229
- }
230
- catch {
231
- quarantined = undefined;
232
- }
233
- if (!quarantined ||
234
- quarantined.rawContent !== expectedContent ||
235
- !sameIdentity(quarantined.identity, expectedIdentity)) {
236
- try {
237
- // Restore without replacing a non-cooperating lock installed after quarantine.
238
- fs.linkSync(quarantinePath, lockPath);
239
- }
240
- catch (err) {
241
- if (err.code !== "EEXIST")
242
- throw err;
243
- }
244
- releaseLockRaw(quarantinePath);
167
+ releaseLockRaw(quarantinePath);
168
+ return false;
169
+ }
170
+ options?.afterQuarantineVerified?.();
171
+ try {
172
+ fs.unlinkSync(quarantinePath);
173
+ return true;
174
+ }
175
+ catch (err) {
176
+ if (err.code === "ENOENT")
245
177
  return false;
246
- }
247
- options?.afterQuarantineVerified?.();
248
- try {
249
- fs.unlinkSync(quarantinePath);
250
- return true;
251
- }
252
- catch (err) {
253
- if (err.code === "ENOENT")
254
- return false;
255
- throw err;
256
- }
257
- });
178
+ throw err;
179
+ }
258
180
  }
259
- /**
260
- * Release only the exact sentinel returned by `tryAcquireLockSync`. Content and
261
- * file identity are revalidated while holding the acquisition operation mutex,
262
- * so a stale holder cannot remove a successor. Synchronous and idempotent so it
263
- * is safe in both `finally` blocks and process exit handlers.
264
- */
181
+ /** Unlink the lock only while it is still the exact file this owner created. */
265
182
  export function releaseLock(ownership) {
266
183
  const { lockPath } = ownership;
267
- if (!fs.existsSync(lockPath) && !fs.existsSync(operationMutexPath(lockPath)))
184
+ let current;
185
+ try {
186
+ current = readLockSnapshot(lockPath);
187
+ }
188
+ catch {
268
189
  return;
269
- withLockOperationMutex(lockPath, () => {
270
- let current;
271
- try {
272
- current = readLockSnapshot(lockPath);
273
- }
274
- catch {
275
- // Absent or unreadable — nothing of ours to release.
276
- return;
277
- }
278
- if (current && current.rawContent === ownership.rawContent && sameIdentity(current.identity, ownership.identity)) {
279
- releaseLockRaw(lockPath);
280
- }
281
- });
190
+ }
191
+ if (current && current.rawContent === ownership.rawContent && sameIdentity(current.identity, ownership.identity)) {
192
+ releaseLockRaw(lockPath);
193
+ }
282
194
  }
283
- /**
284
- * Extract a holder pid, and (#956) a launcher pid when the payload recorded
285
- * one, from a sentinel body. Accepts the two shapes used across the
286
- * codebase: a bare numeric string (config-io, vault, lockfile — never
287
- * carries a `launcherPid`) and a JSON object with `pid`/`launcherPid` fields
288
- * (`createLockPayload`). `holderPid` is undefined when the body is
289
- * unparseable or yields a non-positive integer; `launcherPid` is undefined
290
- * whenever the payload has none, independent of whether `holderPid` parsed.
291
- */
292
195
  function extractLockIdentity(content) {
293
196
  const trimmed = content.trim();
294
197
  if (!trimmed)
@@ -33,13 +33,13 @@
33
33
  * ## Schema evolution
34
34
  *
35
35
  * Same migration-safety contract as state.db: append-only `MIGRATIONS` applied
36
- * through the shared runner in src/storage/engines/sqlite-migrations.ts.
36
+ * through the shared runner in src/storage/sqlite-migrations.ts.
37
37
  *
38
38
  * @module logs-db
39
39
  */
40
40
  import path from "node:path";
41
- import { assertMigrationRegistry, runMigrations as runSqliteMigrations, } from "../storage/engines/sqlite-migrations.js";
42
41
  import { openManagedDatabase } from "../storage/managed-db.js";
42
+ import { assertMigrationRegistry, runMigrations as runSqliteMigrations, } from "../storage/sqlite-migrations.js";
43
43
  import { getDataDir } from "./paths.js";
44
44
  // ── Path helper ──────────────────────────────────────────────────────────────
45
45
  /**
@@ -245,9 +245,6 @@ export function getIndexWriterLockPath() {
245
245
  export function getIndexRebuildLockPath() {
246
246
  return path.join(getDataDir(), "index.rebuild.lock");
247
247
  }
248
- export function getMaintenanceBarrierPath() {
249
- return path.join(getDataDir(), "maintenance.barrier.lock");
250
- }
251
248
  /** Path to the state.db file in $DATA. */
252
249
  export function getStateDbPathInDataDir() {
253
250
  return path.join(getDataDir(), "state.db");
@@ -339,30 +336,6 @@ export function getStashStateKey(stashDir) {
339
336
  function stashScopedDir(base, stashDir) {
340
337
  return path.join(base, getStashStateKey(stashDir));
341
338
  }
342
- /**
343
- * `$STATE/improve/distill-rejected/<stash>/` — lessons that failed the
344
- * distill quality gate. Moved out of `$STASH/.akm/distill-rejected/`
345
- * (itlackey/akm#890): nothing reads it to resolve bundle content, so it does
346
- * not meet the "must travel with the content" rule.
347
- */
348
- export function getDistillRejectedDir(stashDir) {
349
- return stashScopedDir(path.join(getStateDir(), "improve", "distill-rejected"), stashDir);
350
- }
351
- /**
352
- * `$STATE/improve/eval-cases/<stash>/` — regression eval cases captured from
353
- * rejected distill/proposal output. Moved out of `$STASH/.akm/eval-cases/`
354
- * (itlackey/akm#890).
355
- *
356
- * R10: the writer (`src/commands/improve/eval-cases.ts`) was removed —
357
- * nothing ever read the files it wrote, and a rejected proposal row now
358
- * carries the same information (see `quality-gate.ts`'s
359
- * `writeQualityRejection`). This resolver stays: `scripts/akm-migrate/migrate/
360
- * writer-relocation.ts` still uses it to relocate pre-existing eval-case
361
- * files an older release wrote to the legacy `$STASH/.akm/eval-cases/` path.
362
- */
363
- export function getEvalCasesDir(stashDir) {
364
- return stashScopedDir(path.join(getStateDir(), "improve", "eval-cases"), stashDir);
365
- }
366
339
  /**
367
340
  * `$STATE/improve/measurement/verdicts/<stash>/` — `akm-eval-proactive-verdict`
368
341
  * reports. Moved out of `$STASH/.akm/measurement/verdicts/` (itlackey/akm#890);