@evomap/evolver-core 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. package/dist/algo/antiDistill.d.ts +35 -0
  2. package/dist/algo/antiDistill.js +167 -0
  3. package/dist/algo/bans.d.ts +6 -0
  4. package/dist/algo/bans.js +33 -0
  5. package/dist/algo/candidateAssembly.d.ts +65 -0
  6. package/dist/algo/candidateAssembly.js +196 -0
  7. package/dist/algo/capabilityCandidates.d.ts +38 -0
  8. package/dist/algo/capabilityCandidates.js +131 -0
  9. package/dist/algo/confidence.d.ts +106 -0
  10. package/dist/algo/confidence.js +196 -0
  11. package/dist/algo/cycleEngine.d.ts +143 -0
  12. package/dist/algo/cycleEngine.js +417 -0
  13. package/dist/algo/cycleFailureClassifier.d.ts +52 -0
  14. package/dist/algo/cycleFailureClassifier.js +104 -0
  15. package/dist/algo/epigenetics.d.ts +14 -0
  16. package/dist/algo/epigenetics.js +41 -0
  17. package/dist/algo/evolutionEvent.d.ts +23 -0
  18. package/dist/algo/evolutionEvent.js +24 -0
  19. package/dist/algo/exploration.d.ts +34 -0
  20. package/dist/algo/exploration.js +55 -0
  21. package/dist/algo/geneHealth.d.ts +24 -0
  22. package/dist/algo/geneHealth.js +16 -0
  23. package/dist/algo/geneIntake.d.ts +37 -0
  24. package/dist/algo/geneIntake.js +100 -0
  25. package/dist/algo/genePromotion.d.ts +48 -0
  26. package/dist/algo/genePromotion.js +53 -0
  27. package/dist/algo/geneSelection.d.ts +128 -0
  28. package/dist/algo/geneSelection.js +222 -0
  29. package/dist/algo/index.d.ts +18 -0
  30. package/dist/algo/index.js +18 -0
  31. package/dist/algo/mutation.d.ts +12 -0
  32. package/dist/algo/mutation.js +22 -0
  33. package/dist/algo/orchestrator.d.ts +65 -0
  34. package/dist/algo/orchestrator.js +63 -0
  35. package/dist/algo/solidify.d.ts +43 -0
  36. package/dist/algo/solidify.js +63 -0
  37. package/dist/algo/strategyPresets.d.ts +32 -0
  38. package/dist/algo/strategyPresets.js +61 -0
  39. package/dist/assetstore/index.d.ts +8 -0
  40. package/dist/assetstore/index.js +8 -0
  41. package/dist/assetstore/learningHistory.d.ts +25 -0
  42. package/dist/assetstore/learningHistory.js +38 -0
  43. package/dist/assetstore/localJsonl.d.ts +34 -0
  44. package/dist/assetstore/localJsonl.js +182 -0
  45. package/dist/assetstore/pendingSignals.d.ts +22 -0
  46. package/dist/assetstore/pendingSignals.js +171 -0
  47. package/dist/assetstore/provenance.d.ts +39 -0
  48. package/dist/assetstore/provenance.js +109 -0
  49. package/dist/assetstore/provider.d.ts +48 -0
  50. package/dist/assetstore/provider.js +36 -0
  51. package/dist/assetstore/remoteStub.d.ts +32 -0
  52. package/dist/assetstore/remoteStub.js +36 -0
  53. package/dist/assetstore/reviewFilter.d.ts +20 -0
  54. package/dist/assetstore/reviewFilter.js +44 -0
  55. package/dist/assetstore/reviewLedger.d.ts +55 -0
  56. package/dist/assetstore/reviewLedger.js +121 -0
  57. package/dist/benchmark/antiGeneBenchmark.d.ts +79 -0
  58. package/dist/benchmark/antiGeneBenchmark.js +241 -0
  59. package/dist/benchmark/antiGeneRollout.d.ts +80 -0
  60. package/dist/benchmark/antiGeneRollout.js +256 -0
  61. package/dist/benchmark/benchmark.d.ts +32 -0
  62. package/dist/benchmark/benchmark.js +26 -0
  63. package/dist/benchmark/evolutionThesisSolver.d.ts +25 -0
  64. package/dist/benchmark/evolutionThesisSolver.js +41 -0
  65. package/dist/benchmark/index.d.ts +5 -0
  66. package/dist/benchmark/index.js +5 -0
  67. package/dist/benchmark/thesis.d.ts +85 -0
  68. package/dist/benchmark/thesis.js +150 -0
  69. package/dist/bootstrap/envFingerprint.d.ts +45 -0
  70. package/dist/bootstrap/envFingerprint.js +72 -0
  71. package/dist/bootstrap/index.d.ts +2 -0
  72. package/dist/bootstrap/index.js +2 -0
  73. package/dist/bootstrap/selfEvolve.d.ts +36 -0
  74. package/dist/bootstrap/selfEvolve.js +26 -0
  75. package/dist/cycle/cycleTimeline.d.ts +35 -0
  76. package/dist/cycle/cycleTimeline.js +74 -0
  77. package/dist/cycle/index.d.ts +2 -0
  78. package/dist/cycle/index.js +2 -0
  79. package/dist/cycle/stateMachine.d.ts +6 -0
  80. package/dist/cycle/stateMachine.js +25 -0
  81. package/dist/daemon/cycleContext.d.ts +12 -0
  82. package/dist/daemon/cycleContext.js +13 -0
  83. package/dist/daemon/drain.d.ts +11 -0
  84. package/dist/daemon/drain.js +16 -0
  85. package/dist/daemon/guards.d.ts +87 -0
  86. package/dist/daemon/guards.js +142 -0
  87. package/dist/daemon/idempotency.d.ts +11 -0
  88. package/dist/daemon/idempotency.js +36 -0
  89. package/dist/daemon/idleScheduler.d.ts +55 -0
  90. package/dist/daemon/idleScheduler.js +181 -0
  91. package/dist/daemon/index.d.ts +8 -0
  92. package/dist/daemon/index.js +8 -0
  93. package/dist/daemon/stepRunner.d.ts +12 -0
  94. package/dist/daemon/stepRunner.js +31 -0
  95. package/dist/daemon/unhandledRejectionWindow.d.ts +21 -0
  96. package/dist/daemon/unhandledRejectionWindow.js +52 -0
  97. package/dist/daemon/watchdog.d.ts +11 -0
  98. package/dist/daemon/watchdog.js +14 -0
  99. package/dist/events/eventSchema.d.ts +132 -0
  100. package/dist/events/eventSchema.js +30 -0
  101. package/dist/events/eventStore.d.ts +32 -0
  102. package/dist/events/eventStore.js +137 -0
  103. package/dist/events/ingest.d.ts +34 -0
  104. package/dist/events/ingest.js +61 -0
  105. package/dist/events/paths.d.ts +22 -0
  106. package/dist/events/paths.js +44 -0
  107. package/dist/events/projectors.d.ts +9 -0
  108. package/dist/events/projectors.js +11 -0
  109. package/dist/events/public.d.ts +14 -0
  110. package/dist/events/public.js +8 -0
  111. package/dist/events/replayer.d.ts +26 -0
  112. package/dist/events/replayer.js +67 -0
  113. package/dist/events/reports.d.ts +90 -0
  114. package/dist/events/reports.js +244 -0
  115. package/dist/events/retention.d.ts +70 -0
  116. package/dist/events/retention.js +177 -0
  117. package/dist/events/sink.d.ts +5 -0
  118. package/dist/events/sink.js +1 -0
  119. package/dist/exec/autoExec.d.ts +137 -0
  120. package/dist/exec/autoExec.js +221 -0
  121. package/dist/exec/autonomousCycle.d.ts +48 -0
  122. package/dist/exec/autonomousCycle.js +78 -0
  123. package/dist/exec/claudeBridge.d.ts +112 -0
  124. package/dist/exec/claudeBridge.js +219 -0
  125. package/dist/exec/index.d.ts +9 -0
  126. package/dist/exec/index.js +11 -0
  127. package/dist/exec/openPrRegistry.d.ts +60 -0
  128. package/dist/exec/openPrRegistry.js +130 -0
  129. package/dist/exec/policy/blastRadius.d.ts +31 -0
  130. package/dist/exec/policy/blastRadius.js +67 -0
  131. package/dist/exec/policy/constraints.d.ts +26 -0
  132. package/dist/exec/policy/constraints.js +62 -0
  133. package/dist/exec/policy/destructive.d.ts +45 -0
  134. package/dist/exec/policy/destructive.js +108 -0
  135. package/dist/exec/policy/failureMode.d.ts +33 -0
  136. package/dist/exec/policy/failureMode.js +49 -0
  137. package/dist/exec/policy/index.d.ts +24 -0
  138. package/dist/exec/policy/index.js +30 -0
  139. package/dist/exec/policy/protectedPaths.d.ts +17 -0
  140. package/dist/exec/policy/protectedPaths.js +65 -0
  141. package/dist/exec/policyCheck.d.ts +2 -0
  142. package/dist/exec/policyCheck.js +7 -0
  143. package/dist/exec/prompt.d.ts +34 -0
  144. package/dist/exec/prompt.js +108 -0
  145. package/dist/exec/proofOfWork.d.ts +9 -0
  146. package/dist/exec/proofOfWork.js +11 -0
  147. package/dist/exec/runnerRegistry.d.ts +123 -0
  148. package/dist/exec/runnerRegistry.js +237 -0
  149. package/dist/exec/selfPr.d.ts +83 -0
  150. package/dist/exec/selfPr.js +104 -0
  151. package/dist/exec/selfPrObfuscation.d.ts +21 -0
  152. package/dist/exec/selfPrObfuscation.js +85 -0
  153. package/dist/hooks/hooks.d.ts +117 -0
  154. package/dist/hooks/hooks.js +89 -0
  155. package/dist/hooks/index.d.ts +1 -0
  156. package/dist/hooks/index.js +1 -0
  157. package/dist/hub/assetCallLog.d.ts +43 -0
  158. package/dist/hub/assetCallLog.js +72 -0
  159. package/dist/hub/bindings.d.ts +28 -0
  160. package/dist/hub/bindings.js +90 -0
  161. package/dist/hub/capability.d.ts +278 -0
  162. package/dist/hub/capability.js +1 -0
  163. package/dist/hub/conversationDistiller.d.ts +88 -0
  164. package/dist/hub/conversationDistiller.js +264 -0
  165. package/dist/hub/fake.d.ts +45 -0
  166. package/dist/hub/fake.js +69 -0
  167. package/dist/hub/hubReview.d.ts +91 -0
  168. package/dist/hub/hubReview.js +106 -0
  169. package/dist/hub/index.d.ts +10 -0
  170. package/dist/hub/index.js +10 -0
  171. package/dist/hub/ingest.d.ts +15 -0
  172. package/dist/hub/ingest.js +15 -0
  173. package/dist/hub/questionGenerator.d.ts +59 -0
  174. package/dist/hub/questionGenerator.js +406 -0
  175. package/dist/hub/reuseDecision.d.ts +87 -0
  176. package/dist/hub/reuseDecision.js +127 -0
  177. package/dist/hub/sanitize.d.ts +52 -0
  178. package/dist/hub/sanitize.js +321 -0
  179. package/dist/index.d.ts +27 -0
  180. package/dist/index.js +27 -0
  181. package/dist/mailbox/catalog.d.ts +17 -0
  182. package/dist/mailbox/catalog.js +53 -0
  183. package/dist/mailbox/daemon.d.ts +48 -0
  184. package/dist/mailbox/daemon.js +61 -0
  185. package/dist/mailbox/dispatch.d.ts +46 -0
  186. package/dist/mailbox/dispatch.js +62 -0
  187. package/dist/mailbox/envelope.d.ts +43 -0
  188. package/dist/mailbox/envelope.js +52 -0
  189. package/dist/mailbox/index.d.ts +8 -0
  190. package/dist/mailbox/index.js +8 -0
  191. package/dist/mailbox/ipcServer.d.ts +46 -0
  192. package/dist/mailbox/ipcServer.js +168 -0
  193. package/dist/mailbox/requestReply.d.ts +40 -0
  194. package/dist/mailbox/requestReply.js +77 -0
  195. package/dist/mailbox/store.d.ts +74 -0
  196. package/dist/mailbox/store.js +308 -0
  197. package/dist/mailbox/wake.d.ts +45 -0
  198. package/dist/mailbox/wake.js +60 -0
  199. package/dist/material/boundary.d.ts +7 -0
  200. package/dist/material/boundary.js +14 -0
  201. package/dist/material/consumer.d.ts +21 -0
  202. package/dist/material/consumer.js +52 -0
  203. package/dist/material/emit.d.ts +55 -0
  204. package/dist/material/emit.js +52 -0
  205. package/dist/material/factory.d.ts +27 -0
  206. package/dist/material/factory.js +25 -0
  207. package/dist/material/index.d.ts +8 -0
  208. package/dist/material/index.js +8 -0
  209. package/dist/material/materialStore.d.ts +24 -0
  210. package/dist/material/materialStore.js +76 -0
  211. package/dist/material/sampling.d.ts +21 -0
  212. package/dist/material/sampling.js +39 -0
  213. package/dist/material/sources.d.ts +25 -0
  214. package/dist/material/sources.js +33 -0
  215. package/dist/material/watermark.d.ts +21 -0
  216. package/dist/material/watermark.js +76 -0
  217. package/dist/observers/cursorRewriteObserver.d.ts +46 -0
  218. package/dist/observers/cursorRewriteObserver.js +103 -0
  219. package/dist/observers/distillObserver.d.ts +31 -0
  220. package/dist/observers/distillObserver.js +93 -0
  221. package/dist/observers/index.d.ts +5 -0
  222. package/dist/observers/index.js +5 -0
  223. package/dist/observers/observerBus.d.ts +44 -0
  224. package/dist/observers/observerBus.js +73 -0
  225. package/dist/observers/reflectionObserver.d.ts +31 -0
  226. package/dist/observers/reflectionObserver.js +124 -0
  227. package/dist/observers/valueDigestObserver.d.ts +50 -0
  228. package/dist/observers/valueDigestObserver.js +70 -0
  229. package/dist/ops/cleanup.d.ts +23 -0
  230. package/dist/ops/cleanup.js +68 -0
  231. package/dist/ops/health.d.ts +37 -0
  232. package/dist/ops/health.js +96 -0
  233. package/dist/ops/index.d.ts +7 -0
  234. package/dist/ops/index.js +7 -0
  235. package/dist/ops/recall.d.ts +65 -0
  236. package/dist/ops/recall.js +152 -0
  237. package/dist/ops/reuseOutcomes.d.ts +68 -0
  238. package/dist/ops/reuseOutcomes.js +126 -0
  239. package/dist/ops/savingsCore.d.ts +47 -0
  240. package/dist/ops/savingsCore.js +112 -0
  241. package/dist/ops/selfUpdate.d.ts +106 -0
  242. package/dist/ops/selfUpdate.js +294 -0
  243. package/dist/ops/valueLedger.d.ts +205 -0
  244. package/dist/ops/valueLedger.js +238 -0
  245. package/dist/ops/valueOutreach.d.ts +70 -0
  246. package/dist/ops/valueOutreach.js +244 -0
  247. package/dist/personality/drift.d.ts +45 -0
  248. package/dist/personality/drift.js +106 -0
  249. package/dist/personality/events.d.ts +25 -0
  250. package/dist/personality/events.js +37 -0
  251. package/dist/personality/evolveOps.d.ts +20 -0
  252. package/dist/personality/evolveOps.js +93 -0
  253. package/dist/personality/index.d.ts +11 -0
  254. package/dist/personality/index.js +11 -0
  255. package/dist/personality/mutate.d.ts +21 -0
  256. package/dist/personality/mutate.js +39 -0
  257. package/dist/personality/pivot.d.ts +23 -0
  258. package/dist/personality/pivot.js +22 -0
  259. package/dist/personality/prompt.d.ts +6 -0
  260. package/dist/personality/prompt.js +62 -0
  261. package/dist/personality/riskGate.d.ts +42 -0
  262. package/dist/personality/riskGate.js +80 -0
  263. package/dist/personality/schema.d.ts +255 -0
  264. package/dist/personality/schema.js +119 -0
  265. package/dist/personality/select.d.ts +46 -0
  266. package/dist/personality/select.js +71 -0
  267. package/dist/personality/stats.d.ts +46 -0
  268. package/dist/personality/stats.js +82 -0
  269. package/dist/personality/store.d.ts +35 -0
  270. package/dist/personality/store.js +92 -0
  271. package/dist/schema/common.d.ts +28 -0
  272. package/dist/schema/common.js +17 -0
  273. package/dist/schema/index.d.ts +5 -0
  274. package/dist/schema/index.js +5 -0
  275. package/dist/schema/material.d.ts +201 -0
  276. package/dist/schema/material.js +50 -0
  277. package/dist/schema/problem.d.ts +160 -0
  278. package/dist/schema/problem.js +45 -0
  279. package/dist/schema/proofOfWork.d.ts +97 -0
  280. package/dist/schema/proofOfWork.js +9 -0
  281. package/dist/schema/signal.d.ts +41 -0
  282. package/dist/schema/signal.js +19 -0
  283. package/dist/shadow/index.d.ts +6 -0
  284. package/dist/shadow/index.js +6 -0
  285. package/dist/shadow/jsonlSink.d.ts +17 -0
  286. package/dist/shadow/jsonlSink.js +27 -0
  287. package/dist/shadow/redact.d.ts +11 -0
  288. package/dist/shadow/redact.js +18 -0
  289. package/dist/shadow/shadowHub.d.ts +12 -0
  290. package/dist/shadow/shadowHub.js +42 -0
  291. package/dist/shadow/shadowMailbox.d.ts +17 -0
  292. package/dist/shadow/shadowMailbox.js +25 -0
  293. package/dist/shadow/shadowStore.d.ts +18 -0
  294. package/dist/shadow/shadowStore.js +55 -0
  295. package/dist/shadow/sink.d.ts +37 -0
  296. package/dist/shadow/sink.js +18 -0
  297. package/dist/signals/cycleHistoryFromEvents.d.ts +11 -0
  298. package/dist/signals/cycleHistoryFromEvents.js +96 -0
  299. package/dist/signals/expand.d.ts +34 -0
  300. package/dist/signals/expand.js +125 -0
  301. package/dist/signals/extractor.d.ts +25 -0
  302. package/dist/signals/extractor.js +57 -0
  303. package/dist/signals/index.d.ts +6 -0
  304. package/dist/signals/index.js +6 -0
  305. package/dist/signals/metaSignals.d.ts +57 -0
  306. package/dist/signals/metaSignals.js +158 -0
  307. package/dist/signals/signalGate.d.ts +15 -0
  308. package/dist/signals/signalGate.js +40 -0
  309. package/dist/signals/traceSignals.d.ts +44 -0
  310. package/dist/signals/traceSignals.js +123 -0
  311. package/dist/signatures/classifier.d.ts +16 -0
  312. package/dist/signatures/classifier.js +29 -0
  313. package/dist/signatures/index.d.ts +2 -0
  314. package/dist/signatures/index.js +2 -0
  315. package/dist/signatures/signatures.d.ts +22 -0
  316. package/dist/signatures/signatures.js +42 -0
  317. package/dist/strategy/experiment.d.ts +48 -0
  318. package/dist/strategy/experiment.js +63 -0
  319. package/dist/strategy/index.d.ts +2 -0
  320. package/dist/strategy/index.js +2 -0
  321. package/dist/strategy/strategyPoint.d.ts +30 -0
  322. package/dist/strategy/strategyPoint.js +23 -0
  323. package/dist/trace/index.d.ts +2 -0
  324. package/dist/trace/index.js +2 -0
  325. package/dist/trace/trajectory.d.ts +82 -0
  326. package/dist/trace/trajectory.js +117 -0
  327. package/dist/trace/trajectoryExport.d.ts +237 -0
  328. package/dist/trace/trajectoryExport.js +1818 -0
  329. package/dist/trigger/budget.d.ts +16 -0
  330. package/dist/trigger/budget.js +20 -0
  331. package/dist/trigger/engine.d.ts +12 -0
  332. package/dist/trigger/engine.js +23 -0
  333. package/dist/trigger/index.d.ts +6 -0
  334. package/dist/trigger/index.js +6 -0
  335. package/dist/trigger/problemBuilder.d.ts +24 -0
  336. package/dist/trigger/problemBuilder.js +32 -0
  337. package/dist/trigger/trigger.d.ts +22 -0
  338. package/dist/trigger/trigger.js +27 -0
  339. package/dist/trigger/valueModel.d.ts +26 -0
  340. package/dist/trigger/valueModel.js +25 -0
  341. package/dist/trigger/wfq.d.ts +13 -0
  342. package/dist/trigger/wfq.js +25 -0
  343. package/dist/util/fileLock.d.ts +24 -0
  344. package/dist/util/fileLock.js +227 -0
  345. package/dist/util/index.d.ts +2 -0
  346. package/dist/util/index.js +2 -0
  347. package/dist/util/version.d.ts +12 -0
  348. package/dist/util/version.js +51 -0
  349. package/dist/verify/index.d.ts +4 -0
  350. package/dist/verify/index.js +4 -0
  351. package/dist/verify/rollback.d.ts +22 -0
  352. package/dist/verify/rollback.js +33 -0
  353. package/dist/verify/sandboxRunner.d.ts +39 -0
  354. package/dist/verify/sandboxRunner.js +116 -0
  355. package/dist/verify/sandboxedValidation.d.ts +35 -0
  356. package/dist/verify/sandboxedValidation.js +56 -0
  357. package/dist/verify/validation.d.ts +41 -0
  358. package/dist/verify/validation.js +85 -0
  359. package/dist/wire/canonicalize.golden.d.ts +23 -0
  360. package/dist/wire/canonicalize.golden.js +46 -0
  361. package/dist/wire/geneHints.d.ts +64 -0
  362. package/dist/wire/geneHints.js +100 -0
  363. package/dist/wire/index.d.ts +91 -0
  364. package/dist/wire/index.js +3 -0
  365. package/dist/wire/schemaGate.d.ts +11 -0
  366. package/dist/wire/schemaGate.js +49 -0
  367. package/dist/workflow/dsl.d.ts +54 -0
  368. package/dist/workflow/dsl.js +15 -0
  369. package/dist/workflow/engine.d.ts +30 -0
  370. package/dist/workflow/engine.js +94 -0
  371. package/dist/workflow/index.d.ts +2 -0
  372. package/dist/workflow/index.js +2 -0
  373. package/package.json +29 -0
@@ -0,0 +1,35 @@
1
+ import type { AssetRecord } from '../assetstore/provider.js';
2
+ export declare const ANTI_DISTILL_MIN_FAILURES = 2;
3
+ export declare const ANTI_DISTILL_TRIGGER_OVERLAP_MIN = 0.6;
4
+ export interface AntiDistillOptions {
5
+ /** Minimum distinct failed capsules before a failure pattern is treated as reusable evidence. */
6
+ minFailures?: number;
7
+ /** Minimum pairwise trigger Jaccard overlap for capsules to share one cluster. */
8
+ triggerOverlapMin?: number;
9
+ /** Optional cap for callers that only want the strongest clusters. */
10
+ maxClusters?: number;
11
+ }
12
+ export interface AntiDistillFailedCapsule {
13
+ capsuleId: string;
14
+ trigger: readonly string[];
15
+ gene?: string;
16
+ summary?: string;
17
+ outcome?: unknown;
18
+ proofOfWork?: unknown;
19
+ }
20
+ export interface AntiDistillFailureCluster {
21
+ clusterId: string;
22
+ trigger: readonly string[];
23
+ sharedTrigger: readonly string[];
24
+ capsuleIds: readonly string[];
25
+ genes: readonly string[];
26
+ failureCapsules: readonly AntiDistillFailedCapsule[];
27
+ }
28
+ export interface AntiDistillInput {
29
+ dataHash: string;
30
+ failedCapsuleCount: number;
31
+ clusterableFailureCount: number;
32
+ failureClusters: readonly AntiDistillFailureCluster[];
33
+ }
34
+ export declare function triggerOverlapScore(a: readonly string[], b: readonly string[]): number;
35
+ export declare function collectAntiDistillInput(capsules: readonly AssetRecord[], opts?: AntiDistillOptions): AntiDistillInput;
@@ -0,0 +1,167 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const ANTI_DISTILL_MIN_FAILURES = 2;
3
+ export const ANTI_DISTILL_TRIGGER_OVERLAP_MIN = 0.6;
4
+ function asStrings(value) {
5
+ if (!Array.isArray(value))
6
+ return [];
7
+ return [...new Set(value.map(String).map((item) => item.trim()).filter(Boolean))];
8
+ }
9
+ function stringField(record, key) {
10
+ const value = record[key];
11
+ return typeof value === 'string' && value.trim() ? value : undefined;
12
+ }
13
+ function isFailedCapsule(record) {
14
+ if (record.type !== 'Capsule')
15
+ return false;
16
+ const outcome = record['outcome'];
17
+ return Boolean(outcome && typeof outcome === 'object' && !Array.isArray(outcome)
18
+ && outcome.status === 'failed');
19
+ }
20
+ function capsuleId(record, index) {
21
+ return stringField(record, 'asset_id') ?? stringField(record, 'id') ?? `capsule:${index}`;
22
+ }
23
+ function capsuleDigest(record, index) {
24
+ if (!isFailedCapsule(record))
25
+ return null;
26
+ const trigger = asStrings(record['trigger']);
27
+ if (trigger.length === 0)
28
+ return null;
29
+ return {
30
+ capsuleId: capsuleId(record, index),
31
+ trigger,
32
+ ...(stringField(record, 'gene') ? { gene: stringField(record, 'gene') } : {}),
33
+ ...(stringField(record, 'summary') ? { summary: stringField(record, 'summary') } : {}),
34
+ ...(record['outcome'] !== undefined ? { outcome: record['outcome'] } : {}),
35
+ ...(record['proof_of_work'] !== undefined ? { proofOfWork: record['proof_of_work'] } : {}),
36
+ };
37
+ }
38
+ function stableCapsuleView(capsule) {
39
+ return {
40
+ capsuleId: capsule.capsuleId,
41
+ trigger: [...capsule.trigger].sort(),
42
+ ...(capsule.gene ? { gene: capsule.gene } : {}),
43
+ ...(capsule.summary ? { summary: capsule.summary } : {}),
44
+ ...(capsule.outcome !== undefined ? { outcome: capsule.outcome } : {}),
45
+ ...(capsule.proofOfWork !== undefined ? { proofOfWork: capsule.proofOfWork } : {}),
46
+ };
47
+ }
48
+ function canonicalHashValue(value) {
49
+ if (value === null || typeof value !== 'object')
50
+ return value;
51
+ if (Array.isArray(value))
52
+ return value.map(canonicalHashValue);
53
+ return Object.fromEntries(Object.entries(value)
54
+ .sort(([left], [right]) => left.localeCompare(right))
55
+ .map(([key, item]) => [key, canonicalHashValue(item)]));
56
+ }
57
+ function hashStable(value) {
58
+ return createHash('sha256').update(JSON.stringify(canonicalHashValue(value))).digest('hex');
59
+ }
60
+ export function triggerOverlapScore(a, b) {
61
+ const left = new Set(a.map(String).filter(Boolean));
62
+ const right = new Set(b.map(String).filter(Boolean));
63
+ if (left.size === 0 || right.size === 0)
64
+ return 0;
65
+ let hit = 0;
66
+ for (const token of left)
67
+ if (right.has(token))
68
+ hit += 1;
69
+ return hit / new Set([...left, ...right]).size;
70
+ }
71
+ function compatibleWithCluster(capsule, cluster, overlapMin) {
72
+ let total = 0;
73
+ for (const existing of cluster.capsules) {
74
+ const overlap = triggerOverlapScore(capsule.trigger, existing.trigger);
75
+ if (overlap < overlapMin)
76
+ return { ok: false, avg: overlap };
77
+ total += overlap;
78
+ }
79
+ return { ok: true, avg: cluster.capsules.length > 0 ? total / cluster.capsules.length : 1 };
80
+ }
81
+ function recurringTrigger(capsules, minFailures) {
82
+ const counts = new Map();
83
+ for (const capsule of capsules) {
84
+ for (const token of capsule.trigger)
85
+ counts.set(token, (counts.get(token) ?? 0) + 1);
86
+ }
87
+ return [...counts.entries()]
88
+ .filter(([, count]) => count >= minFailures)
89
+ .map(([token]) => token)
90
+ .sort();
91
+ }
92
+ function sharedTrigger(capsules) {
93
+ return recurringTrigger(capsules, capsules.length);
94
+ }
95
+ function clusterId(capsules) {
96
+ return `anti_cluster_${hashStable(capsules.map(stableCapsuleView)).slice(0, 16)}`;
97
+ }
98
+ function toFailureCluster(cluster, minFailures) {
99
+ const capsules = [...cluster.capsules].sort((a, b) => a.capsuleId.localeCompare(b.capsuleId));
100
+ return {
101
+ clusterId: clusterId(capsules),
102
+ trigger: recurringTrigger(capsules, minFailures),
103
+ sharedTrigger: sharedTrigger(capsules),
104
+ capsuleIds: capsules.map((capsule) => capsule.capsuleId),
105
+ genes: [...new Set(capsules.map((capsule) => capsule.gene).filter((gene) => Boolean(gene)))].sort(),
106
+ failureCapsules: capsules,
107
+ };
108
+ }
109
+ function positiveInteger(value, fallback) {
110
+ return Number.isSafeInteger(value) && value !== undefined && value > 0 ? value : fallback;
111
+ }
112
+ function nonNegativeInteger(value, fallback) {
113
+ return Number.isSafeInteger(value) && value !== undefined && value >= 0 ? value : fallback;
114
+ }
115
+ function overlapThreshold(value) {
116
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1
117
+ ? value
118
+ : ANTI_DISTILL_TRIGGER_OVERLAP_MIN;
119
+ }
120
+ export function collectAntiDistillInput(capsules, opts = {}) {
121
+ const minFailures = positiveInteger(opts.minFailures, ANTI_DISTILL_MIN_FAILURES);
122
+ const overlapMin = overlapThreshold(opts.triggerOverlapMin);
123
+ const failedCapsuleCount = capsules.filter(isFailedCapsule).length;
124
+ const seen = new Set();
125
+ const failed = capsules
126
+ .map((record, index) => capsuleDigest(record, index))
127
+ .filter((capsule) => capsule !== null)
128
+ .filter((capsule) => {
129
+ if (seen.has(capsule.capsuleId))
130
+ return false;
131
+ seen.add(capsule.capsuleId);
132
+ return true;
133
+ })
134
+ .sort((a, b) => a.capsuleId.localeCompare(b.capsuleId));
135
+ const clusters = [];
136
+ for (const capsule of failed) {
137
+ let bestIndex = -1;
138
+ let bestScore = -1;
139
+ for (let i = 0; i < clusters.length; i += 1) {
140
+ const score = compatibleWithCluster(capsule, clusters[i], overlapMin);
141
+ if (score.ok && score.avg > bestScore) {
142
+ bestIndex = i;
143
+ bestScore = score.avg;
144
+ }
145
+ }
146
+ if (bestIndex >= 0)
147
+ clusters[bestIndex].capsules.push(capsule);
148
+ else
149
+ clusters.push({ capsules: [capsule] });
150
+ }
151
+ const failureClusters = clusters
152
+ .filter((cluster) => cluster.capsules.length >= minFailures)
153
+ .map((cluster) => toFailureCluster(cluster, minFailures))
154
+ .sort((a, b) => b.failureCapsules.length - a.failureCapsules.length
155
+ || a.trigger.join('\0').localeCompare(b.trigger.join('\0'))
156
+ || a.capsuleIds.join('\0').localeCompare(b.capsuleIds.join('\0')))
157
+ .slice(0, opts.maxClusters !== undefined ? nonNegativeInteger(opts.maxClusters, clusters.length) : clusters.length);
158
+ return {
159
+ dataHash: hashStable(failureClusters.map((cluster) => ({
160
+ trigger: cluster.trigger,
161
+ capsuleIds: cluster.capsuleIds,
162
+ }))),
163
+ failedCapsuleCount,
164
+ clusterableFailureCount: failed.length,
165
+ failureClusters,
166
+ };
167
+ }
@@ -0,0 +1,6 @@
1
+ export interface FailedCapsuleRef {
2
+ gene?: string;
3
+ trigger?: readonly string[];
4
+ }
5
+ /** Gene ids with >=2 failed capsules whose trigger covers >=60% of the current signals. */
6
+ export declare function bannedGenesFromFailures(failures: readonly FailedCapsuleRef[], signals: readonly string[]): Set<string>;
@@ -0,0 +1,33 @@
1
+ // Ban genes that have repeatedly failed on the SAME signals (ported from v1 selector.js
2
+ // banGenesFromFailedCapsules). Complements epigenetic suppression (which is per-environment): this is a
3
+ // hard, signal-overlap-based exclusion — a gene with >=2 failed capsules whose trigger covers the current
4
+ // signals is dropped from the candidate set, so a strategy that keeps failing here is not resurrected.
5
+ const BAN_THRESHOLD = 2;
6
+ const OVERLAP_MIN = 0.6;
7
+ /** Fraction of the current signals covered by a failure's trigger (how much it is "the same problem"). */
8
+ function signalCoverage(signals, trigger) {
9
+ if (signals.length === 0)
10
+ return 0;
11
+ const t = new Set(trigger.map((s) => String(s)));
12
+ let hit = 0;
13
+ for (const s of signals)
14
+ if (t.has(s))
15
+ hit += 1;
16
+ return hit / signals.length;
17
+ }
18
+ /** Gene ids with >=2 failed capsules whose trigger covers >=60% of the current signals. */
19
+ export function bannedGenesFromFailures(failures, signals) {
20
+ const counts = new Map();
21
+ for (const fc of failures) {
22
+ if (!fc.gene)
23
+ continue;
24
+ if (signalCoverage(signals, fc.trigger ?? []) < OVERLAP_MIN)
25
+ continue;
26
+ counts.set(fc.gene, (counts.get(fc.gene) ?? 0) + 1);
27
+ }
28
+ const banned = new Set();
29
+ for (const [gene, c] of counts)
30
+ if (c >= BAN_THRESHOLD)
31
+ banned.add(gene);
32
+ return banned;
33
+ }
@@ -0,0 +1,65 @@
1
+ import type { AssetStoreProvider } from '../assetstore/provider.js';
2
+ import { type ReuseCounts } from '../ops/reuseOutcomes.js';
3
+ import type { ProvenanceStore } from '../assetstore/provenance.js';
4
+ import type { ReviewLedger } from '../assetstore/reviewLedger.js';
5
+ import type { AntiWarning, GeneCandidateInput } from './geneSelection.js';
6
+ export interface AssembleOptions {
7
+ limit?: number;
8
+ provenance?: ProvenanceStore;
9
+ includeUntrusted?: boolean;
10
+ review?: ReviewLedger;
11
+ /**
12
+ * Probation (gated, #306): when true, a quarantined auto-distilled gene is allowed into the candidate pool so it
13
+ * can be TRIED and earn outcome evidence (its empty learning history keeps it ranked below proven genes; the
14
+ * always-on safety gates + the 2-strike failure ban contain a bad one). An explicitly REJECTED gene is still
15
+ * never a candidate. Absent/false (default) = today's behavior: a quarantined draft waits for approval first.
16
+ */
17
+ includeProbation?: boolean;
18
+ /**
19
+ * Reuse-before-solve (#110): hub candidates already resolved by the adapter's two-phase
20
+ * search→score→fetch flow, injected to compete in the SAME pool as local genes. The
21
+ * orchestration that triggers the free hub search + paid fetch lives in the adapter (so core's
22
+ * assembly stays pure and hub-agnostic — it only MERGES the injected candidates here). These stay
23
+ * trust-first: a geneId that collides with a local (trusted) gene keeps the local one; provenance
24
+ * for the hub asset is tracked separately at the ingest layer (#30), this only shapes selection.
25
+ */
26
+ hubCandidates?: readonly GeneCandidateInput[];
27
+ /**
28
+ * Cross-runtime reuse COUNTS per id (#268 phase 1), from reuse-outcome events (ops.reuseCountsFromSummary). Keyed
29
+ * by whatever id the events recorded (logical geneId OR content asset_id); assembly SUMS a gene's ids and derives
30
+ * one sentiment, applied as a SOFT selection re-order (see geneSelection REUSE_WEIGHT). Absent → no effect
31
+ * (default-off). Never resurrects a hard-gated gene (the trust/review/ban filters above run first).
32
+ */
33
+ reuseCounts?: ReadonlyMap<string, ReuseCounts>;
34
+ }
35
+ /** The selection pool for one cycle: the normal scored candidates + the last-resort distilled fallback (#97). */
36
+ export interface SelectionPool {
37
+ /** Genes relevant to the live signals (literal or semantic match) — the normal scored candidate set. */
38
+ candidates: GeneCandidateInput[];
39
+ /**
40
+ * Distilled genes that passed the trust/review/ban gates but do NOT match the live signals. Surfaced
41
+ * separately (NOT in `candidates`, so they never compete in normal scoring) for the v1 #97 fallback: when no
42
+ * candidate clears the floor, selection reuses one of these broadly-applicable distilled strategies instead of
43
+ * falling through to a blind innovate. Kept lightweight (no learning-history aggregation) — picked first-match.
44
+ */
45
+ distilledFallback: GeneCandidateInput[];
46
+ /**
47
+ * Matched AntiGene guardrails for the live signals. This list is advisory-only and is kept out of candidates and
48
+ * distilledFallback so negative memory cannot be selected as a strategy.
49
+ */
50
+ antiWarnings: AntiWarning[];
51
+ }
52
+ /**
53
+ * Assemble the full selection pool from the store for the given signals: the relevant scored candidates AND the
54
+ * distilled-gene fallback pool, in a single pass over the gene list (one store.list + one ban computation). A gene
55
+ * is a normal candidate if its signals_match literally intersects the signals OR semantically overlaps them (so a
56
+ * '429' signal can still reach a gene tagged for 'repair'); a trusted/approved/non-banned *distilled* gene that
57
+ * does NOT match goes to `distilledFallback` (v1 #97).
58
+ */
59
+ export declare function assembleSelectionPool(store: AssetStoreProvider, signals: readonly string[], opts?: AssembleOptions): Promise<SelectionPool>;
60
+ /**
61
+ * Assemble selection candidates from the store for the given signals (the relevant scored set only).
62
+ * Thin wrapper over {@link assembleSelectionPool} kept for back-compat with callers that don't use the
63
+ * distilled-gene fallback pool.
64
+ */
65
+ export declare function assembleCandidates(store: AssetStoreProvider, signals: readonly string[], opts?: AssembleOptions): Promise<GeneCandidateInput[]>;
@@ -0,0 +1,196 @@
1
+ import { aggregateLearningHistory } from '../assetstore/learningHistory.js';
2
+ import { reuseSentiment } from '../ops/reuseOutcomes.js';
3
+ import { tagOverlapScore } from '../signals/expand.js';
4
+ import { bannedGenesFromFailures } from './bans.js';
5
+ import { isDistilledGeneId } from './geneIntake.js';
6
+ function asStrings(v) {
7
+ return Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
8
+ }
9
+ function stringField(v) {
10
+ return typeof v === 'string' && v.trim().length > 0 ? v.trim() : undefined;
11
+ }
12
+ function severityOf(v) {
13
+ return v === 'low' || v === 'medium' || v === 'high' ? v : undefined;
14
+ }
15
+ function candidateIds(geneId, assetId) {
16
+ return [...new Set([geneId, assetId].filter((id) => typeof id === 'string' && id.length > 0))];
17
+ }
18
+ function isBannedCandidate(banned, geneId, assetId) {
19
+ return candidateIds(geneId, assetId).some((id) => banned.has(id));
20
+ }
21
+ function passesInjectedCandidateGates(candidate, opts) {
22
+ const assetId = candidate.assetId;
23
+ if (opts.provenance && !opts.includeUntrusted) {
24
+ if (!assetId || opts.provenance.get(assetId)?.trusted !== true)
25
+ return false;
26
+ }
27
+ if (opts.review) {
28
+ if (!assetId || !opts.review.isApproved(assetId))
29
+ return false;
30
+ }
31
+ return true;
32
+ }
33
+ /** A zero learning view for a gene with no capsules yet (used for lightweight distilled-fallback candidates). */
34
+ function emptyLearningView(geneId) {
35
+ return { geneId, total: 0, success: 0, failed: 0, successRate: 0, avgScore: 0, recentCapsuleIds: [] };
36
+ }
37
+ /** Combined reuse sentiment across ALL of a candidate's ids (#268 Bugbot). Reuse events key by assetId — which
38
+ * may be the content asset_id OR the logical id — while candidates key by geneId, AND one gene's events can SPLIT
39
+ * across both forms. So we SUM the counts of every distinct id the candidate has, then compute sentiment once:
40
+ * averaging two per-id sentiments (or taking the first) would let negatives stored under one id be ignored. */
41
+ function combinedReuseSentiment(map, ...ids) {
42
+ if (!map)
43
+ return undefined;
44
+ let success = 0, negative = 0, found = false;
45
+ const seen = new Set();
46
+ for (const id of ids) {
47
+ if (id === undefined || seen.has(id))
48
+ continue;
49
+ seen.add(id);
50
+ const c = map.get(id);
51
+ if (c) {
52
+ success += c.success;
53
+ negative += c.negative;
54
+ found = true;
55
+ }
56
+ }
57
+ return found ? reuseSentiment({ success, negative }) : undefined;
58
+ }
59
+ /** Genes banned by repeated signal-matched failures (>=2 failed capsules covering the signals). */
60
+ async function computeBans(store, signals, limit) {
61
+ const caps = await store.search({ kind: 'Capsule', signalsAny: [...signals], limit });
62
+ const failures = caps
63
+ .filter((c) => c['outcome']?.status === 'failed')
64
+ .map((c) => ({
65
+ gene: typeof c['gene'] === 'string' ? String(c['gene']) : undefined,
66
+ trigger: asStrings(c['trigger']),
67
+ }));
68
+ return bannedGenesFromFailures(failures, signals);
69
+ }
70
+ /**
71
+ * Assemble the full selection pool from the store for the given signals: the relevant scored candidates AND the
72
+ * distilled-gene fallback pool, in a single pass over the gene list (one store.list + one ban computation). A gene
73
+ * is a normal candidate if its signals_match literally intersects the signals OR semantically overlaps them (so a
74
+ * '429' signal can still reach a gene tagged for 'repair'); a trusted/approved/non-banned *distilled* gene that
75
+ * does NOT match goes to `distilledFallback` (v1 #97).
76
+ */
77
+ export async function assembleSelectionPool(store, signals, opts = {}) {
78
+ const limit = opts.limit ?? 500;
79
+ const genes = await store.list('Gene', limit);
80
+ const banned = await computeBans(store, signals, limit);
81
+ const sigSet = new Set(signals);
82
+ const out = [];
83
+ const distilledFallback = [];
84
+ const antiWarnings = [];
85
+ for (const g of genes) {
86
+ // Trust-first (#30): untrusted (e.g. hub-ingested) genes are excluded from the candidate pool by default;
87
+ // they enter only with includeUntrusted or after an explicit promotion. Provenance is keyed by asset_id.
88
+ if (opts.provenance && !opts.includeUntrusted && !opts.provenance.isTrusted(String(g.asset_id)))
89
+ continue;
90
+ // Review-first (#89/#91): auto-distilled drafts land quarantined until a human approves; rejected drafts stay
91
+ // out too. No record → eligible (cycle/migrate genes). Symmetric to the provenance trust-first filter above.
92
+ // Probation (#306): includeProbation lets a quarantined draft be TRIED so it can earn evidence; a rejected
93
+ // draft is never tried. Off (default) keeps quarantined drafts out until approval.
94
+ if (opts.review && !opts.review.isApproved(String(g.asset_id))
95
+ && (!opts.includeProbation || opts.review.get(String(g.asset_id))?.state === 'rejected'))
96
+ continue;
97
+ const geneId = typeof g['id'] === 'string' ? String(g['id']) : String(g.asset_id);
98
+ const assetId = String(g.asset_id);
99
+ if (isBannedCandidate(banned, geneId, assetId))
100
+ continue; // repeated signal-matched failures → not a candidate (nor a fallback)
101
+ const signalsMatch = asStrings(g['signals_match']);
102
+ const category = typeof g['category'] === 'string' ? String(g['category']) : undefined;
103
+ const summary = typeof g['summary'] === 'string' ? String(g['summary']) : undefined;
104
+ const literal = signalsMatch.some((m) => sigSet.has(m));
105
+ const relevant = literal || tagOverlapScore(signals, { signalsMatch, geneId, category, summary }) > 0;
106
+ if (!relevant) {
107
+ // #97: a trusted, approved, non-banned distilled gene that doesn't match the live signals is not a normal
108
+ // candidate, but it IS eligible as a last-resort fallback (selection uses it only when nothing clears the
109
+ // floor). NB in v2 "distilled" = any intaken gene (intakeGene tags them all gene_distilled_), not just skill-
110
+ // derived as in v1 — eligibility here is gated by trust/review/ban, not by skill provenance.
111
+ // Lightweight: no learning-history aggregation — it is picked first-match, not ranked by health.
112
+ if (isDistilledGeneId(geneId)) {
113
+ distilledFallback.push({
114
+ geneId,
115
+ assetId,
116
+ signalsMatch,
117
+ view: emptyLearningView(geneId),
118
+ reuseCount: 0,
119
+ ...(category ? { category } : {}),
120
+ ...(summary ? { summary } : {}),
121
+ });
122
+ }
123
+ continue;
124
+ }
125
+ const view = await aggregateLearningHistory(store, geneId);
126
+ // #268 Bugbot: reuse events key by assetId, which may be the content asset_id (sha256:…) OR the logical id —
127
+ // candidates key by the logical geneId. Look the sentiment up by BOTH so the soft re-order actually matches
128
+ // regardless of which form the reuse-result carried (recall's resolveGene accepts both for the same reason).
129
+ const reuseAdjustVal = combinedReuseSentiment(opts.reuseCounts, geneId, String(g.asset_id));
130
+ out.push({
131
+ geneId,
132
+ assetId: String(g.asset_id),
133
+ signalsMatch,
134
+ view,
135
+ // #195: inert (zero-work) cycles are not productive reuse — exclude them so a do-nothing gene can't earn
136
+ // the reuse bonus. success + failed === total when there are no inert cycles (back-compat).
137
+ reuseCount: view.success + view.failed,
138
+ ...(category ? { category } : {}),
139
+ ...(summary ? { summary } : {}),
140
+ ...(reuseAdjustVal !== undefined ? { reuseAdjust: reuseAdjustVal } : {}),
141
+ });
142
+ }
143
+ // #110: merge hub reuse candidates into the same pool, trust-first — local (trusted) genes win on a
144
+ // geneId collision, and a hub candidate banned by repeated signal-matched failures stays out too.
145
+ if (opts.hubCandidates && opts.hubCandidates.length > 0) {
146
+ const localIds = new Set(out.map((c) => c.geneId));
147
+ for (const h of opts.hubCandidates) {
148
+ if (!passesInjectedCandidateGates(h, opts))
149
+ continue;
150
+ if (localIds.has(h.geneId))
151
+ continue; // a trusted local gene already covers this id
152
+ if (isBannedCandidate(banned, h.geneId, h.assetId))
153
+ continue;
154
+ // Stamp the reuse sentiment onto a hub candidate too (only when it didn't carry one), matched by its geneId
155
+ // OR its asset_id — symmetric with local genes, so a map keyed like reuse events (often sha256:…) still hits
156
+ // (#268 Bugbot). A hub candidate that exposes neither matching id is simply left unstamped.
157
+ const hubAdj = h.reuseAdjust === undefined ? combinedReuseSentiment(opts.reuseCounts, h.geneId, h.assetId) : undefined;
158
+ out.push(hubAdj !== undefined ? { ...h, reuseAdjust: hubAdj } : h);
159
+ localIds.add(h.geneId);
160
+ }
161
+ }
162
+ for (const a of await store.list('AntiGene', limit)) {
163
+ if (opts.review && !opts.review.isApproved(String(a.asset_id)))
164
+ continue;
165
+ const trigger = asStrings(a['trigger']);
166
+ const avoid = asStrings(a['avoid']);
167
+ if (trigger.length === 0 || avoid.length === 0)
168
+ continue;
169
+ const antiGeneId = stringField(a['id']) ?? String(a.asset_id);
170
+ const summary = stringField(a['summary']);
171
+ const relevant = trigger.some((m) => sigSet.has(m))
172
+ || tagOverlapScore(signals, { signalsMatch: trigger, geneId: antiGeneId, summary }) > 0;
173
+ if (!relevant)
174
+ continue;
175
+ const severity = severityOf(a['severity']);
176
+ const rationale = stringField(a['rationale']);
177
+ antiWarnings.push({
178
+ antiGeneId,
179
+ assetId: String(a.asset_id),
180
+ trigger,
181
+ avoid,
182
+ ...(summary ? { summary } : {}),
183
+ ...(severity ? { severity } : {}),
184
+ ...(rationale ? { rationale } : {}),
185
+ });
186
+ }
187
+ return { candidates: out, distilledFallback, antiWarnings };
188
+ }
189
+ /**
190
+ * Assemble selection candidates from the store for the given signals (the relevant scored set only).
191
+ * Thin wrapper over {@link assembleSelectionPool} kept for back-compat with callers that don't use the
192
+ * distilled-gene fallback pool.
193
+ */
194
+ export async function assembleCandidates(store, signals, opts = {}) {
195
+ return (await assembleSelectionPool(store, signals, opts)).candidates;
196
+ }
@@ -0,0 +1,38 @@
1
+ /** The "five-question shape" of a capability proposal (ported verbatim from v1). */
2
+ export interface FiveQuestionShape {
3
+ title: string;
4
+ input: string;
5
+ output: string;
6
+ invariants: string;
7
+ params: string;
8
+ failure_points: string;
9
+ evidence: string;
10
+ }
11
+ export interface CapabilityCandidate {
12
+ type: 'CapabilityCandidate';
13
+ id: string;
14
+ title: string;
15
+ source: 'transcript' | 'signals' | 'failed_capsules';
16
+ signals: string[];
17
+ tags: string[];
18
+ shape: FiveQuestionShape;
19
+ }
20
+ export interface FailedCapsuleLike {
21
+ trigger?: readonly string[];
22
+ failure_reason?: string;
23
+ gene?: string;
24
+ outcome?: {
25
+ status?: string;
26
+ };
27
+ }
28
+ export interface ExtractCandidatesInput {
29
+ /** Tool-call names observed (e.g. extracted from the runtime transcript). A name repeated >=3 times becomes a candidate. */
30
+ toolCalls?: readonly string[];
31
+ signals?: readonly string[];
32
+ failedCapsules?: readonly FailedCapsuleLike[];
33
+ }
34
+ /**
35
+ * Mine capability candidates from three sources (ported v1): repeated tool calls (>=3), active opportunity
36
+ * signals, and clusters of failed capsules (>=2 in the same dominant-problem group). Deduped by stable id.
37
+ */
38
+ export declare function extractCapabilityCandidates(inp: ExtractCandidatesInput): CapabilityCandidate[];