@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,131 @@
1
+ // Capability candidate extraction (ported from v1 src/gep/candidates.js). Mines NEW capability proposals
2
+ // from agent behavior — repeated tool calls, active opportunity signals, and clusters of failed evolutions —
3
+ // to feed the innovation step. Candidates are ADVISORY (the agent runtime decides whether to act, exactly
4
+ // as in v1); this is the self-growth path v2 otherwise lacks (v2 only scores EXISTING genes). Pure +
5
+ // deterministic: callers pass already-extracted tool-call names / signals / failed capsules; no time/io here.
6
+ import { expandSignals } from '../signals/expand.js';
7
+ const TOOL_CALL_MIN = 3;
8
+ const FAILURE_CLUSTER_MIN = 2;
9
+ const TITLE_MAX = 120;
10
+ const EVIDENCE_MAX = 240;
11
+ /** Predefined signal → candidate-title map (ported v1): defensive + opportunity signals. */
12
+ const SIGNAL_CANDIDATES = [
13
+ { signal: 'log_error', title: 'Repair recurring runtime errors' },
14
+ { signal: 'protocol_drift', title: 'Prevent protocol drift and enforce auditable outputs' },
15
+ { signal: 'windows_shell_incompatible', title: 'Avoid platform-specific shell assumptions (Windows compatibility)' },
16
+ { signal: 'session_logs_missing', title: 'Harden session log detection and fallback behavior' },
17
+ { signal: 'user_feature_request', title: 'Implement user-requested feature' },
18
+ { signal: 'user_improvement_suggestion', title: 'Apply user improvement suggestion' },
19
+ { signal: 'perf_bottleneck', title: 'Resolve performance bottleneck' },
20
+ { signal: 'capability_gap', title: 'Fill capability gap' },
21
+ { signal: 'stable_success_plateau', title: 'Explore new strategies during stability plateau' },
22
+ { signal: 'external_opportunity', title: 'Evaluate external A2A asset for local adoption' },
23
+ ];
24
+ /** Highest → lowest priority problem class used to pick a failure cluster's grouping key (ported v1). */
25
+ const PROBLEM_PRIORITY = ['problem:performance', 'problem:protocol', 'problem:reliability', 'problem:stagnation', 'problem:capability'];
26
+ /** FNV-1a 32-bit stable hash (ported v1 hash.js) — deterministic candidate ids. */
27
+ function stableHash(input) {
28
+ let h = 2166136261;
29
+ for (let i = 0; i < input.length; i++) {
30
+ h ^= input.charCodeAt(i);
31
+ h = Math.imul(h, 16777619);
32
+ }
33
+ return (h >>> 0).toString(16).padStart(8, '0');
34
+ }
35
+ const clip = (s, n) => (s.length > n ? s.slice(0, n) : s);
36
+ /** Build the fixed five-question shape (ported v1): only title/params/evidence vary per candidate. */
37
+ function buildShape(title, signals, evidence) {
38
+ const params = `Signals: ${signals.join(', ')}`.trim();
39
+ return {
40
+ title: clip(title, TITLE_MAX),
41
+ input: 'Recent session transcript + memory snippets + user instructions',
42
+ output: 'A safe, auditable evolution patch guided by GEP assets',
43
+ invariants: 'Protocol order, small reversible patches, validation, append-only events',
44
+ params: params || 'Signals: (none)',
45
+ failure_points: 'Missing signals, over-broad changes, skipped validation, missing knowledge solidification',
46
+ evidence: clip(evidence, EVIDENCE_MAX),
47
+ };
48
+ }
49
+ function candidate(source, id, title, signals, evidence, tags) {
50
+ return { type: 'CapabilityCandidate', id: `cand_${id}`, title, source, signals, tags, shape: buildShape(title, signals, evidence) };
51
+ }
52
+ function failureTitle(tags) {
53
+ if (tags.includes('problem:performance'))
54
+ return 'Resolve recurring performance regressions';
55
+ if (tags.includes('problem:protocol'))
56
+ return 'Prevent recurring protocol and validation regressions';
57
+ if (tags.includes('problem:reliability'))
58
+ return 'Repair recurring reliability failures';
59
+ if (tags.includes('problem:stagnation'))
60
+ return 'Break repeated stagnation loops with a new strategy';
61
+ if (tags.includes('area:orchestration'))
62
+ return 'Stabilize task and orchestration behavior';
63
+ return 'Learn from recurring failed evolution paths';
64
+ }
65
+ /**
66
+ * Mine capability candidates from three sources (ported v1): repeated tool calls (>=3), active opportunity
67
+ * signals, and clusters of failed capsules (>=2 in the same dominant-problem group). Deduped by stable id.
68
+ */
69
+ export function extractCapabilityCandidates(inp) {
70
+ const signals = (inp.signals ?? []).map((s) => String(s));
71
+ const signalTags = expandSignals(signals);
72
+ const out = [];
73
+ // A. Tool-call mining: a tool used >= TOOL_CALL_MIN times suggests a reusable capability.
74
+ const freq = new Map();
75
+ for (const t of inp.toolCalls ?? [])
76
+ freq.set(t, (freq.get(t) ?? 0) + 1);
77
+ for (const [tool, count] of freq) {
78
+ if (count < TOOL_CALL_MIN)
79
+ continue;
80
+ const title = `Repeated tool usage: ${tool}`;
81
+ out.push(candidate('transcript', stableHash(title), title, signals, `Observed ${count} occurrences of tool call ${tool}.`, signalTags));
82
+ }
83
+ // B. Signal-mapped candidates: predefined defensive/opportunity signals.
84
+ for (const sc of SIGNAL_CANDIDATES) {
85
+ if (!signals.some((s) => s === sc.signal || s.startsWith(sc.signal + ':')))
86
+ continue;
87
+ out.push(candidate('signals', stableHash(sc.signal), sc.title, signals, `Signal ${sc.signal} active.`, signalTags));
88
+ }
89
+ // C. Failure clustering: group failed capsules by dominant problem class.
90
+ const groups = new Map();
91
+ for (const fc of inp.failedCapsules ?? []) {
92
+ if (fc.outcome?.status === 'success')
93
+ continue;
94
+ const reason = String(fc.failure_reason ?? '').trim();
95
+ const failureTags = expandSignals([...(fc.trigger ?? []), ...signals], reason).filter((t) => /^(problem|risk|area|action):/.test(t));
96
+ if (failureTags.length === 0)
97
+ continue;
98
+ let dominant = null;
99
+ for (const p of PROBLEM_PRIORITY)
100
+ if (failureTags.includes(p)) {
101
+ dominant = p;
102
+ break;
103
+ }
104
+ const grouping = dominant ? [dominant] : failureTags.filter((t) => t.startsWith('area:') || t.startsWith('risk:')).slice(0, 1);
105
+ const key = grouping.join('|');
106
+ if (!key)
107
+ continue;
108
+ const g = groups.get(key) ?? { count: 0, tags: failureTags, reasons: [] };
109
+ g.count += 1;
110
+ if (reason)
111
+ g.reasons.push(reason);
112
+ groups.set(key, g);
113
+ }
114
+ for (const [key, g] of groups) {
115
+ if (g.count < FAILURE_CLUSTER_MIN)
116
+ continue;
117
+ const title = failureTitle(g.tags);
118
+ const evidence = `${g.count} recurring failures${g.reasons.length ? ` (${g.reasons.slice(0, 2).join('; ')})` : ''}`;
119
+ out.push(candidate('failed_capsules', stableHash('failed:' + key), title, signals, evidence, g.tags));
120
+ }
121
+ // Dedup by stable id (first occurrence wins).
122
+ const seen = new Set();
123
+ const deduped = [];
124
+ for (const c of out) {
125
+ if (seen.has(c.id))
126
+ continue;
127
+ seen.add(c.id);
128
+ deduped.push(c);
129
+ }
130
+ return deduped;
131
+ }
@@ -0,0 +1,106 @@
1
+ /** A single per-(fingerprint, gene) outcome observation derived from the event log. */
2
+ export interface ConfidenceObservation {
3
+ signalFingerprint: string;
4
+ geneId: string;
5
+ /**
6
+ * `inert` (port of v1 #195 `stable_no_error`): the cycle hit no error AND produced no measurable value
7
+ * (no ProofOfWork output) — i.e. nothing happened. Counting that as a `success` lets a gene that only ever
8
+ * does nothing climb confidence → ~1.0 and dominate `--loop` selection forever (diversity collapse). An
9
+ * inert observation therefore builds NO positive evidence: it does not touch success/fail counts and so does
10
+ * not raise baseConfidence; it is tallied apart (inertCount) and is what `inertBannedGeneIds` uses to ban a
11
+ * gene stuck doing nothing on a signal.
12
+ */
13
+ status: 'success' | 'failed' | 'inert';
14
+ /** Epoch millis of the outcome (from the event ts). Used for half-life decay. */
15
+ at: number;
16
+ }
17
+ /** A derived confidence edge: how reliably `geneId` resolved problems under `signalFingerprint`. */
18
+ export interface ConfidenceEdge {
19
+ signalFingerprint: string;
20
+ geneId: string;
21
+ successCount: number;
22
+ failCount: number;
23
+ /**
24
+ * Inert (zero-work) observations on this edge (#195). Tallied apart from success/fail so they neither raise
25
+ * baseConfidence nor count toward attempts — an all-inert edge stays at the neutral 0.5 prior, never ~1.0.
26
+ */
27
+ inertCount: number;
28
+ /** Epoch millis of the most recent observation on this edge (newest wins). */
29
+ lastAt: number;
30
+ /** Laplace-smoothed, undecayed expected success rate in [0,1]. Decay is applied at query time against `now`. */
31
+ baseConfidence: number;
32
+ }
33
+ /** All derived edges, keyed by `confidenceEdgeKey(signalFingerprint, geneId)`. */
34
+ export type ConfidenceEdges = ReadonlyMap<string, ConfidenceEdge>;
35
+ /** Default half-life for confidence decay (days). Aligned with v1 edgeExpectedSuccess half_life_days=30. */
36
+ export declare const CONFIDENCE_HALF_LIFE_DAYS = 30;
37
+ /**
38
+ * Composite map key for an edge: `<fingerprint>::<geneId>`. The fingerprint is fixed-length hex (no `:`), so
39
+ * `::` is an unambiguous separator. Exported so callers/tests look edges up the same way they are stored,
40
+ * instead of hand-building the key string.
41
+ */
42
+ export declare function confidenceEdgeKey(signalFingerprint: string, geneId: string): string;
43
+ /**
44
+ * Stable signal fingerprint (port of v1 computeSignalKey): normalize → de-duplicate → sort → digest.
45
+ * Deterministic and order-independent, so the same signal SET always yields the same fingerprint.
46
+ * An empty set maps to a fixed sentinel digest so "no signals" is still a well-defined edge key.
47
+ */
48
+ export declare function signalFingerprint(signals: readonly string[]): string;
49
+ /**
50
+ * Half-life decay weight in (0,1] (port of v1 decayWeight): 0.5^(ageDays / halfLife).
51
+ * Age is measured from the edge's lastAt to `now`. Future/zero/negative age → no decay (weight 1).
52
+ */
53
+ export declare function decayWeight(lastAt: number, now: number, halfLifeDays?: number): number;
54
+ /**
55
+ * Derive confidence edges from a flat list of per-(fingerprint, gene) outcome observations.
56
+ * Pure and deterministic: the same observations (in any order — we track the max `at` for lastAt) always
57
+ * produce the same edges. This is the replay primitive — feed it the observations re-extracted from
58
+ * root_events and you get byte-identical edges back.
59
+ */
60
+ export declare function deriveConfidenceEdges(observations: readonly ConfidenceObservation[]): ConfidenceEdges;
61
+ /**
62
+ * Query the confidence of `geneId` under `signalFingerprint` at time `now`, in [0,1].
63
+ * = baseConfidence (Laplace-smoothed success rate) × half-life decay weight.
64
+ * Returns 0 when there is no edge (no history) so a never-tried gene gets no positive nudge —
65
+ * absence of evidence is not evidence of success — and 0 for a purely-inert edge (only zero-work cycles),
66
+ * so a do-nothing gene gets the same zero nudge as a never-tried one (#195).
67
+ */
68
+ export declare function confidenceFor(edges: ConfidenceEdges, signalFingerprint: string, geneId: string, now: number, halfLifeDays?: number): number;
69
+ /**
70
+ * Consecutive inert (zero-work) outcomes on a (fingerprint, gene) edge after which a gene with NO real success
71
+ * on that signal is banned, so `--loop` selection explores instead of re-running a do-nothing gene (#195).
72
+ * Port of v1 `GENE_INERT_BAN_STREAK` (env `EVOLVER_GENE_INERT_BAN_STREAK`, default 8); kept an inline const to
73
+ * match v2's algo-tunable convention (BAN_THRESHOLD / MIN_ENV_ATTEMPTS), not env-driven.
74
+ */
75
+ export declare const GENE_INERT_BAN_STREAK = 8;
76
+ /**
77
+ * Observation window (in raw events) over which the inert ban is derived — deliberately MUCH wider than the
78
+ * small recency window used for confidence SCORING. A banned gene runs as `ad-hoc` and accrues no new
79
+ * observation for itself, so its trailing inert run must be recomputed from a history wide enough that
80
+ * intervening innovate/ad-hoc cycles cannot evict it — and cannot evict an earlier real success that exempts
81
+ * the gene (`successCount > 0`). With a small window the run/exemption age out purely from unrelated cycles, so
82
+ * the ban flaps: the do-nothing gene resurfaces and the productive gene gets falsely banned (#195 regression).
83
+ * ~14000 events ≈ 2000 cycles, mirroring v1's multi-hundred-cycle memory-graph read horizon: far past any
84
+ * realistic flap window, yet still bounded (a long-idle gene's stale success eventually ages out, matching v1).
85
+ * `EventStore.tail()` reads the entire log regardless of window size, so a larger window costs no extra I/O.
86
+ */
87
+ export declare const INERT_BAN_OBSERVATION_WINDOW = 14000;
88
+ /**
89
+ * Trailing consecutive-inert run per (fingerprint, gene), keyed by `confidenceEdgeKey`. Unlike
90
+ * `deriveConfidenceEdges` (a pure function of the observation SET), this is deliberately order-DEPENDENT: it
91
+ * counts inert outcomes from the most recent backward and ANY real success/failure resets the run to 0 — so a
92
+ * gene that ever does real work is never punished for older idle cycles. Input MUST be chronological
93
+ * (oldest→newest, i.e. the order `ingestor.tail` yields); the trailing run is the value left after the final
94
+ * observation per edge.
95
+ */
96
+ export declare function trailingInertByEdge(observations: readonly ConfidenceObservation[]): Map<string, number>;
97
+ /**
98
+ * Gene ids to ban for the CURRENT signal fingerprint because they are stuck producing inert (zero-work)
99
+ * cycles (#195). A gene is banned iff, on this fingerprint's edge, its trailing inert run ≥ `streak` AND it has
100
+ * ZERO real success on this signal (double guard: the consecutive run is reset by any real outcome, and a gene
101
+ * that ever truly succeeded here keeps successCount > 0). Banning a sole-matching inert gene lets selection
102
+ * fall through to mutation (selected:null → fresh gene), restoring diversity — the failure-streak ban never
103
+ * fires on these because nothing "fails". Per-signal, mirroring v1's per-signal-key ban: a gene idle on THIS
104
+ * signal can still be tried on others.
105
+ */
106
+ export declare function inertBannedGeneIds(edges: ConfidenceEdges, observations: readonly ConfidenceObservation[], fingerprint: string, streak?: number): Set<string>;
@@ -0,0 +1,196 @@
1
+ // Preferred-gene confidence edges (positive cross-cycle learning, ported from v1 src/gep/memoryGraph.js,
2
+ // adapted to v2's derive-from-events model). The negative side (ban / epigenetic penalty) is already ported;
3
+ // this is the missing POSITIVE half: a gene that keeps succeeding under a given signal fingerprint should be
4
+ // nudged UP in ranking for that fingerprint — without ever resurrecting a gene that a hard gate excluded.
5
+ //
6
+ // Sidecar principle (same as epigenetics.ts): edges are DERIVED from the append-only root_events log at
7
+ // selection time. We never mutate an asset, never add an asset field, never persist a separate store — so
8
+ // asset_id stays stable and the edges can be replayed byte-for-byte from the events alone.
9
+ //
10
+ // Edge key: (signalFingerprint, geneId). Edge value: { successCount, failCount, inertCount, lastAt, confidence },
11
+ // where confidence is a Laplace-smoothed, half-life-decayed expected success rate in [0, 1] (port of v1
12
+ // edgeExpectedSuccess). The fingerprint is a stable, deterministic digest of the signal set (port of v1
13
+ // computeSignalKey): sorted, de-duplicated, normalized — so the same signals always map to the same edge.
14
+ //
15
+ // This file also carries the negative #195 half of the same scoring data: an `inert` (zero-work) outcome
16
+ // builds no confidence (tallied apart as inertCount), and `inertBannedGeneIds` bans a gene stuck producing only
17
+ // inert cycles on a signal — so a sole-matching do-nothing gene can no longer dominate `--loop` selection.
18
+ //
19
+ // Purity: no Date.now(), no Math.random(). Time enters only through event timestamps and an injected `now`.
20
+ import { createHash } from 'node:crypto';
21
+ /** Default half-life for confidence decay (days). Aligned with v1 edgeExpectedSuccess half_life_days=30. */
22
+ export const CONFIDENCE_HALF_LIFE_DAYS = 30;
23
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
24
+ /**
25
+ * Composite map key for an edge: `<fingerprint>::<geneId>`. The fingerprint is fixed-length hex (no `:`), so
26
+ * `::` is an unambiguous separator. Exported so callers/tests look edges up the same way they are stored,
27
+ * instead of hand-building the key string.
28
+ */
29
+ export function confidenceEdgeKey(signalFingerprint, geneId) {
30
+ return `${signalFingerprint}::${geneId}`;
31
+ }
32
+ /**
33
+ * Stable signal fingerprint (port of v1 computeSignalKey): normalize → de-duplicate → sort → digest.
34
+ * Deterministic and order-independent, so the same signal SET always yields the same fingerprint.
35
+ * An empty set maps to a fixed sentinel digest so "no signals" is still a well-defined edge key.
36
+ */
37
+ export function signalFingerprint(signals) {
38
+ const norm = (Array.isArray(signals) ? signals : [])
39
+ .map((s) => String(s ?? '').trim())
40
+ .filter((s) => s.length > 0);
41
+ const uniqSorted = Array.from(new Set(norm)).sort();
42
+ const canonical = uniqSorted.length > 0 ? uniqSorted.join('|') : '(none)';
43
+ // Short, collision-resistant, deterministic. 16 hex chars (64 bits) is ample for an edge key.
44
+ return createHash('sha256').update(canonical, 'utf8').digest('hex').slice(0, 16);
45
+ }
46
+ /**
47
+ * Laplace-smoothed expected success rate (port of v1 edgeExpectedSuccess, smoothing only — decay is separate).
48
+ * p = (success + 1) / (success + fail + 2). With zero evidence this is 0.5 (a neutral prior), not 0 or 1.
49
+ */
50
+ function laplaceSuccessRate(success, fail) {
51
+ const total = success + fail;
52
+ return (success + 1) / (total + 2);
53
+ }
54
+ /**
55
+ * Half-life decay weight in (0,1] (port of v1 decayWeight): 0.5^(ageDays / halfLife).
56
+ * Age is measured from the edge's lastAt to `now`. Future/zero/negative age → no decay (weight 1).
57
+ */
58
+ export function decayWeight(lastAt, now, halfLifeDays = CONFIDENCE_HALF_LIFE_DAYS) {
59
+ if (!Number.isFinite(halfLifeDays) || halfLifeDays <= 0)
60
+ return 1;
61
+ if (!Number.isFinite(lastAt) || !Number.isFinite(now))
62
+ return 1;
63
+ const ageDays = (now - lastAt) / MS_PER_DAY;
64
+ if (!Number.isFinite(ageDays) || ageDays <= 0)
65
+ return 1;
66
+ return Math.pow(0.5, ageDays / halfLifeDays);
67
+ }
68
+ /**
69
+ * Derive confidence edges from a flat list of per-(fingerprint, gene) outcome observations.
70
+ * Pure and deterministic: the same observations (in any order — we track the max `at` for lastAt) always
71
+ * produce the same edges. This is the replay primitive — feed it the observations re-extracted from
72
+ * root_events and you get byte-identical edges back.
73
+ */
74
+ export function deriveConfidenceEdges(observations) {
75
+ const map = new Map();
76
+ for (const o of observations) {
77
+ if (!o || !o.geneId || !o.signalFingerprint)
78
+ continue;
79
+ if (o.status !== 'success' && o.status !== 'failed' && o.status !== 'inert')
80
+ continue;
81
+ const k = confidenceEdgeKey(o.signalFingerprint, o.geneId);
82
+ const cur = map.get(k) ?? {
83
+ signalFingerprint: o.signalFingerprint,
84
+ geneId: o.geneId,
85
+ successCount: 0,
86
+ failCount: 0,
87
+ inertCount: 0,
88
+ lastAt: 0,
89
+ baseConfidence: 0,
90
+ };
91
+ // #195: inert (zero-work) outcomes are tallied apart — they must NOT raise success/fail counts, so they
92
+ // build no positive confidence. They still advance lastAt (the gene WAS exercised; freshness is real).
93
+ if (o.status === 'success')
94
+ cur.successCount += 1;
95
+ else if (o.status === 'failed')
96
+ cur.failCount += 1;
97
+ else
98
+ cur.inertCount += 1;
99
+ const at = Number.isFinite(o.at) ? o.at : 0;
100
+ if (at > cur.lastAt)
101
+ cur.lastAt = at;
102
+ map.set(k, cur);
103
+ }
104
+ // Finalize baseConfidence once counts are known. Inert outcomes are excluded from the smoothing inputs, so an
105
+ // all-inert edge has success=0/fail=0 → the neutral 0.5 prior (no climb toward 1.0). Order-independent: the
106
+ // result is a pure function of the observation SET (counts + max `at`), never their sequence.
107
+ for (const edge of map.values()) {
108
+ edge.baseConfidence = laplaceSuccessRate(edge.successCount, edge.failCount);
109
+ }
110
+ return map;
111
+ }
112
+ /**
113
+ * Query the confidence of `geneId` under `signalFingerprint` at time `now`, in [0,1].
114
+ * = baseConfidence (Laplace-smoothed success rate) × half-life decay weight.
115
+ * Returns 0 when there is no edge (no history) so a never-tried gene gets no positive nudge —
116
+ * absence of evidence is not evidence of success — and 0 for a purely-inert edge (only zero-work cycles),
117
+ * so a do-nothing gene gets the same zero nudge as a never-tried one (#195).
118
+ */
119
+ export function confidenceFor(edges, signalFingerprint, geneId, now, halfLifeDays = CONFIDENCE_HALF_LIFE_DAYS) {
120
+ const edge = edges.get(confidenceEdgeKey(signalFingerprint, geneId));
121
+ if (!edge)
122
+ return 0;
123
+ // #195: a purely-inert edge (only zero-work cycles — no real success or failure) carries no positive evidence,
124
+ // so it must give the SAME zero nudge as a never-tried gene, not the neutral-prior 0.5 (which would leak a
125
+ // +CONFIDENCE_WEIGHT×0.5 boost and let a do-nothing gene out-rank an equal-health fresh candidate before the
126
+ // inert ban trips). Mirrors v1's hasPositiveEvidence (success>0) gate. A fail-only edge keeps its small Laplace
127
+ // nudge unchanged — that is pre-existing v2 behavior, out of #195's scope.
128
+ if (edge.successCount === 0 && edge.failCount === 0)
129
+ return 0;
130
+ const w = decayWeight(edge.lastAt, now, halfLifeDays);
131
+ const c = edge.baseConfidence * w;
132
+ return c < 0 ? 0 : c > 1 ? 1 : c;
133
+ }
134
+ /**
135
+ * Consecutive inert (zero-work) outcomes on a (fingerprint, gene) edge after which a gene with NO real success
136
+ * on that signal is banned, so `--loop` selection explores instead of re-running a do-nothing gene (#195).
137
+ * Port of v1 `GENE_INERT_BAN_STREAK` (env `EVOLVER_GENE_INERT_BAN_STREAK`, default 8); kept an inline const to
138
+ * match v2's algo-tunable convention (BAN_THRESHOLD / MIN_ENV_ATTEMPTS), not env-driven.
139
+ */
140
+ export const GENE_INERT_BAN_STREAK = 8;
141
+ /**
142
+ * Observation window (in raw events) over which the inert ban is derived — deliberately MUCH wider than the
143
+ * small recency window used for confidence SCORING. A banned gene runs as `ad-hoc` and accrues no new
144
+ * observation for itself, so its trailing inert run must be recomputed from a history wide enough that
145
+ * intervening innovate/ad-hoc cycles cannot evict it — and cannot evict an earlier real success that exempts
146
+ * the gene (`successCount > 0`). With a small window the run/exemption age out purely from unrelated cycles, so
147
+ * the ban flaps: the do-nothing gene resurfaces and the productive gene gets falsely banned (#195 regression).
148
+ * ~14000 events ≈ 2000 cycles, mirroring v1's multi-hundred-cycle memory-graph read horizon: far past any
149
+ * realistic flap window, yet still bounded (a long-idle gene's stale success eventually ages out, matching v1).
150
+ * `EventStore.tail()` reads the entire log regardless of window size, so a larger window costs no extra I/O.
151
+ */
152
+ export const INERT_BAN_OBSERVATION_WINDOW = 14_000;
153
+ /**
154
+ * Trailing consecutive-inert run per (fingerprint, gene), keyed by `confidenceEdgeKey`. Unlike
155
+ * `deriveConfidenceEdges` (a pure function of the observation SET), this is deliberately order-DEPENDENT: it
156
+ * counts inert outcomes from the most recent backward and ANY real success/failure resets the run to 0 — so a
157
+ * gene that ever does real work is never punished for older idle cycles. Input MUST be chronological
158
+ * (oldest→newest, i.e. the order `ingestor.tail` yields); the trailing run is the value left after the final
159
+ * observation per edge.
160
+ */
161
+ export function trailingInertByEdge(observations) {
162
+ const run = new Map();
163
+ for (const o of observations) {
164
+ if (!o || !o.geneId || !o.signalFingerprint)
165
+ continue;
166
+ const k = confidenceEdgeKey(o.signalFingerprint, o.geneId);
167
+ if (o.status === 'inert')
168
+ run.set(k, (run.get(k) ?? 0) + 1);
169
+ else if (o.status === 'success' || o.status === 'failed')
170
+ run.set(k, 0); // any real outcome breaks the run
171
+ }
172
+ return run;
173
+ }
174
+ /**
175
+ * Gene ids to ban for the CURRENT signal fingerprint because they are stuck producing inert (zero-work)
176
+ * cycles (#195). A gene is banned iff, on this fingerprint's edge, its trailing inert run ≥ `streak` AND it has
177
+ * ZERO real success on this signal (double guard: the consecutive run is reset by any real outcome, and a gene
178
+ * that ever truly succeeded here keeps successCount > 0). Banning a sole-matching inert gene lets selection
179
+ * fall through to mutation (selected:null → fresh gene), restoring diversity — the failure-streak ban never
180
+ * fires on these because nothing "fails". Per-signal, mirroring v1's per-signal-key ban: a gene idle on THIS
181
+ * signal can still be tried on others.
182
+ */
183
+ export function inertBannedGeneIds(edges, observations, fingerprint, streak = GENE_INERT_BAN_STREAK) {
184
+ const trailing = trailingInertByEdge(observations);
185
+ const banned = new Set();
186
+ for (const edge of edges.values()) {
187
+ if (edge.signalFingerprint !== fingerprint)
188
+ continue;
189
+ if (edge.successCount > 0)
190
+ continue; // ever did real work here → never banned for idle cycles
191
+ const k = confidenceEdgeKey(fingerprint, edge.geneId);
192
+ if ((trailing.get(k) ?? 0) >= streak)
193
+ banned.add(edge.geneId);
194
+ }
195
+ return banned;
196
+ }
@@ -0,0 +1,143 @@
1
+ import type { Ingestor } from '../events/ingest.js';
2
+ import type { ProblemPattern } from '../schema/problem.js';
3
+ import type { GepCategory, Mutation, Capsule, EvolutionEvent } from '../wire/index.js';
4
+ import type { AssetStoreProvider } from '../assetstore/provider.js';
5
+ import type { StrategyPoint } from '../strategy/strategyPoint.js';
6
+ import { type CycleStage } from '../cycle/stateMachine.js';
7
+ import { type GeneDecision, type SelectionInput, type GeneCandidateInput, type AntiWarning } from './geneSelection.js';
8
+ import { type EnvFingerprint } from '../bootstrap/envFingerprint.js';
9
+ import type { PersonalityStore } from '../personality/store.js';
10
+ import { type ResolutionStatus } from './solidify.js';
11
+ import type { ProofOfWork } from '../schema/proofOfWork.js';
12
+ import { type ClassifyRecentEvent } from './cycleFailureClassifier.js';
13
+ export interface TriggerEval {
14
+ trigger: boolean;
15
+ reasons: string[];
16
+ valueScore: number;
17
+ }
18
+ export interface ExecutionResult {
19
+ outcome: {
20
+ status: 'success' | 'failed';
21
+ score: number;
22
+ reason?: string;
23
+ };
24
+ proofOfWork?: ProofOfWork;
25
+ strongEvidence?: boolean;
26
+ /**
27
+ * The agent run's transcript (stdout, plus stderr when present), attached by the execution layer on a FAILED
28
+ * outcome. It is the host-side context classifyCycleFailure needs to reach the host_no_transcript /
29
+ * host_provider_error buckets on the PRODUCTION path (#279): an empty transcript means the host gave evolver
30
+ * nothing to evolve from; a provider-error string (429 / quota / context-length) means the host's LLM call
31
+ * failed, not the gene. Consumed only for failure triage and NEVER persisted to event payloads (the engine
32
+ * writes only the derived failure_class), so it adds no root_events bloat and leaks no transcript content.
33
+ */
34
+ sessionLog?: string;
35
+ }
36
+ export interface SolidifyPermitContext {
37
+ cycleId: string;
38
+ geneId: string;
39
+ signals: readonly string[];
40
+ mutation: Mutation;
41
+ decision: GeneDecision;
42
+ outcome: ExecutionResult['outcome'];
43
+ proofOfWork?: ProofOfWork;
44
+ strongEvidence?: boolean;
45
+ }
46
+ export type SolidifyPermitDecision = {
47
+ ok: true;
48
+ reason?: string;
49
+ } | {
50
+ ok: false;
51
+ reason: string;
52
+ detail?: string;
53
+ };
54
+ export type SolidifyPermitGate = (ctx: SolidifyPermitContext) => Promise<SolidifyPermitDecision> | SolidifyPermitDecision;
55
+ export interface CycleEngineDeps {
56
+ ingestor: Ingestor;
57
+ selection: StrategyPoint<SelectionInput, GeneDecision>;
58
+ store: AssetStoreProvider;
59
+ now: () => number;
60
+ /** Injected randomness for exploration drift (deterministic tests). Defaults to Math.random inside selection. */
61
+ rng?: () => number;
62
+ /** Injected environment fingerprint (deterministic tests). Defaults to capturing the real runtime env. */
63
+ envFingerprint?: () => EnvFingerprint;
64
+ /** 触发评估(常注入 TriggerEngine.evaluate 的包装; 缺省=直接触发). */
65
+ trigger?: (p: ProblemPattern, now: number) => Promise<TriggerEval> | TriggerEval;
66
+ /** 可进化人格(可选). 注入后, 每轮:
67
+ * - 轮首: (平台期?先 applyForcePivot→personality.pivoted) → applySelectForRun 自然选择+触发变异
68
+ * (personality.mutated), 落盘, 选出的状态喂 personality.selected + 人格风险闸(personality.risk_gated),
69
+ * 并被 exec bridge 读回注入 prompt(用途①).
70
+ * - 轮尾(拿到 outcome 后): applyStatsUpdate 把本轮 outcome/score 回写到当轮所用人格桶
71
+ * (personality.stats_updated); v1 语义: 只动 stats/history, 不挪 current.
72
+ * 缺省 ⇒ 完全不改现有行为(逐字向后兼容). 人格只调"风格/风险", 不改"选哪个 gene / 做什么"——
73
+ * 与 valueModel/gene 选择共存而非互斥. */
74
+ personality?: PersonalityStore;
75
+ }
76
+ export interface CycleInput {
77
+ cycleId: string;
78
+ problem: ProblemPattern;
79
+ signals: readonly string[];
80
+ category: GepCategory;
81
+ /** Optional explicit strategy preset name; when set, it wins over history-derived meta-signal auto-detection. */
82
+ strategyName?: string;
83
+ candidates: readonly GeneCandidateInput[];
84
+ selectionFloor?: number;
85
+ /**
86
+ * Explicit GEP/runtime-selected gene. Forwarded after candidate assembly and local hard filters, so it cannot
87
+ * bypass trust/review/ban; selection still rejects an env-suppressed candidate.
88
+ */
89
+ forcedGeneId?: string;
90
+ target: string;
91
+ expectedEffect: string;
92
+ summary: string;
93
+ confidence: number;
94
+ execute: (mutation: Mutation, decision: GeneDecision) => Promise<ExecutionResult> | ExecutionResult;
95
+ /** Optional adapter/runtime permit gate. Runs after execute succeeds and before solidify writes assets. */
96
+ solidifyPermit?: SolidifyPermitGate;
97
+ /**
98
+ * Distilled-gene fallback pool (ported from v1 #97): broadly-applicable distilled genes that do NOT match the
99
+ * live signals, assembled (trust/review/ban-filtered) upstream. Forwarded to selection, which uses one only as a
100
+ * last resort when no candidate clears the floor — reusing a known distilled strategy instead of a blind innovate.
101
+ */
102
+ distilledFallback?: readonly GeneCandidateInput[];
103
+ /** Advisory-only AntiGene warnings matched upstream for this cycle's base signals. */
104
+ antiWarnings?: readonly AntiWarning[];
105
+ /**
106
+ * Optional triage context for the cycle.failed event (PORT v1 #279 issue-reporter half). When the caller can
107
+ * supply a session transcript or a list of recent failed cycles, classifyCycleFailure runs and the resulting
108
+ * `failure_class` is written onto cycle.failed payloads. Inert handling (V2 #216) is untouched — this is purely
109
+ * additive metadata. When absent, host transcript classification stays off; V2-local no-blast classification may
110
+ * still run from the current failed gene + capsule blast radius.
111
+ *
112
+ * This is the EXTERNAL/test injection path. The PRODUCTION host transcript no longer comes through here: the
113
+ * execution layer (claudeBridge) attaches the agent transcript to ExecutionResult.sessionLog on a failed
114
+ * outcome, and the failed-write site feeds THAT into classifyCycleFailure (#279 wiring). So host_no_transcript /
115
+ * host_provider_error now fire on the real autonomous path. failureContext remains for callers that supply a
116
+ * transcript or recentFailedEvents out-of-band (and for tests). local_gene_no_blast runs in production from the
117
+ * current gene + capsule blast radius and needs neither.
118
+ */
119
+ failureContext?: {
120
+ sessionLog?: string;
121
+ recentFailedEvents?: readonly ClassifyRecentEvent[];
122
+ };
123
+ }
124
+ export interface CycleResult {
125
+ cycleId: string;
126
+ triggered: boolean;
127
+ finalStage: CycleStage;
128
+ decision?: GeneDecision;
129
+ mutation?: Mutation;
130
+ capsule?: Capsule;
131
+ event?: EvolutionEvent;
132
+ resolutionStatus?: ResolutionStatus;
133
+ reasons: string[];
134
+ }
135
+ /**
136
+ * cycle engine(M4A-1d): signals → trigger → 选 gene → mutation → 执行 → solidify → Capsule + EvolutionEvent.
137
+ * 每阶段 emit root_events 并校验状态机迁移; 写入序列守硬化 A4(capsule asset_id 先 → 填 capsule_id → event asset_id).
138
+ */
139
+ export declare class CycleEngine {
140
+ private readonly deps;
141
+ constructor(deps: CycleEngineDeps);
142
+ runCycle(input: CycleInput): Promise<CycleResult>;
143
+ }