@jamesaphoenix/tx-core 0.4.2 → 0.4.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 (336) hide show
  1. package/README.md +480 -0
  2. package/dist/db.d.ts +28 -14
  3. package/dist/db.d.ts.map +1 -1
  4. package/dist/db.js +108 -14
  5. package/dist/db.js.map +1 -1
  6. package/dist/errors.d.ts +178 -34
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +119 -26
  9. package/dist/errors.js.map +1 -1
  10. package/dist/id.d.ts +10 -0
  11. package/dist/id.d.ts.map +1 -1
  12. package/dist/id.js +17 -1
  13. package/dist/id.js.map +1 -1
  14. package/dist/index.d.ts +15 -7
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +62 -8
  17. package/dist/index.js.map +1 -1
  18. package/dist/layer.d.ts +23 -14
  19. package/dist/layer.d.ts.map +1 -1
  20. package/dist/layer.js +75 -76
  21. package/dist/layer.js.map +1 -1
  22. package/dist/mappers/attempt.d.ts +3 -1
  23. package/dist/mappers/attempt.d.ts.map +1 -1
  24. package/dist/mappers/attempt.js +23 -9
  25. package/dist/mappers/attempt.js.map +1 -1
  26. package/dist/mappers/claim.d.ts +1 -1
  27. package/dist/mappers/claim.d.ts.map +1 -1
  28. package/dist/mappers/claim.js +11 -4
  29. package/dist/mappers/claim.js.map +1 -1
  30. package/dist/mappers/deduplication.d.ts +13 -1
  31. package/dist/mappers/deduplication.d.ts.map +1 -1
  32. package/dist/mappers/deduplication.js +22 -3
  33. package/dist/mappers/deduplication.js.map +1 -1
  34. package/dist/mappers/doc.d.ts +24 -0
  35. package/dist/mappers/doc.d.ts.map +1 -0
  36. package/dist/mappers/doc.js +161 -0
  37. package/dist/mappers/doc.js.map +1 -0
  38. package/dist/mappers/file-learning.d.ts.map +1 -1
  39. package/dist/mappers/file-learning.js +2 -1
  40. package/dist/mappers/file-learning.js.map +1 -1
  41. package/dist/mappers/index.d.ts +6 -7
  42. package/dist/mappers/index.d.ts.map +1 -1
  43. package/dist/mappers/index.js +10 -12
  44. package/dist/mappers/index.js.map +1 -1
  45. package/dist/mappers/learning.d.ts +9 -1
  46. package/dist/mappers/learning.d.ts.map +1 -1
  47. package/dist/mappers/learning.js +94 -14
  48. package/dist/mappers/learning.js.map +1 -1
  49. package/dist/mappers/orchestrator-state.d.ts +1 -1
  50. package/dist/mappers/orchestrator-state.d.ts.map +1 -1
  51. package/dist/mappers/orchestrator-state.js +31 -5
  52. package/dist/mappers/orchestrator-state.js.map +1 -1
  53. package/dist/mappers/parse-date.d.ts +11 -0
  54. package/dist/mappers/parse-date.d.ts.map +1 -0
  55. package/dist/mappers/parse-date.js +18 -0
  56. package/dist/mappers/parse-date.js.map +1 -0
  57. package/dist/mappers/run.d.ts +14 -4
  58. package/dist/mappers/run.d.ts.map +1 -1
  59. package/dist/mappers/run.js +49 -18
  60. package/dist/mappers/run.js.map +1 -1
  61. package/dist/mappers/task.d.ts +5 -1
  62. package/dist/mappers/task.d.ts.map +1 -1
  63. package/dist/mappers/task.js +66 -16
  64. package/dist/mappers/task.js.map +1 -1
  65. package/dist/mappers/tracked-project.d.ts +3 -1
  66. package/dist/mappers/tracked-project.d.ts.map +1 -1
  67. package/dist/mappers/tracked-project.js +23 -9
  68. package/dist/mappers/tracked-project.js.map +1 -1
  69. package/dist/mappers/worker.d.ts +1 -1
  70. package/dist/mappers/worker.d.ts.map +1 -1
  71. package/dist/mappers/worker.js +44 -6
  72. package/dist/mappers/worker.js.map +1 -1
  73. package/dist/repo/attempt-repo.d.ts +2 -2
  74. package/dist/repo/attempt-repo.d.ts.map +1 -1
  75. package/dist/repo/attempt-repo.js +16 -6
  76. package/dist/repo/attempt-repo.js.map +1 -1
  77. package/dist/repo/claim-repo.d.ts +46 -2
  78. package/dist/repo/claim-repo.d.ts.map +1 -1
  79. package/dist/repo/claim-repo.js +113 -6
  80. package/dist/repo/claim-repo.js.map +1 -1
  81. package/dist/repo/deduplication-repo.d.ts +9 -1
  82. package/dist/repo/deduplication-repo.d.ts.map +1 -1
  83. package/dist/repo/deduplication-repo.js +46 -9
  84. package/dist/repo/deduplication-repo.js.map +1 -1
  85. package/dist/repo/dep-repo.d.ts +27 -3
  86. package/dist/repo/dep-repo.d.ts.map +1 -1
  87. package/dist/repo/dep-repo.js +166 -39
  88. package/dist/repo/dep-repo.js.map +1 -1
  89. package/dist/repo/doc-repo.d.ts +59 -0
  90. package/dist/repo/doc-repo.d.ts.map +1 -0
  91. package/dist/repo/doc-repo.js +276 -0
  92. package/dist/repo/doc-repo.js.map +1 -0
  93. package/dist/repo/file-learning-repo.d.ts +3 -3
  94. package/dist/repo/file-learning-repo.d.ts.map +1 -1
  95. package/dist/repo/file-learning-repo.js +19 -8
  96. package/dist/repo/file-learning-repo.js.map +1 -1
  97. package/dist/repo/index.d.ts +4 -6
  98. package/dist/repo/index.d.ts.map +1 -1
  99. package/dist/repo/index.js +3 -5
  100. package/dist/repo/index.js.map +1 -1
  101. package/dist/repo/learning-repo.d.ts +10 -3
  102. package/dist/repo/learning-repo.d.ts.map +1 -1
  103. package/dist/repo/learning-repo.js +68 -11
  104. package/dist/repo/learning-repo.js.map +1 -1
  105. package/dist/repo/orchestrator-state-repo.d.ts.map +1 -1
  106. package/dist/repo/orchestrator-state-repo.js +8 -1
  107. package/dist/repo/orchestrator-state-repo.js.map +1 -1
  108. package/dist/repo/run-repo.d.ts +3 -3
  109. package/dist/repo/run-repo.d.ts.map +1 -1
  110. package/dist/repo/run-repo.js +40 -19
  111. package/dist/repo/run-repo.js.map +1 -1
  112. package/dist/repo/task-repo.d.ts +14 -3
  113. package/dist/repo/task-repo.d.ts.map +1 -1
  114. package/dist/repo/task-repo.js +194 -20
  115. package/dist/repo/task-repo.js.map +1 -1
  116. package/dist/repo/tracked-project-repo.d.ts.map +1 -1
  117. package/dist/repo/tracked-project-repo.js +15 -1
  118. package/dist/repo/tracked-project-repo.js.map +1 -1
  119. package/dist/repo/worker-repo.d.ts +3 -2
  120. package/dist/repo/worker-repo.d.ts.map +1 -1
  121. package/dist/repo/worker-repo.js +54 -8
  122. package/dist/repo/worker-repo.js.map +1 -1
  123. package/dist/schemas/sync.js +2 -2
  124. package/dist/schemas/sync.js.map +1 -1
  125. package/dist/schemas/worker.d.ts +1 -0
  126. package/dist/schemas/worker.d.ts.map +1 -1
  127. package/dist/schemas/worker.js +1 -0
  128. package/dist/schemas/worker.js.map +1 -1
  129. package/dist/services/agent-service.d.ts +57 -0
  130. package/dist/services/agent-service.d.ts.map +1 -0
  131. package/dist/services/agent-service.js +81 -0
  132. package/dist/services/agent-service.js.map +1 -0
  133. package/dist/services/attempt-service.d.ts.map +1 -1
  134. package/dist/services/attempt-service.js +1 -4
  135. package/dist/services/attempt-service.js.map +1 -1
  136. package/dist/services/auto-sync-service.d.ts.map +1 -1
  137. package/dist/services/auto-sync-service.js +18 -10
  138. package/dist/services/auto-sync-service.js.map +1 -1
  139. package/dist/services/claim-service.d.ts +8 -2
  140. package/dist/services/claim-service.d.ts.map +1 -1
  141. package/dist/services/claim-service.js +37 -23
  142. package/dist/services/claim-service.js.map +1 -1
  143. package/dist/services/cycle-scan-service.d.ts +32 -0
  144. package/dist/services/cycle-scan-service.d.ts.map +1 -0
  145. package/dist/services/cycle-scan-service.js +546 -0
  146. package/dist/services/cycle-scan-service.js.map +1 -0
  147. package/dist/services/daemon-service.d.ts +40 -2
  148. package/dist/services/daemon-service.d.ts.map +1 -1
  149. package/dist/services/daemon-service.js +199 -52
  150. package/dist/services/daemon-service.js.map +1 -1
  151. package/dist/services/deduplication-service.d.ts +8 -4
  152. package/dist/services/deduplication-service.d.ts.map +1 -1
  153. package/dist/services/deduplication-service.js +79 -25
  154. package/dist/services/deduplication-service.js.map +1 -1
  155. package/dist/services/dep-service.d.ts +2 -2
  156. package/dist/services/dep-service.d.ts.map +1 -1
  157. package/dist/services/dep-service.js +9 -5
  158. package/dist/services/dep-service.js.map +1 -1
  159. package/dist/services/diversifier-service.d.ts +2 -1
  160. package/dist/services/diversifier-service.d.ts.map +1 -1
  161. package/dist/services/diversifier-service.js +37 -43
  162. package/dist/services/diversifier-service.js.map +1 -1
  163. package/dist/services/doc-service.d.ts +49 -0
  164. package/dist/services/doc-service.d.ts.map +1 -0
  165. package/dist/services/doc-service.js +605 -0
  166. package/dist/services/doc-service.js.map +1 -0
  167. package/dist/services/embedding-service.d.ts +66 -2
  168. package/dist/services/embedding-service.d.ts.map +1 -1
  169. package/dist/services/embedding-service.js +138 -24
  170. package/dist/services/embedding-service.js.map +1 -1
  171. package/dist/services/file-learning-service.d.ts.map +1 -1
  172. package/dist/services/file-learning-service.js +8 -7
  173. package/dist/services/file-learning-service.js.map +1 -1
  174. package/dist/services/file-watcher-service.d.ts.map +1 -1
  175. package/dist/services/file-watcher-service.js +58 -11
  176. package/dist/services/file-watcher-service.js.map +1 -1
  177. package/dist/services/hierarchy-service.d.ts +1 -1
  178. package/dist/services/hierarchy-service.d.ts.map +1 -1
  179. package/dist/services/hierarchy-service.js +50 -32
  180. package/dist/services/hierarchy-service.js.map +1 -1
  181. package/dist/services/index.d.ts +13 -15
  182. package/dist/services/index.d.ts.map +1 -1
  183. package/dist/services/index.js +13 -15
  184. package/dist/services/index.js.map +1 -1
  185. package/dist/services/learning-service.d.ts +3 -3
  186. package/dist/services/learning-service.d.ts.map +1 -1
  187. package/dist/services/learning-service.js +75 -42
  188. package/dist/services/learning-service.js.map +1 -1
  189. package/dist/services/llm-service.d.ts +62 -0
  190. package/dist/services/llm-service.d.ts.map +1 -0
  191. package/dist/services/llm-service.js +172 -0
  192. package/dist/services/llm-service.js.map +1 -0
  193. package/dist/services/migration-service.d.ts +1 -1
  194. package/dist/services/migration-service.d.ts.map +1 -1
  195. package/dist/services/migration-service.js +18 -7
  196. package/dist/services/migration-service.js.map +1 -1
  197. package/dist/services/orchestrator-service.d.ts +4 -3
  198. package/dist/services/orchestrator-service.d.ts.map +1 -1
  199. package/dist/services/orchestrator-service.js +66 -27
  200. package/dist/services/orchestrator-service.js.map +1 -1
  201. package/dist/services/query-expansion-service.d.ts +30 -9
  202. package/dist/services/query-expansion-service.d.ts.map +1 -1
  203. package/dist/services/query-expansion-service.js +54 -63
  204. package/dist/services/query-expansion-service.js.map +1 -1
  205. package/dist/services/ready-service.d.ts +21 -1
  206. package/dist/services/ready-service.d.ts.map +1 -1
  207. package/dist/services/ready-service.js +44 -21
  208. package/dist/services/ready-service.js.map +1 -1
  209. package/dist/services/retriever-service.d.ts +10 -10
  210. package/dist/services/retriever-service.d.ts.map +1 -1
  211. package/dist/services/retriever-service.js +53 -161
  212. package/dist/services/retriever-service.js.map +1 -1
  213. package/dist/services/sync-service.d.ts +17 -4
  214. package/dist/services/sync-service.d.ts.map +1 -1
  215. package/dist/services/sync-service.js +381 -116
  216. package/dist/services/sync-service.js.map +1 -1
  217. package/dist/services/task-service.d.ts +6 -4
  218. package/dist/services/task-service.d.ts.map +1 -1
  219. package/dist/services/task-service.js +165 -35
  220. package/dist/services/task-service.js.map +1 -1
  221. package/dist/services/tracing-service.d.ts +55 -0
  222. package/dist/services/tracing-service.d.ts.map +1 -0
  223. package/dist/services/tracing-service.js +99 -0
  224. package/dist/services/tracing-service.js.map +1 -0
  225. package/dist/services/transcript-adapter.d.ts +99 -0
  226. package/dist/services/transcript-adapter.d.ts.map +1 -0
  227. package/dist/services/transcript-adapter.js +283 -0
  228. package/dist/services/transcript-adapter.js.map +1 -0
  229. package/dist/services/validation-service.d.ts +85 -0
  230. package/dist/services/validation-service.d.ts.map +1 -0
  231. package/dist/services/validation-service.js +289 -0
  232. package/dist/services/validation-service.js.map +1 -0
  233. package/dist/services/worker-process.d.ts +23 -4
  234. package/dist/services/worker-process.d.ts.map +1 -1
  235. package/dist/services/worker-process.js +168 -72
  236. package/dist/services/worker-process.js.map +1 -1
  237. package/dist/services/worker-service.d.ts.map +1 -1
  238. package/dist/services/worker-service.js +7 -12
  239. package/dist/services/worker-service.js.map +1 -1
  240. package/dist/sync/claude-task-writer.d.ts +49 -0
  241. package/dist/sync/claude-task-writer.d.ts.map +1 -0
  242. package/dist/sync/claude-task-writer.js +135 -0
  243. package/dist/sync/claude-task-writer.js.map +1 -0
  244. package/dist/utils/doc-hash.d.ts +10 -0
  245. package/dist/utils/doc-hash.d.ts.map +1 -0
  246. package/dist/utils/doc-hash.js +14 -0
  247. package/dist/utils/doc-hash.js.map +1 -0
  248. package/dist/utils/doc-renderer.d.ts +44 -0
  249. package/dist/utils/doc-renderer.d.ts.map +1 -0
  250. package/dist/utils/doc-renderer.js +202 -0
  251. package/dist/utils/doc-renderer.js.map +1 -0
  252. package/dist/utils/math.d.ts +5 -1
  253. package/dist/utils/math.d.ts.map +1 -1
  254. package/dist/utils/math.js +12 -4
  255. package/dist/utils/math.js.map +1 -1
  256. package/dist/utils/sql.d.ts +9 -0
  257. package/dist/utils/sql.d.ts.map +1 -0
  258. package/dist/utils/sql.js +9 -0
  259. package/dist/utils/sql.js.map +1 -0
  260. package/dist/utils/toml-config.d.ts +22 -0
  261. package/dist/utils/toml-config.d.ts.map +1 -0
  262. package/dist/utils/toml-config.js +75 -0
  263. package/dist/utils/toml-config.js.map +1 -0
  264. package/dist/worker/hooks.d.ts +102 -0
  265. package/dist/worker/hooks.d.ts.map +1 -0
  266. package/dist/worker/hooks.js +11 -0
  267. package/dist/worker/hooks.js.map +1 -0
  268. package/dist/worker/index.d.ts +9 -0
  269. package/dist/worker/index.d.ts.map +1 -0
  270. package/dist/worker/index.js +8 -0
  271. package/dist/worker/index.js.map +1 -0
  272. package/dist/worker/run-worker.d.ts +33 -0
  273. package/dist/worker/run-worker.d.ts.map +1 -0
  274. package/dist/worker/run-worker.js +265 -0
  275. package/dist/worker/run-worker.js.map +1 -0
  276. package/package.json +14 -12
  277. package/dist/mappers/anchor.d.ts +0 -14
  278. package/dist/mappers/anchor.d.ts.map +0 -1
  279. package/dist/mappers/anchor.js +0 -38
  280. package/dist/mappers/anchor.js.map +0 -1
  281. package/dist/mappers/candidate.d.ts +0 -23
  282. package/dist/mappers/candidate.d.ts.map +0 -1
  283. package/dist/mappers/candidate.js +0 -53
  284. package/dist/mappers/candidate.js.map +0 -1
  285. package/dist/mappers/edge.d.ts +0 -10
  286. package/dist/mappers/edge.d.ts.map +0 -1
  287. package/dist/mappers/edge.js +0 -19
  288. package/dist/mappers/edge.js.map +0 -1
  289. package/dist/repo/anchor-repo.d.ts +0 -52
  290. package/dist/repo/anchor-repo.d.ts.map +0 -1
  291. package/dist/repo/anchor-repo.js +0 -204
  292. package/dist/repo/anchor-repo.js.map +0 -1
  293. package/dist/repo/candidate-repo.d.ts +0 -16
  294. package/dist/repo/candidate-repo.d.ts.map +0 -1
  295. package/dist/repo/candidate-repo.js +0 -143
  296. package/dist/repo/candidate-repo.js.map +0 -1
  297. package/dist/repo/edge-repo.d.ts +0 -26
  298. package/dist/repo/edge-repo.d.ts.map +0 -1
  299. package/dist/repo/edge-repo.js +0 -227
  300. package/dist/repo/edge-repo.js.map +0 -1
  301. package/dist/services/anchor-service.d.ts +0 -147
  302. package/dist/services/anchor-service.d.ts.map +0 -1
  303. package/dist/services/anchor-service.js +0 -540
  304. package/dist/services/anchor-service.js.map +0 -1
  305. package/dist/services/anchor-verification.d.ts +0 -94
  306. package/dist/services/anchor-verification.d.ts.map +0 -1
  307. package/dist/services/anchor-verification.js +0 -617
  308. package/dist/services/anchor-verification.js.map +0 -1
  309. package/dist/services/ast-grep-service.d.ts +0 -58
  310. package/dist/services/ast-grep-service.d.ts.map +0 -1
  311. package/dist/services/ast-grep-service.js +0 -356
  312. package/dist/services/ast-grep-service.js.map +0 -1
  313. package/dist/services/candidate-extractor-service.d.ts +0 -56
  314. package/dist/services/candidate-extractor-service.d.ts.map +0 -1
  315. package/dist/services/candidate-extractor-service.js +0 -365
  316. package/dist/services/candidate-extractor-service.js.map +0 -1
  317. package/dist/services/edge-service.d.ts +0 -78
  318. package/dist/services/edge-service.d.ts.map +0 -1
  319. package/dist/services/edge-service.js +0 -158
  320. package/dist/services/edge-service.js.map +0 -1
  321. package/dist/services/feedback-tracker.d.ts +0 -64
  322. package/dist/services/feedback-tracker.d.ts.map +0 -1
  323. package/dist/services/feedback-tracker.js +0 -110
  324. package/dist/services/feedback-tracker.js.map +0 -1
  325. package/dist/services/graph-expansion.d.ts +0 -155
  326. package/dist/services/graph-expansion.d.ts.map +0 -1
  327. package/dist/services/graph-expansion.js +0 -466
  328. package/dist/services/graph-expansion.js.map +0 -1
  329. package/dist/services/promotion-service.d.ts +0 -67
  330. package/dist/services/promotion-service.d.ts.map +0 -1
  331. package/dist/services/promotion-service.js +0 -151
  332. package/dist/services/promotion-service.js.map +0 -1
  333. package/dist/services/swarm-verification.d.ts +0 -104
  334. package/dist/services/swarm-verification.d.ts.map +0 -1
  335. package/dist/services/swarm-verification.js +0 -400
  336. package/dist/services/swarm-verification.js.map +0 -1
@@ -1,151 +0,0 @@
1
- import { Context, Effect, Layer } from "effect";
2
- import { CandidateNotFoundError, DatabaseError, ValidationError } from "../errors.js";
3
- import { CandidateRepository } from "../repo/candidate-repo.js";
4
- import { LearningService } from "./learning-service.js";
5
- import { EdgeService } from "./edge-service.js";
6
- /**
7
- * PromotionService manages the lifecycle of learning candidates,
8
- * including listing, promoting to learnings, rejecting, and auto-promotion.
9
- *
10
- * @see PRD-015 for the knowledge promotion pipeline
11
- */
12
- export class PromotionService extends Context.Tag("PromotionService")() {
13
- }
14
- /** Duplicate detection threshold for auto-promotion (0.85 = high similarity) */
15
- const DUPLICATE_MIN_SCORE = 0.85;
16
- export const PromotionServiceLive = Layer.effect(PromotionService, Effect.gen(function* () {
17
- const candidateRepo = yield* CandidateRepository;
18
- const learningService = yield* LearningService;
19
- const edgeService = yield* EdgeService;
20
- /**
21
- * Promote a single candidate with optional reviewer identifier.
22
- * Internal helper shared by promote() and autoPromote().
23
- */
24
- const promoteCandidate = (candidate, reviewedBy) => Effect.gen(function* () {
25
- // Create learning from candidate content
26
- // Map ValidationError to DatabaseError (validation should not fail for existing candidates)
27
- const learning = yield* Effect.mapError(learningService.create({
28
- content: candidate.content,
29
- sourceType: "run",
30
- sourceRef: candidate.sourceRunId ?? candidate.sourceFile,
31
- category: candidate.category
32
- }), (error) => error._tag === "ValidationError"
33
- ? new DatabaseError({ cause: error.reason })
34
- : error);
35
- // Create DERIVED_FROM edge for provenance tracking
36
- // Link the learning back to its source (run or task)
37
- if (candidate.sourceRunId) {
38
- yield* Effect.catchAll(edgeService.createEdge({
39
- edgeType: "DERIVED_FROM",
40
- sourceType: "learning",
41
- sourceId: String(learning.id),
42
- targetType: "run",
43
- targetId: candidate.sourceRunId,
44
- weight: 1.0
45
- }), () => Effect.void // Ignore edge creation failures
46
- );
47
- }
48
- else if (candidate.sourceTaskId) {
49
- yield* Effect.catchAll(edgeService.createEdge({
50
- edgeType: "DERIVED_FROM",
51
- sourceType: "learning",
52
- sourceId: String(learning.id),
53
- targetType: "task",
54
- targetId: candidate.sourceTaskId,
55
- weight: 1.0
56
- }), () => Effect.void // Ignore edge creation failures
57
- );
58
- }
59
- // Update candidate status to promoted
60
- const now = new Date();
61
- const updatedCandidate = yield* candidateRepo.update(candidate.id, {
62
- status: "promoted",
63
- reviewedAt: now,
64
- reviewedBy,
65
- promotedLearningId: learning.id
66
- });
67
- if (!updatedCandidate) {
68
- return yield* Effect.fail(new CandidateNotFoundError({ id: candidate.id }));
69
- }
70
- return { candidate: updatedCandidate, learning };
71
- });
72
- return {
73
- list: (filter) => candidateRepo.findByFilter(filter),
74
- promote: (id) => Effect.gen(function* () {
75
- const candidate = yield* candidateRepo.findById(id);
76
- if (!candidate) {
77
- return yield* Effect.fail(new CandidateNotFoundError({ id }));
78
- }
79
- return yield* promoteCandidate(candidate, "manual");
80
- }),
81
- reject: (id, reason) => Effect.gen(function* () {
82
- // Validate reason is provided
83
- if (!reason || reason.trim().length === 0) {
84
- return yield* Effect.fail(new ValidationError({ reason: "Rejection reason is required" }));
85
- }
86
- const candidate = yield* candidateRepo.findById(id);
87
- if (!candidate) {
88
- return yield* Effect.fail(new CandidateNotFoundError({ id }));
89
- }
90
- const now = new Date();
91
- const updatedCandidate = yield* candidateRepo.update(id, {
92
- status: "rejected",
93
- reviewedAt: now,
94
- reviewedBy: "manual",
95
- rejectionReason: reason.trim()
96
- });
97
- if (!updatedCandidate) {
98
- return yield* Effect.fail(new CandidateNotFoundError({ id }));
99
- }
100
- return updatedCandidate;
101
- }),
102
- autoPromote: () => Effect.gen(function* () {
103
- // Get all pending high-confidence candidates
104
- const candidates = yield* candidateRepo.findByFilter({
105
- status: "pending",
106
- confidence: "high"
107
- });
108
- let promoted = 0;
109
- let skipped = 0;
110
- let failed = 0;
111
- const learningIds = [];
112
- for (const candidate of candidates) {
113
- // Check for duplicates using semantic search
114
- const searchResult = yield* Effect.catchAll(learningService.search({
115
- query: candidate.content,
116
- limit: 1,
117
- minScore: DUPLICATE_MIN_SCORE
118
- }), () => Effect.succeed([]));
119
- // If a highly similar learning exists, skip this candidate
120
- if (searchResult.length > 0) {
121
- skipped++;
122
- // Mark as merged with the existing learning
123
- yield* Effect.catchAll(candidateRepo.update(candidate.id, {
124
- status: "merged",
125
- reviewedAt: new Date(),
126
- reviewedBy: "auto",
127
- promotedLearningId: searchResult[0].id
128
- }), () => Effect.void);
129
- continue;
130
- }
131
- // Promote the candidate
132
- const result = yield* Effect.either(promoteCandidate(candidate, "auto"));
133
- if (result._tag === "Right") {
134
- promoted++;
135
- learningIds.push(result.right.learning.id);
136
- }
137
- else {
138
- failed++;
139
- }
140
- }
141
- return {
142
- promoted,
143
- skipped,
144
- failed,
145
- learningIds
146
- };
147
- }),
148
- getPending: () => candidateRepo.findByFilter({ status: "pending" })
149
- };
150
- }));
151
- //# sourceMappingURL=promotion-service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"promotion-service.js","sourceRoot":"","sources":["../../src/services/promotion-service.ts"],"names":[],"mappings":"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"}
@@ -1,104 +0,0 @@
1
- /**
2
- * SwarmVerificationService - Bulk invalidation with concurrent verification agents
3
- *
4
- * For large batches of anchors, spawns up to 4 concurrent verification agents.
5
- * Coordinates via job queue pattern using Effect's concurrency primitives.
6
- * Aggregates results with majority vote for edge cases.
7
- * Tracks swarm metrics for observability.
8
- *
9
- * @see docs/prd/PRD-017-invalidation-maintenance.md - IM-004: Bulk invalidation via agent swarm
10
- */
11
- import { Context, Effect, Layer } from "effect";
12
- import { AnchorVerificationService, type VerificationResult, type VerifyOptions } from "./anchor-verification.js";
13
- import { AnchorRepository } from "../repo/anchor-repo.js";
14
- import { DatabaseError } from "../errors.js";
15
- import type { AnchorStatus } from "@jamesaphoenix/tx-types";
16
- /** A batch of anchor IDs to verify */
17
- export interface VerificationBatch {
18
- readonly batchId: number;
19
- readonly anchorIds: readonly number[];
20
- }
21
- /** Result of a single agent's verification of a batch */
22
- export interface BatchResult {
23
- readonly batchId: number;
24
- readonly results: readonly VerificationResult[];
25
- readonly duration: number;
26
- readonly errors: number;
27
- }
28
- /** Swarm verification metrics */
29
- export interface SwarmMetrics {
30
- readonly totalAnchors: number;
31
- readonly totalBatches: number;
32
- readonly agentsUsed: number;
33
- readonly duration: number;
34
- /** Time spent per agent (for load balancing analysis) */
35
- readonly agentDurations: readonly number[];
36
- /** Counts by action type */
37
- readonly unchanged: number;
38
- readonly selfHealed: number;
39
- readonly drifted: number;
40
- readonly invalid: number;
41
- readonly errors: number;
42
- /** Edge cases requiring human review (tie votes) */
43
- readonly needsReview: number;
44
- }
45
- /** Complete swarm verification result */
46
- export interface SwarmVerificationResult {
47
- readonly metrics: SwarmMetrics;
48
- readonly results: readonly VerificationResult[];
49
- /** Anchor IDs that require human review due to tie votes */
50
- readonly reviewRequired: readonly number[];
51
- }
52
- /** Options for swarm verification */
53
- export interface SwarmVerifyOptions extends VerifyOptions {
54
- /** Batch size per agent (default: 10) */
55
- readonly batchSize?: number;
56
- /** Max concurrent agents (default: 4) */
57
- readonly maxConcurrent?: number;
58
- /** Force swarm even for small batches */
59
- readonly forceSwarm?: boolean;
60
- }
61
- /** Majority vote result for an anchor */
62
- export interface VoteResult {
63
- readonly anchorId: number;
64
- readonly votes: Map<AnchorStatus | "error", number>;
65
- readonly consensus: AnchorStatus | null;
66
- readonly needsReview: boolean;
67
- }
68
- declare const SwarmVerificationService_base: Context.TagClass<SwarmVerificationService, "SwarmVerificationService", {
69
- /**
70
- * Verify anchors using concurrent agents.
71
- * Automatically partitions into batches and spawns agents.
72
- */
73
- readonly verifyAnchors: (anchorIds: readonly number[], options?: SwarmVerifyOptions) => Effect.Effect<SwarmVerificationResult, DatabaseError>;
74
- /**
75
- * Verify all valid anchors using swarm.
76
- */
77
- readonly verifyAll: (options?: SwarmVerifyOptions) => Effect.Effect<SwarmVerificationResult, DatabaseError>;
78
- /**
79
- * Verify anchors for files matching glob pattern using swarm.
80
- */
81
- readonly verifyGlob: (globPattern: string, options?: SwarmVerifyOptions) => Effect.Effect<SwarmVerificationResult, DatabaseError>;
82
- /**
83
- * Verify anchors affected by a list of changed files.
84
- * Typically called from git hooks after large commits.
85
- */
86
- readonly verifyChangedFiles: (filePaths: readonly string[], options?: SwarmVerifyOptions) => Effect.Effect<SwarmVerificationResult, DatabaseError>;
87
- }>;
88
- export declare class SwarmVerificationService extends SwarmVerificationService_base {
89
- }
90
- /**
91
- * Calculate majority vote for conflicting results on the same anchor.
92
- * Used when multiple agents verify the same anchor (edge cases).
93
- *
94
- * Rules (per PRD-017):
95
- * - If 3/4 agents say valid, it's valid
96
- * - Tie = mark for human review
97
- *
98
- * Exported for use in LLM-assisted verification scenarios where multiple
99
- * agents may verify the same anchor for edge cases.
100
- */
101
- export declare const calculateMajorityVote: (results: readonly VerificationResult[]) => VoteResult;
102
- export declare const SwarmVerificationServiceLive: Layer.Layer<SwarmVerificationService, never, AnchorRepository | AnchorVerificationService>;
103
- export {};
104
- //# sourceMappingURL=swarm-verification.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"swarm-verification.d.ts","sourceRoot":"","sources":["../../src/services/swarm-verification.ts"],"names":[],"mappings":"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"}
@@ -1,400 +0,0 @@
1
- /**
2
- * SwarmVerificationService - Bulk invalidation with concurrent verification agents
3
- *
4
- * For large batches of anchors, spawns up to 4 concurrent verification agents.
5
- * Coordinates via job queue pattern using Effect's concurrency primitives.
6
- * Aggregates results with majority vote for edge cases.
7
- * Tracks swarm metrics for observability.
8
- *
9
- * @see docs/prd/PRD-017-invalidation-maintenance.md - IM-004: Bulk invalidation via agent swarm
10
- */
11
- import { Context, Effect, Layer, Queue, Fiber, Ref } from "effect";
12
- import { AnchorVerificationService } from "./anchor-verification.js";
13
- import { AnchorRepository } from "../repo/anchor-repo.js";
14
- import { matchesGlob } from "../utils/glob.js";
15
- // =============================================================================
16
- // Configuration Constants
17
- // =============================================================================
18
- /** Default batch size per agent (PRD-017: batches of 10) */
19
- const DEFAULT_BATCH_SIZE = 10;
20
- /** Maximum concurrent agents (PRD-017: up to 4) */
21
- const MAX_CONCURRENT_AGENTS = 4;
22
- /** Minimum batch size to trigger swarm (sequential is fine for small batches) */
23
- const SWARM_THRESHOLD = 20;
24
- // =============================================================================
25
- // Service Definition
26
- // =============================================================================
27
- export class SwarmVerificationService extends Context.Tag("SwarmVerificationService")() {
28
- }
29
- // =============================================================================
30
- // Utility Functions
31
- // =============================================================================
32
- /**
33
- * Partition anchor IDs into batches.
34
- */
35
- const partitionIntoBatches = (anchorIds, batchSize) => {
36
- const batches = [];
37
- for (let i = 0; i < anchorIds.length; i += batchSize) {
38
- batches.push({
39
- batchId: batches.length,
40
- anchorIds: anchorIds.slice(i, i + batchSize)
41
- });
42
- }
43
- return batches;
44
- };
45
- /**
46
- * Calculate majority vote for conflicting results on the same anchor.
47
- * Used when multiple agents verify the same anchor (edge cases).
48
- *
49
- * Rules (per PRD-017):
50
- * - If 3/4 agents say valid, it's valid
51
- * - Tie = mark for human review
52
- *
53
- * Exported for use in LLM-assisted verification scenarios where multiple
54
- * agents may verify the same anchor for edge cases.
55
- */
56
- export const calculateMajorityVote = (results) => {
57
- const anchorId = results[0].anchorId;
58
- const votes = new Map();
59
- for (const result of results) {
60
- const status = result.newStatus;
61
- votes.set(status, (votes.get(status) ?? 0) + 1);
62
- }
63
- // Find the status with most votes
64
- let maxVotes = 0;
65
- let consensus = null;
66
- let tieCount = 0;
67
- for (const [status, count] of votes) {
68
- if (status === "error")
69
- continue; // Don't count errors in consensus
70
- if (count > maxVotes) {
71
- maxVotes = count;
72
- consensus = status;
73
- tieCount = 1;
74
- }
75
- else if (count === maxVotes) {
76
- tieCount++;
77
- }
78
- }
79
- // Tie = needs human review
80
- const needsReview = tieCount > 1;
81
- return {
82
- anchorId,
83
- votes,
84
- consensus: needsReview ? null : consensus,
85
- needsReview
86
- };
87
- };
88
- /**
89
- * Aggregate batch results into final metrics.
90
- */
91
- const aggregateResults = (batchResults, startTime, agentCount) => {
92
- let unchanged = 0;
93
- let selfHealed = 0;
94
- let drifted = 0;
95
- let invalid = 0;
96
- let errors = 0;
97
- const allResults = [];
98
- const agentDurations = [];
99
- for (const batch of batchResults) {
100
- agentDurations.push(batch.duration);
101
- errors += batch.errors;
102
- for (const result of batch.results) {
103
- allResults.push(result);
104
- switch (result.action) {
105
- case "unchanged":
106
- unchanged++;
107
- break;
108
- case "self_healed":
109
- selfHealed++;
110
- break;
111
- case "drifted":
112
- drifted++;
113
- break;
114
- case "invalidated":
115
- invalid++;
116
- break;
117
- }
118
- }
119
- }
120
- return {
121
- metrics: {
122
- totalAnchors: allResults.length + errors,
123
- totalBatches: batchResults.length,
124
- agentsUsed: agentCount,
125
- duration: Date.now() - startTime,
126
- agentDurations,
127
- unchanged,
128
- selfHealed,
129
- drifted,
130
- invalid,
131
- errors
132
- },
133
- results: allResults
134
- };
135
- };
136
- // =============================================================================
137
- // Service Implementation
138
- // =============================================================================
139
- export const SwarmVerificationServiceLive = Layer.effect(SwarmVerificationService, Effect.gen(function* () {
140
- const anchorVerification = yield* AnchorVerificationService;
141
- const anchorRepo = yield* AnchorRepository;
142
- /**
143
- * Process a single batch of anchors using the verification service.
144
- */
145
- const processB = (batch, options) => Effect.gen(function* () {
146
- const startTime = Date.now();
147
- const results = [];
148
- let errors = 0;
149
- // Process each anchor in the batch
150
- for (const anchorId of batch.anchorIds) {
151
- const result = yield* anchorVerification.verify(anchorId, options).pipe(Effect.catchAll(() => {
152
- errors++;
153
- return Effect.succeed(null);
154
- }));
155
- if (result) {
156
- results.push(result);
157
- }
158
- }
159
- return {
160
- batchId: batch.batchId,
161
- results,
162
- duration: Date.now() - startTime,
163
- errors
164
- };
165
- });
166
- /**
167
- * Run swarm verification with concurrent agents.
168
- */
169
- const runSwarm = (anchorIds, options) => Effect.gen(function* () {
170
- const startTime = Date.now();
171
- const batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
172
- const maxConcurrent = options.maxConcurrent ?? MAX_CONCURRENT_AGENTS;
173
- // Partition into batches
174
- const batches = partitionIntoBatches(anchorIds, batchSize);
175
- if (batches.length === 0) {
176
- return {
177
- metrics: {
178
- totalAnchors: 0,
179
- totalBatches: 0,
180
- agentsUsed: 0,
181
- duration: 0,
182
- agentDurations: [],
183
- unchanged: 0,
184
- selfHealed: 0,
185
- drifted: 0,
186
- invalid: 0,
187
- errors: 0,
188
- needsReview: 0
189
- },
190
- results: [],
191
- reviewRequired: []
192
- };
193
- }
194
- // Determine actual concurrency (don't spawn more agents than batches)
195
- const agentCount = Math.min(batches.length, maxConcurrent);
196
- // Create a queue for job distribution
197
- const queue = yield* Queue.bounded(batches.length);
198
- // Enqueue all batches
199
- for (const batch of batches) {
200
- yield* Queue.offer(queue, batch);
201
- }
202
- // Counter to track active work
203
- const completedBatches = yield* Ref.make([]);
204
- // Worker function: continuously pull batches from queue
205
- const worker = (_workerId) => Effect.gen(function* () {
206
- while (true) {
207
- // Try to take a batch (non-blocking)
208
- const maybeBatch = yield* Queue.poll(queue);
209
- if (maybeBatch._tag === "None") {
210
- // No more batches, worker done
211
- break;
212
- }
213
- const batch = maybeBatch.value;
214
- const result = yield* processB(batch, options);
215
- // Record result
216
- yield* Ref.update(completedBatches, (results) => [...results, result]);
217
- }
218
- });
219
- // Spawn agents as fibers
220
- const fibers = [];
221
- for (let i = 0; i < agentCount; i++) {
222
- const fiber = yield* Effect.fork(worker(i));
223
- fibers.push(fiber);
224
- }
225
- // Wait for all agents to complete
226
- for (const fiber of fibers) {
227
- yield* Fiber.join(fiber);
228
- }
229
- // Shutdown queue
230
- yield* Queue.shutdown(queue);
231
- // Get all batch results
232
- const batchResults = yield* Ref.get(completedBatches);
233
- // Aggregate results
234
- const { metrics, results } = aggregateResults(batchResults, startTime, agentCount);
235
- // For now, we don't have multi-agent verification of the same anchor,
236
- // so no majority voting needed. reviewRequired is empty.
237
- // This would be used if we added LLM-assisted verification where
238
- // multiple agents verify the same anchor for edge cases.
239
- const reviewRequired = [];
240
- return {
241
- metrics: {
242
- ...metrics,
243
- needsReview: reviewRequired.length
244
- },
245
- results,
246
- reviewRequired
247
- };
248
- });
249
- /**
250
- * Simple sequential verification for small batches.
251
- */
252
- const runSequential = (anchorIds, options) => Effect.gen(function* () {
253
- // Handle empty input
254
- if (anchorIds.length === 0) {
255
- return {
256
- metrics: {
257
- totalAnchors: 0,
258
- totalBatches: 0,
259
- agentsUsed: 0,
260
- duration: 0,
261
- agentDurations: [],
262
- unchanged: 0,
263
- selfHealed: 0,
264
- drifted: 0,
265
- invalid: 0,
266
- errors: 0,
267
- needsReview: 0
268
- },
269
- results: [],
270
- reviewRequired: []
271
- };
272
- }
273
- const startTime = Date.now();
274
- const results = [];
275
- let errors = 0;
276
- let unchanged = 0;
277
- let selfHealed = 0;
278
- let drifted = 0;
279
- let invalid = 0;
280
- for (const anchorId of anchorIds) {
281
- const result = yield* anchorVerification.verify(anchorId, options).pipe(Effect.catchAll(() => {
282
- errors++;
283
- return Effect.succeed(null);
284
- }));
285
- if (result) {
286
- results.push(result);
287
- switch (result.action) {
288
- case "unchanged":
289
- unchanged++;
290
- break;
291
- case "self_healed":
292
- selfHealed++;
293
- break;
294
- case "drifted":
295
- drifted++;
296
- break;
297
- case "invalidated":
298
- invalid++;
299
- break;
300
- }
301
- }
302
- }
303
- return {
304
- metrics: {
305
- totalAnchors: results.length + errors,
306
- totalBatches: 1,
307
- agentsUsed: 1,
308
- duration: Date.now() - startTime,
309
- agentDurations: [Date.now() - startTime],
310
- unchanged,
311
- selfHealed,
312
- drifted,
313
- invalid,
314
- errors,
315
- needsReview: 0
316
- },
317
- results,
318
- reviewRequired: []
319
- };
320
- });
321
- return {
322
- verifyAnchors: (anchorIds, options = {}) => Effect.gen(function* () {
323
- // Use swarm for large batches, sequential for small ones
324
- const useSwarm = options.forceSwarm || anchorIds.length >= SWARM_THRESHOLD;
325
- if (useSwarm) {
326
- return yield* runSwarm(anchorIds, options);
327
- }
328
- else {
329
- return yield* runSequential(anchorIds, options);
330
- }
331
- }),
332
- verifyAll: (options = {}) => Effect.gen(function* () {
333
- const anchors = yield* anchorRepo.findAllValid();
334
- const anchorIds = anchors
335
- .filter((a) => !options.skipPinned || !a.pinned)
336
- .map((a) => a.id);
337
- const useSwarm = options.forceSwarm || anchorIds.length >= SWARM_THRESHOLD;
338
- if (useSwarm) {
339
- return yield* runSwarm(anchorIds, {
340
- ...options,
341
- detectedBy: options.detectedBy ?? "periodic"
342
- });
343
- }
344
- else {
345
- return yield* runSequential(anchorIds, {
346
- ...options,
347
- detectedBy: options.detectedBy ?? "periodic"
348
- });
349
- }
350
- }),
351
- verifyGlob: (globPattern, options = {}) => Effect.gen(function* () {
352
- const allAnchors = yield* anchorRepo.findAll();
353
- const matchingIds = allAnchors
354
- .filter((a) => matchesGlob(a.filePath, globPattern))
355
- .filter((a) => !options.skipPinned || !a.pinned)
356
- .map((a) => a.id);
357
- const useSwarm = options.forceSwarm || matchingIds.length >= SWARM_THRESHOLD;
358
- if (useSwarm) {
359
- return yield* runSwarm(matchingIds, {
360
- ...options,
361
- detectedBy: options.detectedBy ?? "manual"
362
- });
363
- }
364
- else {
365
- return yield* runSequential(matchingIds, {
366
- ...options,
367
- detectedBy: options.detectedBy ?? "manual"
368
- });
369
- }
370
- }),
371
- verifyChangedFiles: (filePaths, options = {}) => Effect.gen(function* () {
372
- // Find anchors for all changed files
373
- const anchorIdSet = new Set();
374
- for (const filePath of filePaths) {
375
- const anchors = yield* anchorRepo.findByFilePath(filePath);
376
- for (const anchor of anchors) {
377
- if (!options.skipPinned || !anchor.pinned) {
378
- anchorIdSet.add(anchor.id);
379
- }
380
- }
381
- }
382
- const anchorIds = Array.from(anchorIdSet);
383
- // Git hook context typically means large changes, use swarm
384
- const useSwarm = options.forceSwarm || anchorIds.length >= SWARM_THRESHOLD;
385
- if (useSwarm) {
386
- return yield* runSwarm(anchorIds, {
387
- ...options,
388
- detectedBy: options.detectedBy ?? "git_hook"
389
- });
390
- }
391
- else {
392
- return yield* runSequential(anchorIds, {
393
- ...options,
394
- detectedBy: options.detectedBy ?? "git_hook"
395
- });
396
- }
397
- })
398
- };
399
- }));
400
- //# sourceMappingURL=swarm-verification.js.map