2sagaco48 1.0.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 (365) hide show
  1. package/diagnostics.mjs +141 -0
  2. package/dist/compute.worker-j5ahIpF-.js +1 -0
  3. package/dist/graph.worker-DG6iGCB9.js +1 -0
  4. package/dist/index.html +2314 -0
  5. package/flatten-guide.md +248 -0
  6. package/index.html +12 -0
  7. package/package.json +38 -0
  8. package/src/App.orig.tsx +204 -0
  9. package/src/App.orig1.tsx +27 -0
  10. package/src/App.orig2.tsx +25 -0
  11. package/src/App.tsx +3 -0
  12. package/src/BaseApp.tsx +18 -0
  13. package/src/INTEGRATION_LEDGER.md +22 -0
  14. package/src/PERSIST_CANARY.orig.txt +1 -0
  15. package/src/PERSIST_CANARY.txt +1 -0
  16. package/src/REGRESSION_LEDGER.md +651 -0
  17. package/src/TEMPLATE_PIPELINE_AUDIT.md +208 -0
  18. package/src/WILLIAMS_PERSONA_GUIDE.md +62 -0
  19. package/src/chat/VeritasChat.tsx +69 -0
  20. package/src/chat/synthesis.ts +31 -0
  21. package/src/chat/tier.ts +45 -0
  22. package/src/components/AdaptersPage.orig.tsx +99 -0
  23. package/src/components/AdaptersPage.tsx +3 -0
  24. package/src/components/AdversarialPanel.tsx +136 -0
  25. package/src/components/AnchorBaselinePanel.tsx +75 -0
  26. package/src/components/AnswerPanel.tsx +60 -0
  27. package/src/components/ArtifactPanel.tsx +43 -0
  28. package/src/components/ChatApp.orig.tsx +1582 -0
  29. package/src/components/ChatApp.orig1.tsx +722 -0
  30. package/src/components/ChatApp.tsx +95 -0
  31. package/src/components/ChatAugmentPanels.tsx +73 -0
  32. package/src/components/CitationLedgerPanel.tsx +313 -0
  33. package/src/components/ComputeSandboxPanel.tsx +130 -0
  34. package/src/components/ConfigPanel.tsx +110 -0
  35. package/src/components/ControlPlanePage.tsx +195 -0
  36. package/src/components/CreativeTreeLifePage.tsx +234 -0
  37. package/src/components/CreativeTreeOfLifePanel.tsx +149 -0
  38. package/src/components/DebugTracePanel.tsx +137 -0
  39. package/src/components/DeepReasoningTrace.tsx +48 -0
  40. package/src/components/EntitySheetPanel.tsx +51 -0
  41. package/src/components/FailureModesPanel.tsx +104 -0
  42. package/src/components/GBSDashboard.tsx +239 -0
  43. package/src/components/GraphView.tsx +116 -0
  44. package/src/components/HUD.tsx +125 -0
  45. package/src/components/HypothesisPanel.tsx +67 -0
  46. package/src/components/InnovationGenomeEngine.tsx +792 -0
  47. package/src/components/InnovationPersonaGuide.tsx +348 -0
  48. package/src/components/InnovationPersonaPanel.tsx +289 -0
  49. package/src/components/LiveResourceHUD.tsx +109 -0
  50. package/src/components/LongWriterPanel.tsx +112 -0
  51. package/src/components/MainPipelineV10Bridge.tsx +72 -0
  52. package/src/components/MarkdownLite.tsx +63 -0
  53. package/src/components/MemoryInspector.tsx +38 -0
  54. package/src/components/MemoryMonitor.tsx +52 -0
  55. package/src/components/MemoryStressPanel.tsx +176 -0
  56. package/src/components/ModulesPage.tsx +171 -0
  57. package/src/components/PipelineDebugConsole.orig.tsx +1856 -0
  58. package/src/components/PipelineDebugConsole.tsx +3 -0
  59. package/src/components/PreFlightHUD.tsx +67 -0
  60. package/src/components/PrismaFetchTracePanel.tsx +87 -0
  61. package/src/components/ReportOSPanel.tsx +165 -0
  62. package/src/components/ResourceEstimatorPage.tsx +327 -0
  63. package/src/components/RichText.tsx +181 -0
  64. package/src/components/SagaOsPanel.tsx +605 -0
  65. package/src/components/SagaOsReference.tsx +421 -0
  66. package/src/components/SagaOsV2Panel.tsx +594 -0
  67. package/src/components/SagaStyleTab.tsx +382 -0
  68. package/src/components/SageBlueprintPanel.tsx +416 -0
  69. package/src/components/SharedChatInput.tsx +77 -0
  70. package/src/components/StatFinancePanel.tsx +190 -0
  71. package/src/components/StylePersonaPanel.tsx +128 -0
  72. package/src/components/TemplatesPage.tsx +300 -0
  73. package/src/components/TestPanel.tsx +63 -0
  74. package/src/components/TraceLog.tsx +89 -0
  75. package/src/components/V15CalibrationAugment.tsx +1134 -0
  76. package/src/components/V15CalibrationDialog.tsx +1871 -0
  77. package/src/components/V15Overlay.orig.tsx +120 -0
  78. package/src/components/V15Overlay.tsx +4 -0
  79. package/src/components/V15OverlayWrapper.tsx +362 -0
  80. package/src/components/V15Toggle.tsx +34 -0
  81. package/src/console/DiagnosticRecoveryPanel.tsx +358 -0
  82. package/src/console/EngineeringConsole.tsx +103 -0
  83. package/src/console/FictionSystemPanels.tsx +882 -0
  84. package/src/console/InspectorPanels.tsx +254 -0
  85. package/src/console/ManuscriptGraderPanel.tsx +182 -0
  86. package/src/console/RecursiveReviserPanel.tsx +245 -0
  87. package/src/console/SeedControlPanel.tsx +135 -0
  88. package/src/console/StoryControllerPanel.tsx +443 -0
  89. package/src/console/engineBridge.ts +258 -0
  90. package/src/console/gemini.ts +106 -0
  91. package/src/console/grading.ts +250 -0
  92. package/src/console/util.ts +45 -0
  93. package/src/fiction/continuity.ts +372 -0
  94. package/src/fiction/crash-protection.ts +111 -0
  95. package/src/fiction/diagnostics.ts +208 -0
  96. package/src/fiction/diff.ts +74 -0
  97. package/src/fiction/entity-state-machine.ts +214 -0
  98. package/src/fiction/nive-engine.ts +404 -0
  99. package/src/fiction/pipeline-selftest.ts +132 -0
  100. package/src/fiction/seed-control.ts +193 -0
  101. package/src/fiction/story-engine.ts +326 -0
  102. package/src/fiction/types.ts +68 -0
  103. package/src/flatten-guide.md +379 -0
  104. package/src/index.css +14 -0
  105. package/src/index.orig.css +13 -0
  106. package/src/lib/academic-sources.base.ts +188 -0
  107. package/src/lib/academic-sources.orig.ts +28 -0
  108. package/src/lib/academic-sources.ts +10 -0
  109. package/src/lib/advanced-math.ts +119 -0
  110. package/src/lib/adversarial-engine.base.ts +409 -0
  111. package/src/lib/adversarial-engine.ts +82 -0
  112. package/src/lib/ai-revision.ts +623 -0
  113. package/src/lib/app-state.tsx +426 -0
  114. package/src/lib/artifact-registry.ts +97 -0
  115. package/src/lib/artifacts.ts +180 -0
  116. package/src/lib/atlas-dr.ts +167 -0
  117. package/src/lib/browser-mtls.ts +127 -0
  118. package/src/lib/browser-queue.ts +221 -0
  119. package/src/lib/browser-search-scraper.base.ts +382 -0
  120. package/src/lib/browser-search-scraper.orig.ts +90 -0
  121. package/src/lib/browser-search-scraper.ts +10 -0
  122. package/src/lib/calc-interceptor.ts +82 -0
  123. package/src/lib/citation-lane-tap.ts +78 -0
  124. package/src/lib/citation-ledger-store.ts +369 -0
  125. package/src/lib/citation-ledger.ts +203 -0
  126. package/src/lib/compute-sandbox.ts +215 -0
  127. package/src/lib/compute.worker.ts +153 -0
  128. package/src/lib/connectors/gemini.ts +120 -0
  129. package/src/lib/connectors/jina.ts +233 -0
  130. package/src/lib/connectors/marketdata.ts +51 -0
  131. package/src/lib/connectors/prismafetch.base.ts +175 -0
  132. package/src/lib/connectors/prismafetch.ts +1 -0
  133. package/src/lib/connectors/serpapi.ts +65 -0
  134. package/src/lib/connectors/wikidata.ts +44 -0
  135. package/src/lib/constraints.ts +331 -0
  136. package/src/lib/continuation-detector.base.ts +153 -0
  137. package/src/lib/continuation-detector.ts +48 -0
  138. package/src/lib/contradraft.ts +168 -0
  139. package/src/lib/cors-proxy.ts +120 -0
  140. package/src/lib/coverage.ts +81 -0
  141. package/src/lib/debug/architecture-prescription.ts +556 -0
  142. package/src/lib/debug/covea-repair.ts +543 -0
  143. package/src/lib/debug/helios-ground.ts +319 -0
  144. package/src/lib/debug/intent-decomposer.ts +281 -0
  145. package/src/lib/debug/intent-lattice.ts +349 -0
  146. package/src/lib/debug/pipeline-diagnosis.ts +1149 -0
  147. package/src/lib/debug/pipeline-trace-bus.ts +424 -0
  148. package/src/lib/debug/prompt-forge.ts +678 -0
  149. package/src/lib/debug/repair-sites.ts +513 -0
  150. package/src/lib/debug/research-phase.ts +266 -0
  151. package/src/lib/debug/retrieval-context.ts +76 -0
  152. package/src/lib/debug/retrieval-hardener.ts +142 -0
  153. package/src/lib/debug/scraper-debug-runner.ts +576 -0
  154. package/src/lib/debug/scraper-forensics.ts +418 -0
  155. package/src/lib/debug/scraper-lane-roadmap.ts +136 -0
  156. package/src/lib/debug/self-test.ts +415 -0
  157. package/src/lib/debug/step-attribution.ts +211 -0
  158. package/src/lib/debug/template-rubric.ts +301 -0
  159. package/src/lib/debug/unified-innovation.ts +126 -0
  160. package/src/lib/debug/veritas-hybrid-scraper.ts +335 -0
  161. package/src/lib/defense-registry.ts +104 -0
  162. package/src/lib/defenses.ts +162 -0
  163. package/src/lib/deterministic-citation-ledger.ts +174 -0
  164. package/src/lib/elo-registry.base.ts +117 -0
  165. package/src/lib/elo-registry.ts +1 -0
  166. package/src/lib/entity-resolver.ts +291 -0
  167. package/src/lib/failure-modes.ts +267 -0
  168. package/src/lib/feature-registry.ts +69 -0
  169. package/src/lib/flaw-registry.ts +143 -0
  170. package/src/lib/flaws/_template.ts +52 -0
  171. package/src/lib/flaws/builtins.ts +63 -0
  172. package/src/lib/flaws/finance.ts +169 -0
  173. package/src/lib/flaws/fixers.ts +10 -0
  174. package/src/lib/flaws/index.ts +32 -0
  175. package/src/lib/flaws/legal.ts +157 -0
  176. package/src/lib/flaws/medical.ts +188 -0
  177. package/src/lib/flaws/original-defenses-pack.ts +81 -0
  178. package/src/lib/flaws/sample-declarative-pack.json +38 -0
  179. package/src/lib/flaws/selftest.ts +201 -0
  180. package/src/lib/flaws/software-extended.ts +125 -0
  181. package/src/lib/flaws/software-rn-webgl.ts +182 -0
  182. package/src/lib/flaws/statistics-advanced.ts +46 -0
  183. package/src/lib/flaws/statistics.ts +61 -0
  184. package/src/lib/gbse/config.ts +20 -0
  185. package/src/lib/gbse/engine.ts +226 -0
  186. package/src/lib/gbse/graph.ts +118 -0
  187. package/src/lib/gbse/graph.worker.ts +21 -0
  188. package/src/lib/gbse/tests.ts +117 -0
  189. package/src/lib/gbse/tiers.ts +65 -0
  190. package/src/lib/gbse/types.ts +94 -0
  191. package/src/lib/innovation-genome-engine-v2.orig.ts +1001 -0
  192. package/src/lib/innovation-genome-engine-v2.ts +3 -0
  193. package/src/lib/innovation-genome-engine.orig.ts +330 -0
  194. package/src/lib/innovation-genome-engine.ts +3 -0
  195. package/src/lib/innovation-genome-v10.orig.ts +314 -0
  196. package/src/lib/innovation-genome-v10.ts +2 -0
  197. package/src/lib/innovation-genome-v3.orig.ts +2015 -0
  198. package/src/lib/innovation-genome-v3.ts +2 -0
  199. package/src/lib/innovation-genome-v4.orig.ts +1959 -0
  200. package/src/lib/innovation-genome-v4.ts +2 -0
  201. package/src/lib/innovation-genome-v5.orig.ts +1210 -0
  202. package/src/lib/innovation-genome-v5.ts +2 -0
  203. package/src/lib/innovation-genome-v7.orig.ts +2549 -0
  204. package/src/lib/innovation-genome-v7.ts +2 -0
  205. package/src/lib/innovation-genome-v8.orig.ts +1485 -0
  206. package/src/lib/innovation-genome-v8.ts +2 -0
  207. package/src/lib/innovation-genome-v9.orig.ts +643 -0
  208. package/src/lib/innovation-genome-v9.ts +2 -0
  209. package/src/lib/jina.base.ts +293 -0
  210. package/src/lib/jina.ts +1 -0
  211. package/src/lib/live-telemetry.ts +61 -0
  212. package/src/lib/longwriter.ts +84 -0
  213. package/src/lib/manuscript-grade-v2.ts +298 -0
  214. package/src/lib/memory-governor.ts +173 -0
  215. package/src/lib/memory-stress-tests.ts +248 -0
  216. package/src/lib/model-intelligence.ts +48 -0
  217. package/src/lib/model-rotator.ts +75 -0
  218. package/src/lib/models.orig.ts +513 -0
  219. package/src/lib/models.ts +151 -0
  220. package/src/lib/n-deep.base.ts +592 -0
  221. package/src/lib/n-deep.ts +51 -0
  222. package/src/lib/nih-simulator.ts +56 -0
  223. package/src/lib/nih-vulnerability-fixes.ts +460 -0
  224. package/src/lib/omega-templates.base.ts +294 -0
  225. package/src/lib/omega-templates.ts +225 -0
  226. package/src/lib/omni-nexus.ts +64 -0
  227. package/src/lib/oracle-adapters.ts +67 -0
  228. package/src/lib/oracle-registry.ts +163 -0
  229. package/src/lib/orchestrator.ts +357 -0
  230. package/src/lib/output-boundary.ts +235 -0
  231. package/src/lib/overrides/vite-native-chaos-harness.ts +154 -0
  232. package/src/lib/overrides/vite-native-contract-plane.ts +245 -0
  233. package/src/lib/overrides/vite-native-doctor-plane.ts +208 -0
  234. package/src/lib/overrides/vite-native-knowledge-store.ts +267 -0
  235. package/src/lib/overrides/vite-native-policy-plane.ts +190 -0
  236. package/src/lib/overrides/vite-native-replay-plane.ts +197 -0
  237. package/src/lib/overrides/vite-native-runtime-plane.ts +106 -0
  238. package/src/lib/overrides/vite-native-scraper.ts +848 -0
  239. package/src/lib/overrides/vite-native-selftest-functional.ts +217 -0
  240. package/src/lib/overrides/vite-native-selftest.ts +183 -0
  241. package/src/lib/overrides/vite-native-snapshot-plane.ts +123 -0
  242. package/src/lib/philosophy-toolkit.ts +75 -0
  243. package/src/lib/pipeline.orig.ts +659 -0
  244. package/src/lib/pipeline.ts +42 -0
  245. package/src/lib/precache.ts +128 -0
  246. package/src/lib/py-sandbox.ts +205 -0
  247. package/src/lib/quality-score.ts +96 -0
  248. package/src/lib/quant-engine.ts +231 -0
  249. package/src/lib/quant-lib.ts +80 -0
  250. package/src/lib/reportos.ts +175 -0
  251. package/src/lib/research-os.ts +306 -0
  252. package/src/lib/resource-estimator.ts +114 -0
  253. package/src/lib/rpm-governor.ts +93 -0
  254. package/src/lib/runtime-estimator.ts +135 -0
  255. package/src/lib/sage/empty-space-v6.ts +560 -0
  256. package/src/lib/sage/empty-space-v7.ts +222 -0
  257. package/src/lib/sage/empty-space.ts +733 -0
  258. package/src/lib/sage/engine.ts +786 -0
  259. package/src/lib/sage/index.ts +17 -0
  260. package/src/lib/sage/judge.ts +246 -0
  261. package/src/lib/sage/prng.ts +53 -0
  262. package/src/lib/sage/reality-grounding.ts +380 -0
  263. package/src/lib/sage/repetition.ts +151 -0
  264. package/src/lib/sage/saga-os-v2-engines.ts +1870 -0
  265. package/src/lib/sage/saga-os-v2.ts +274 -0
  266. package/src/lib/sage/saga-os-v3-core.ts +1491 -0
  267. package/src/lib/sage/saga-os-v3-release.ts +739 -0
  268. package/src/lib/sage/saga-os-v4-aureate.ts +1161 -0
  269. package/src/lib/sage/saga-os-v4.ts +212 -0
  270. package/src/lib/sage/saga-os-v5.ts +205 -0
  271. package/src/lib/sage/saga-os-v6.ts +346 -0
  272. package/src/lib/sage/saga-os-v7.ts +314 -0
  273. package/src/lib/sage/saga-os-v8.ts +505 -0
  274. package/src/lib/sage/saga-os.ts +329 -0
  275. package/src/lib/sage/taxonomy.ts +403 -0
  276. package/src/lib/sage/unified-roll.ts +524 -0
  277. package/src/lib/sage/worked-sketches.ts +44 -0
  278. package/src/lib/sage.ts +166 -0
  279. package/src/lib/scraper-debug-bus.ts +53 -0
  280. package/src/lib/scraper-enhanced.orig.ts +153 -0
  281. package/src/lib/scraper-enhanced.ts +10 -0
  282. package/src/lib/scraper-hardener.base.orig.ts +155 -0
  283. package/src/lib/scraper-hardener.base.ts +317 -0
  284. package/src/lib/scraper-hardener.ts +1 -0
  285. package/src/lib/scraper-palisade/palisade-adjudicator.orig.ts +419 -0
  286. package/src/lib/scraper-palisade/palisade-adjudicator.ts +13 -0
  287. package/src/lib/scraper-vnext/arbiter-omega.orig.ts +688 -0
  288. package/src/lib/scraper-vnext/arbiter-omega.ts +13 -0
  289. package/src/lib/scraper-vnext/canonical-portfolio-augments.ts +479 -0
  290. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.orig.ts +1529 -0
  291. package/src/lib/scraper-vnext/canonical-portfolio-orchestrator.ts +13 -0
  292. package/src/lib/scraper-vnext/conclave-omega.ts +1830 -0
  293. package/src/lib/scraper-vnext/content-extractor-v2.ts +226 -0
  294. package/src/lib/scraper-vnext/diagnostics-suite.ts +36 -0
  295. package/src/lib/scraper-vnext/epistemic-packer.ts +97 -0
  296. package/src/lib/scraper-vnext/fusion-v2.ts +65 -0
  297. package/src/lib/scraper-vnext/hydra-reader.orig.ts +1216 -0
  298. package/src/lib/scraper-vnext/hydra-reader.ts +13 -0
  299. package/src/lib/scraper-vnext/native-scraper-browser-vnext.orig.ts +91 -0
  300. package/src/lib/scraper-vnext/native-scraper-browser-vnext.ts +13 -0
  301. package/src/lib/scraper-vnext/nexus-consensus.orig.ts +905 -0
  302. package/src/lib/scraper-vnext/nexus-consensus.ts +13 -0
  303. package/src/lib/scraper-vnext/portfolio-consensus-adjudicator.ts +804 -0
  304. package/src/lib/scraper-vnext/portfolio-consensus-memory.ts +377 -0
  305. package/src/lib/scraper-vnext/portfolio-terminal-governor.ts +548 -0
  306. package/src/lib/scraper-vnext/query-strategist.orig.ts +224 -0
  307. package/src/lib/scraper-vnext/query-strategist.ts +423 -0
  308. package/src/lib/scraper-vnext/retrieval-accelerator.ts +708 -0
  309. package/src/lib/scraper-vnext/retrieval-audit-augments.ts +477 -0
  310. package/src/lib/scraper-vnext/retrieval-control-plane.ts +904 -0
  311. package/src/lib/scraper-vnext/retrieval-policy-augments.ts +358 -0
  312. package/src/lib/scraper-vnext/safe-fetch-v2.ts +157 -0
  313. package/src/lib/scraper-vnext/sentinel-omega.ts +56 -0
  314. package/src/lib/scraper-vnext/sentinel-orchestrator.ts +69 -0
  315. package/src/lib/scraper-vnext/sibyl-oracle.orig.ts +413 -0
  316. package/src/lib/scraper-vnext/sibyl-oracle.ts +13 -0
  317. package/src/lib/scraper-vnext/smart-read-v2.ts +55 -0
  318. package/src/lib/scraper-vnext/spa-rescue-bridge.ts +608 -0
  319. package/src/lib/scraper-vnext/strata-engine.orig.ts +2666 -0
  320. package/src/lib/scraper-vnext/strata-engine.ts +13 -0
  321. package/src/lib/scraper-vnext/structured-source-adapter.orig.ts +369 -0
  322. package/src/lib/scraper-vnext/structured-source-adapter.ts +34 -0
  323. package/src/lib/scraper-vnext/terminal-complete.ts +224 -0
  324. package/src/lib/scraper-vnext/terminal-final.ts +277 -0
  325. package/src/lib/scraper-vnext/terminal-saturation.ts +345 -0
  326. package/src/lib/scraper-vnext/terminal-wire.ts +425 -0
  327. package/src/lib/scraper-vnext/vanguard-titanium.orig.ts +467 -0
  328. package/src/lib/scraper-vnext/vanguard-titanium.ts +17 -0
  329. package/src/lib/search-cache.ts +138 -0
  330. package/src/lib/sloop-runner.base.ts +223 -0
  331. package/src/lib/sloop-runner.ts +104 -0
  332. package/src/lib/sloop.ts +114 -0
  333. package/src/lib/small-model-adapters.ts +82 -0
  334. package/src/lib/sscp.ts +86 -0
  335. package/src/lib/system-map.ts +54 -0
  336. package/src/lib/uni-node.ts +86 -0
  337. package/src/lib/universal-rigor-guard.ts +433 -0
  338. package/src/lib/v15-gate-testbed.ts +274 -0
  339. package/src/lib/v15-gemini.base.ts +89 -0
  340. package/src/lib/v15-gemini.ts +1 -0
  341. package/src/lib/v15-grounding.orig.ts +241 -0
  342. package/src/lib/v15-grounding.ts +79 -0
  343. package/src/lib/v15-pipeline.base.ts +769 -0
  344. package/src/lib/v15-pipeline.orig.ts +1154 -0
  345. package/src/lib/v15-pipeline.ts +674 -0
  346. package/src/lib/v15-questions.ts +64 -0
  347. package/src/lib/v15-rate-limiter.orig.ts +91 -0
  348. package/src/lib/v15-rate-limiter.ts +48 -0
  349. package/src/lib/v15-state.base.ts +87 -0
  350. package/src/lib/v15-state.ts +28 -0
  351. package/src/lib/visual-table-generator.tsx +207 -0
  352. package/src/lib/wasm-runtime.ts +133 -0
  353. package/src/lib/williams-persona-guide.ts +265 -0
  354. package/src/lib/williams-style.base.ts +464 -0
  355. package/src/lib/williams-style.ts +59 -0
  356. package/src/lib/worker-pool.ts +96 -0
  357. package/src/lib/writing-tiers.ts +125 -0
  358. package/src/main.orig.tsx +10 -0
  359. package/src/main.tsx +10 -0
  360. package/src/utils/cn.orig.ts +6 -0
  361. package/src/utils/cn.ts +6 -0
  362. package/src/vite-env.d.ts +1 -0
  363. package/tsconfig.json +31 -0
  364. package/unify.mjs +537 -0
  365. package/vite.config.ts +18 -0
@@ -0,0 +1,2015 @@
1
+ /**
2
+ * innovation-genome-v3.ts — Innovation Genome Engine V3.0, verified discovery
3
+ * runtime. TypeScript port of the supplied `innovation_genome_v3.py`.
4
+ * ============================================================================
5
+ * RUNTIME HONESTY (per task instructions — read before trusting any claim
6
+ * of "verbatim 1:1" below):
7
+ *
8
+ * Tools actually available in this session: file read/write/edit, a Vite
9
+ * build tool, static grep. No Python interpreter, no independent test
10
+ * runner, no network fetch, no theorem prover, no SQLite. Nothing below
11
+ * was executed against the original Python file — it could not be, because
12
+ * the Python source pasted into the task was itself already truncated
13
+ * (see §7 note) before it reached this file. Every claim of "1:1" is a
14
+ * claim about the TypeScript SOURCE CODE topology (same class/field names,
15
+ * same algorithms, same validation rules), verified by side-by-side reading
16
+ * of this file against the pasted spec — not by running both and diffing
17
+ * output, which is impossible without a Python runtime in this workspace.
18
+ *
19
+ * Sections 1–6 of the pasted spec (deterministic utilities, the P/A/E/N/V/T/S
20
+ * graph-life scheduler, GoalSpec/EvaluatorSpec/Candidate/Report dataclasses,
21
+ * adapter protocols, mutation policy + calibration, budget accounting) were
22
+ * supplied WITHOUT truncation. Those are ported line-for-line: same field
23
+ * names, same validation predicates, same hashing material, same thresholds.
24
+ *
25
+ * Section 7 onward (EventStore SQL bodies, ToolRegistry, the 7-D descriptor,
26
+ * the versioned archive, the GEPA-feedback mutation engine, the discovery
27
+ * engine, and `generate_v3_report`) arrived in the task prompt with the SQL
28
+ * query strings and several class/method BODIES already blanked out by
29
+ * whatever stripped the code before it reached me (e.g. `self.@7.@KC(,
30
+ * (row,))` — the query text itself is missing, only the call shape survives).
31
+ * I cannot invent the exact missing SQL and call it "verbatim" — that would
32
+ * be a fabrication. Instead: every CONTRACT that IS fully legible in that
33
+ * truncated region (event-hash chain material, `verify_chain` walk logic,
34
+ * checkpoint hashing, memory priority validation, the "Versioning Invariant"
35
+ * docstring, the 105-mechanism report shape actually printed by
36
+ * `generate_v3_report`, and the full CLI `main()` body) is reproduced
37
+ * exactly. Where only a docstring survived and the body did not (the
38
+ * subprocess tool adapter, the archive bucketing, the mutation engine, the
39
+ * discovery engine's internal loop), I implement the DESCRIBED BEHAVIOUR in
40
+ * full, functioning, non-mocked code, and say so explicitly in the comment
41
+ * directly above each such class. SQLite itself does not exist in a browser
42
+ * runtime at all (no filesystem, no native SQLite driver in a Vite SPA), so
43
+ * the EventStore below is disclosed, necessary substitution: an in-memory,
44
+ * hash-chained event log using the EXACT SAME hashing algorithm the spec
45
+ * gives for `append_event`/`verify_chain`, backed by `localStorage` so it
46
+ * survives reloads the same way the Python version's on-disk SQLite file
47
+ * would survive process restarts.
48
+ * ============================================================================ */
49
+
50
+ import {
51
+ DIMENSIONS,
52
+ compileInnovationPrompt,
53
+ seedToGenome,
54
+ type Genome,
55
+ } from '@/lib/innovation-genome-engine';
56
+ import {
57
+ DIMENSION_BLOCKS,
58
+ DOMAIN_PACKS,
59
+ CapabilityGate,
60
+ SafetyGate,
61
+ applyMutation,
62
+ classifyPersonaExtended,
63
+ selectPathExtended,
64
+ type DomainPack,
65
+ type RiskTier,
66
+ } from '@/lib/innovation-genome-engine-v2';
67
+
68
+ // ═══════════════════════════════════════════════════════════════════════
69
+ // 0. Synchronous SHA-256 (FIPS 180-4) — browsers have no synchronous
70
+ // crypto.subtle.digest, and content_hash is used as a *synchronous*
71
+ // getter throughout the Python spec (a @property), so a sync
72
+ // implementation is required for parity. Verified in diagnostics
73
+ // against the two published NIST test vectors (empty string and "abc").
74
+ // ═══════════════════════════════════════════════════════════════════════
75
+ const SHA256_K = new Uint32Array([
76
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
77
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
78
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
79
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
80
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
81
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
82
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
83
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
84
+ ]);
85
+
86
+ function rotr(x: number, n: number): number {
87
+ return (x >>> n) | (x << (32 - n));
88
+ }
89
+
90
+ function sha256Bytes(bytes: Uint8Array): Uint8Array {
91
+ let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;
92
+ let h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
93
+
94
+ const bitLen = bytes.length * 8;
95
+ const padded = new Uint8Array((bytes.length + 9 + 63) & ~63);
96
+ padded.set(bytes);
97
+ padded[bytes.length] = 0x80;
98
+ const view = new DataView(padded.buffer);
99
+ view.setUint32(padded.length - 4, bitLen >>> 0, false);
100
+ view.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000), false);
101
+
102
+ const w = new Uint32Array(64);
103
+ for (let chunk = 0; chunk < padded.length; chunk += 64) {
104
+ for (let i = 0; i < 16; i++) w[i] = view.getUint32(chunk + i * 4, false);
105
+ for (let i = 16; i < 64; i++) {
106
+ const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
107
+ const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
108
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
109
+ }
110
+
111
+ let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
112
+ for (let i = 0; i < 64; i++) {
113
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
114
+ const ch = (e & f) ^ (~e & g);
115
+ const temp1 = (h + S1 + ch + SHA256_K[i] + w[i]) >>> 0;
116
+ const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
117
+ const maj = (a & b) ^ (a & c) ^ (b & c);
118
+ const temp2 = (S0 + maj) >>> 0;
119
+ h = g; g = f; f = e; e = (d + temp1) >>> 0;
120
+ d = c; c = b; b = a; a = (temp1 + temp2) >>> 0;
121
+ }
122
+
123
+ h0 = (h0 + a) >>> 0; h1 = (h1 + b) >>> 0; h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0;
124
+ h4 = (h4 + e) >>> 0; h5 = (h5 + f) >>> 0; h6 = (h6 + g) >>> 0; h7 = (h7 + h) >>> 0;
125
+ }
126
+
127
+ const out = new Uint8Array(32);
128
+ const outView = new DataView(out.buffer);
129
+ [h0, h1, h2, h3, h4, h5, h6, h7].forEach((h, i) => outView.setUint32(i * 4, h, false));
130
+ return out;
131
+ }
132
+
133
+ function bytesToHex(bytes: Uint8Array): string {
134
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
135
+ }
136
+
137
+ // ═══════════════════════════════════════════════════════════════════════
138
+ // 1. Deterministic utilities — verbatim port of §1
139
+ // ═══════════════════════════════════════════════════════════════════════
140
+ export const ZERO_HASH = "0".repeat(64);
141
+ export const STANDARD_METRICS = ["novelty", "utility", "tractability", "robustness", "taste"] as const;
142
+ export type StandardMetric = (typeof STANDARD_METRICS)[number];
143
+
144
+ export function utcNow(): string {
145
+ return new Date().toISOString();
146
+ }
147
+
148
+ export function canonicalJson(value: unknown): string {
149
+ const canon = (v: unknown): string => {
150
+ if (v === null || v === undefined) return "null";
151
+ if (typeof v === "number") return Number.isFinite(v) ? String(v) : "null";
152
+ if (typeof v === "boolean") return v ? "true" : "false";
153
+ if (typeof v === "string") return JSON.stringify(v);
154
+ if (Array.isArray(v)) return `[${v.map(canon).join(",")}]`;
155
+ if (typeof v === "object") {
156
+ const record = v as Record<string, unknown>;
157
+ const keys = Object.keys(record).sort();
158
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canon(record[k])}`).join(",")}}`;
159
+ }
160
+ return "null";
161
+ };
162
+ return canon(value);
163
+ }
164
+
165
+ export function sha256Text(value: string): string {
166
+ return bytesToHex(sha256Bytes(new TextEncoder().encode(value)));
167
+ }
168
+
169
+ /**
170
+ * derive_seed(*parts) — Python takes the first 8 bytes of sha256 as a
171
+ * big-endian *64-bit* unsigned integer. JS `number` only safely represents
172
+ * 53 bits, and the downstream `seedToGenome(seed: number)` from the V1
173
+ * engine already expects a 32-bit-range seed. Disclosed adaptation: this
174
+ * function truncates to the low 32 bits of that 64-bit value so it is a
175
+ * valid argument everywhere V1/V2 expect a `number` seed. The full 64-bit
176
+ * value remains available via `deriveSeedBigInt` for anyone who needs exact
177
+ * parity with the Python integer.
178
+ */
179
+ export function deriveSeedBigInt(...parts: unknown[]): bigint {
180
+ const material = parts.map((p) => String(p)).join("|");
181
+ const digest = sha256Bytes(new TextEncoder().encode(material));
182
+ let value = 0n;
183
+ for (let i = 0; i < 8; i++) value = (value << 8n) | BigInt(digest[i]);
184
+ return value;
185
+ }
186
+
187
+ export function deriveSeed(...parts: unknown[]): number {
188
+ return Number(deriveSeedBigInt(...parts) % 4294967296n);
189
+ }
190
+
191
+ export function clamp01(value: number): number {
192
+ return Math.round(Math.max(0, Math.min(1, value)) * 10000) / 10000;
193
+ }
194
+
195
+ export function dimensionIds(): readonly string[] {
196
+ return DIMENSIONS.map((d) => d.id);
197
+ }
198
+
199
+ export function validateGenome(genome: Genome): void {
200
+ const expected = new Set(dimensionIds());
201
+ const actual = new Set(Object.keys(genome));
202
+
203
+ const missing = [...expected].filter((k) => !actual.has(k)).sort();
204
+ const extra = [...actual].filter((k) => !expected.has(k)).sort();
205
+
206
+ if (missing.length) throw new Error(`Genome missing dimensions: ${JSON.stringify(missing)}`);
207
+ if (extra.length) throw new Error(`Genome has unknown dimensions: ${JSON.stringify(extra)}`);
208
+
209
+ for (const [name, value] of Object.entries(genome)) {
210
+ if (typeof value !== "number" || Number.isNaN(value)) {
211
+ throw new TypeError(`Genome value ${JSON.stringify(name)} is not numeric`);
212
+ }
213
+ if (value < 0 || value > 1) {
214
+ throw new Error(`Genome value ${JSON.stringify(name)}=${value} outside [0,1]`);
215
+ }
216
+ }
217
+ }
218
+
219
+ // ═══════════════════════════════════════════════════════════════════════
220
+ // 2. Executable P/A/E/N/V/T/S graph-life scheduler — verbatim port of §2
221
+ // ═══════════════════════════════════════════════════════════════════════
222
+ export const NODE_LABELS: Readonly<Record<string, string>> = {
223
+ P: "Problem Choice and Framing",
224
+ A: "Anomaly Valuation",
225
+ E: "Embodiment and World Contact",
226
+ N: "Analogy and Representation Transfer",
227
+ V: "Evaluator Construction and Revision",
228
+ T: "Taste-Weighted Selection",
229
+ S: "Social Stabilization and Independent Review",
230
+ };
231
+
232
+ const NODE_ORDER = Object.keys(NODE_LABELS); // insertion order, matches Python dict iteration order
233
+
234
+ export const NODE_GRAPH: Readonly<Record<string, ReadonlySet<string>>> = {
235
+ P: new Set(["A", "N", "V", "T", "S"]),
236
+ A: new Set(["P", "E", "N", "V", "T"]),
237
+ E: new Set(["P", "A", "V", "S"]),
238
+ N: new Set(["P", "A", "V", "T", "S"]),
239
+ V: new Set(["P", "A", "E", "N", "T", "S"]),
240
+ T: new Set(["P", "A", "N", "V", "S"]),
241
+ S: new Set(["P", "E", "N", "V", "T"]),
242
+ };
243
+
244
+ /** Finite operational forms of V1/V2 paths — ported verbatim, including deliberate node repeats (ρ, σ, τ, υ, ψ, ω represent loops). */
245
+ export const PATH_NODES: Readonly<Record<string, readonly string[]>> = {
246
+ "α": ["P", "A", "E", "N", "V", "T", "S"],
247
+ "β": ["P", "N", "A", "V", "E", "T", "S"],
248
+ "γ": ["A", "P", "E", "V", "N", "T", "S"],
249
+ "δ": ["E", "A", "P", "N", "V", "T", "S"],
250
+ "ε": ["N", "P", "V", "A", "E", "T", "S"],
251
+ "ζ": ["T", "P", "A", "N", "V", "E", "S"],
252
+ "η": ["P", "V", "A", "E", "N", "T", "S"],
253
+ "θ": ["A", "N", "P", "V", "E", "T", "S"],
254
+ "ι": ["E", "P", "A", "V", "N", "T", "S"],
255
+ "κ": ["P", "A", "N", "V", "T", "E", "S"],
256
+ "λ": ["S", "P", "A", "E", "N", "V", "T"],
257
+ "μ": ["A", "E", "P", "V", "N", "T", "S"],
258
+ "ν": ["T", "A", "P", "N", "V", "E", "S"],
259
+ "ξ": ["N", "A", "V", "P", "E", "T", "S"],
260
+ "ο": ["P", "E", "A", "N", "V", "T", "S"],
261
+ "π": ["V", "P", "A", "E", "N", "T", "S"],
262
+ "ρ": ["P", "A", "V", "A", "V", "N", "T", "S"],
263
+ "σ": ["E", "A", "N", "V", "E", "A", "T", "S"],
264
+ "τ": ["T", "P", "A", "T", "N", "V", "E", "T", "S"],
265
+ "υ": ["P", "A", "E", "N", "V", "T", "S", "P"],
266
+ "φ": ["P", "N", "A", "V", "T", "E", "S"],
267
+ "χ": ["V", "P", "A", "E", "N", "T", "S"],
268
+ "ψ": ["P", "N", "N", "A", "V", "E", "T", "S"],
269
+ "ω": ["P", "A", "E", "N", "V", "T", "S", "S"],
270
+ };
271
+
272
+ const DEFAULT_PRIMARY: readonly string[] = ["P", "A", "E", "N", "V", "T", "S"];
273
+
274
+ export interface StageWaveJSON {
275
+ tick: number;
276
+ nodes: string[];
277
+ labels: string[];
278
+ source: string;
279
+ }
280
+
281
+ export class StageWave {
282
+ constructor(
283
+ public readonly tick: number,
284
+ public readonly nodes: readonly string[],
285
+ public readonly source: string,
286
+ ) {
287
+ Object.freeze(this);
288
+ }
289
+
290
+ toDict(): StageWaveJSON {
291
+ return {
292
+ tick: this.tick,
293
+ nodes: [...this.nodes],
294
+ labels: this.nodes.map((n) => NODE_LABELS[n]),
295
+ source: this.source,
296
+ };
297
+ }
298
+ }
299
+
300
+ export class GraphLifeScheduler {
301
+ readonly seed: number;
302
+ readonly genome: Genome;
303
+ readonly pathId: string;
304
+ readonly primary: readonly string[];
305
+
306
+ constructor(seed: number, genome: Genome, pathId: string) {
307
+ validateGenome(genome);
308
+ this.seed = seed;
309
+ this.genome = { ...genome };
310
+ this.pathId = pathId;
311
+ this.primary = PATH_NODES[pathId] ?? DEFAULT_PRIMARY;
312
+ }
313
+
314
+ private initialAlive(): Set<string> {
315
+ const digest = sha256Bytes(new TextEncoder().encode(`graph-life:${this.seed}:${this.pathId}`));
316
+ const alive = new Set<string>();
317
+ NODE_ORDER.forEach((node, index) => {
318
+ if (digest[index] & 1) alive.add(node);
319
+ });
320
+ alive.add(this.primary[0]);
321
+ return alive;
322
+ }
323
+
324
+ build(maxTicks = 7): StageWave[] {
325
+ if (maxTicks < 1) throw new Error("maxTicks must be >= 1");
326
+
327
+ let alive = this.initialAlive();
328
+ const seenStates = new Set<string>();
329
+ const visited = new Set<string>();
330
+ const waves: StageWave[] = [];
331
+
332
+ const birthThreshold = this.genome.portfolio_breadth >= 0.67 ? 3 : 2;
333
+ const survivalMax = this.genome.mechanism_independence >= 0.67 ? 4 : 3;
334
+
335
+ const primaryRank = new Map<string, number>();
336
+ this.primary.forEach((node, index) => {
337
+ if (!primaryRank.has(node)) primaryRank.set(node, index);
338
+ });
339
+
340
+ for (let tick = 0; tick < maxTicks; tick++) {
341
+ const state = [...alive].sort().join(",");
342
+ if (seenStates.has(state)) break;
343
+ seenStates.add(state);
344
+
345
+ const ordered = [...alive].sort((a, b) => {
346
+ const ra = primaryRank.get(a) ?? 10_000;
347
+ const rb = primaryRank.get(b) ?? 10_000;
348
+ if (ra !== rb) return ra - rb;
349
+ return a < b ? -1 : a > b ? 1 : 0;
350
+ });
351
+
352
+ if (ordered.length > 0) {
353
+ waves.push(new StageWave(tick, ordered, "graph-life"));
354
+ ordered.forEach((n) => visited.add(n));
355
+ }
356
+
357
+ const nextAlive = new Set<string>();
358
+ for (const node of NODE_ORDER) {
359
+ let liveNeighbors = 0;
360
+ for (const neighbor of NODE_GRAPH[node]) if (alive.has(neighbor)) liveNeighbors++;
361
+
362
+ if (alive.has(node)) {
363
+ if (liveNeighbors >= 1 && liveNeighbors <= survivalMax) nextAlive.add(node);
364
+ } else if (liveNeighbors === birthThreshold) {
365
+ nextAlive.add(node);
366
+ }
367
+ }
368
+
369
+ const nextRequired = this.primary.find((n) => !visited.has(n));
370
+ if (nextRequired !== undefined) nextAlive.add(nextRequired);
371
+
372
+ alive = nextAlive;
373
+ }
374
+
375
+ let nextTick = waves.length;
376
+ for (const node of this.primary) {
377
+ if (!visited.has(node)) {
378
+ waves.push(new StageWave(nextTick, [node], "path-coverage"));
379
+ visited.add(node);
380
+ nextTick += 1;
381
+ }
382
+ }
383
+
384
+ return waves;
385
+ }
386
+ }
387
+
388
+ // ═══════════════════════════════════════════════════════════════════════
389
+ // 3. Versioned goals, evaluator contracts, candidates and reports —
390
+ // verbatim port of §3
391
+ // ═══════════════════════════════════════════════════════════════════════
392
+ export interface GoalSpecInit {
393
+ version: number;
394
+ statement: string;
395
+ successCriteria: readonly string[];
396
+ hardConstraints: readonly string[];
397
+ softObjectives?: readonly string[];
398
+ parentHash?: string;
399
+ rationale?: string;
400
+ approvals?: readonly string[];
401
+ }
402
+
403
+ export class GoalSpec {
404
+ readonly version: number;
405
+ readonly statement: string;
406
+ readonly successCriteria: readonly string[];
407
+ readonly hardConstraints: readonly string[];
408
+ readonly softObjectives: readonly string[];
409
+ readonly parentHash: string;
410
+ readonly rationale: string;
411
+ readonly approvals: readonly string[];
412
+
413
+ constructor(init: GoalSpecInit) {
414
+ this.version = init.version;
415
+ this.statement = init.statement;
416
+ this.successCriteria = init.successCriteria;
417
+ this.hardConstraints = init.hardConstraints;
418
+ this.softObjectives = init.softObjectives ?? [];
419
+ this.parentHash = init.parentHash ?? "";
420
+ this.rationale = init.rationale ?? "initial goal";
421
+ this.approvals = init.approvals ?? [];
422
+ }
423
+
424
+ validate(): void {
425
+ if (this.version < 1) throw new Error("Goal version must be >= 1");
426
+ if (!this.statement.trim()) throw new Error("Goal statement is empty");
427
+ if (this.successCriteria.length === 0) throw new Error("Goal must contain success criteria");
428
+ if (this.hardConstraints.length === 0) throw new Error("Goal must contain hard constraints");
429
+ }
430
+
431
+ get contentHash(): string {
432
+ return sha256Text(
433
+ canonicalJson({
434
+ version: this.version,
435
+ statement: this.statement,
436
+ success_criteria: this.successCriteria,
437
+ hard_constraints: this.hardConstraints,
438
+ soft_objectives: this.softObjectives,
439
+ parent_hash: this.parentHash,
440
+ rationale: this.rationale,
441
+ approvals: this.approvals,
442
+ }),
443
+ );
444
+ }
445
+
446
+ static fromDict(raw: Record<string, unknown>): GoalSpec {
447
+ return new GoalSpec({
448
+ version: Number(raw.version),
449
+ statement: String(raw.statement),
450
+ successCriteria: [...(raw.success_criteria as string[])],
451
+ hardConstraints: [...(raw.hard_constraints as string[])],
452
+ softObjectives: [...((raw.soft_objectives as string[]) ?? [])],
453
+ parentHash: String(raw.parent_hash ?? ""),
454
+ rationale: String(raw.rationale ?? ""),
455
+ approvals: [...((raw.approvals as string[]) ?? [])],
456
+ });
457
+ }
458
+ }
459
+
460
+ export interface EvaluatorSpecInit {
461
+ version: number;
462
+ metrics?: readonly string[];
463
+ hardGates?: readonly string[];
464
+ parentHash?: string;
465
+ rationale?: string;
466
+ }
467
+
468
+ export class EvaluatorSpec {
469
+ readonly version: number;
470
+ readonly metrics: readonly string[];
471
+ readonly hardGates: readonly string[];
472
+ readonly parentHash: string;
473
+ readonly rationale: string;
474
+
475
+ constructor(init: EvaluatorSpecInit) {
476
+ this.version = init.version;
477
+ this.metrics = init.metrics ?? STANDARD_METRICS;
478
+ this.hardGates = init.hardGates ?? ["correctness", "scope", "evidence", "safety"];
479
+ this.parentHash = init.parentHash ?? "";
480
+ this.rationale = init.rationale ?? "initial evaluator";
481
+ }
482
+
483
+ validate(): void {
484
+ if (this.version < 1) throw new Error("Evaluator version must be >= 1");
485
+ if (this.metrics.length === 0) throw new Error("Evaluator must define metrics");
486
+ if (new Set(this.metrics).size !== this.metrics.length) throw new Error("Evaluator metrics contain duplicates");
487
+ if (this.hardGates.length === 0) throw new Error("Evaluator must define hard gates");
488
+ if (new Set(this.hardGates).size !== this.hardGates.length) throw new Error("Evaluator hard gates contain duplicates");
489
+ }
490
+
491
+ get contentHash(): string {
492
+ return sha256Text(
493
+ canonicalJson({
494
+ version: this.version,
495
+ metrics: this.metrics,
496
+ hard_gates: this.hardGates,
497
+ parent_hash: this.parentHash,
498
+ rationale: this.rationale,
499
+ }),
500
+ );
501
+ }
502
+
503
+ static fromDict(raw: Record<string, unknown>): EvaluatorSpec {
504
+ return new EvaluatorSpec({
505
+ version: Number(raw.version),
506
+ metrics: [...(raw.metrics as string[])],
507
+ hardGates: [...(raw.hard_gates as string[])],
508
+ parentHash: String(raw.parent_hash ?? ""),
509
+ rationale: String(raw.rationale ?? ""),
510
+ });
511
+ }
512
+ }
513
+
514
+ export interface GenerationRequest {
515
+ runId: string;
516
+ epoch: number;
517
+ candidateIndex: number;
518
+ candidateSeed: number;
519
+ goal: GoalSpec;
520
+ evaluatorSpec: EvaluatorSpec;
521
+ genome: Genome;
522
+ persona: { name: string; tagline: string };
523
+ path: { id: string; name: string; seq: string };
524
+ schedule: readonly StageWave[];
525
+ prompt: string;
526
+ }
527
+
528
+ export interface CandidateJSON {
529
+ candidate_id: string;
530
+ run_id: string;
531
+ epoch: number;
532
+ candidate_index: number;
533
+ candidate_seed: number;
534
+ goal_hash: string;
535
+ evaluator_hash: string;
536
+ genome: Genome;
537
+ persona: Record<string, string>;
538
+ path: Record<string, string>;
539
+ schedule: StageWaveJSON[];
540
+ artifact: string;
541
+ producer_name: string;
542
+ producer_family: string;
543
+ parent_ids: string[];
544
+ mutation_rationale: string;
545
+ artifact_hash: string;
546
+ }
547
+
548
+ export class BlindCandidate {
549
+ constructor(
550
+ public readonly candidateId: string,
551
+ public readonly runId: string,
552
+ public readonly epoch: number,
553
+ public readonly goalHash: string,
554
+ public readonly evaluatorHash: string,
555
+ public readonly genome: Genome,
556
+ public readonly artifact: string,
557
+ public readonly artifactHash: string,
558
+ ) {}
559
+ }
560
+
561
+ export class Candidate {
562
+ constructor(
563
+ public readonly candidateId: string,
564
+ public readonly runId: string,
565
+ public readonly epoch: number,
566
+ public readonly candidateIndex: number,
567
+ public readonly candidateSeed: number,
568
+ public readonly goalHash: string,
569
+ public readonly evaluatorHash: string,
570
+ public readonly genome: Genome,
571
+ public readonly persona: { name: string; tagline: string },
572
+ public readonly path: { id: string; name: string; seq: string },
573
+ public readonly schedule: readonly StageWave[],
574
+ public readonly artifact: string,
575
+ public readonly producerName: string,
576
+ public readonly producerFamily: string,
577
+ public readonly parentIds: readonly string[],
578
+ public readonly mutationRationale: string,
579
+ public readonly artifactHash: string,
580
+ ) {}
581
+
582
+ /** Evaluator-family separation: strips producer identity, persona, and path from what the evaluator sees, so evaluators cannot exhibit self-preference toward a producer they recognize. */
583
+ blind(): BlindCandidate {
584
+ return new BlindCandidate(
585
+ this.candidateId,
586
+ this.runId,
587
+ this.epoch,
588
+ this.goalHash,
589
+ this.evaluatorHash,
590
+ { ...this.genome },
591
+ this.artifact,
592
+ this.artifactHash,
593
+ );
594
+ }
595
+
596
+ toDict(): CandidateJSON {
597
+ return {
598
+ candidate_id: this.candidateId,
599
+ run_id: this.runId,
600
+ epoch: this.epoch,
601
+ candidate_index: this.candidateIndex,
602
+ candidate_seed: this.candidateSeed,
603
+ goal_hash: this.goalHash,
604
+ evaluator_hash: this.evaluatorHash,
605
+ genome: { ...this.genome },
606
+ persona: { ...this.persona },
607
+ path: { ...this.path },
608
+ schedule: this.schedule.map((w) => w.toDict()),
609
+ artifact: this.artifact,
610
+ producer_name: this.producerName,
611
+ producer_family: this.producerFamily,
612
+ parent_ids: [...this.parentIds],
613
+ mutation_rationale: this.mutationRationale,
614
+ artifact_hash: this.artifactHash,
615
+ };
616
+ }
617
+ }
618
+
619
+ export interface EvaluationReportInit {
620
+ candidateId: string;
621
+ evaluatorId: string;
622
+ evaluatorFamily: string;
623
+ evaluatorSpecHash: string;
624
+ metrics: Record<string, number>;
625
+ hardGates: Record<string, boolean>;
626
+ confidence: number;
627
+ evidence: readonly string[];
628
+ actionableInformation?: readonly string[];
629
+ anomalies?: readonly string[];
630
+ }
631
+
632
+ export class EvaluationReport {
633
+ readonly candidateId: string;
634
+ readonly evaluatorId: string;
635
+ readonly evaluatorFamily: string;
636
+ readonly evaluatorSpecHash: string;
637
+ readonly metrics: Record<string, number>;
638
+ readonly hardGates: Record<string, boolean>;
639
+ readonly confidence: number;
640
+ readonly evidence: readonly string[];
641
+ readonly actionableInformation: readonly string[];
642
+ readonly anomalies: readonly string[];
643
+
644
+ constructor(init: EvaluationReportInit) {
645
+ this.candidateId = init.candidateId;
646
+ this.evaluatorId = init.evaluatorId;
647
+ this.evaluatorFamily = init.evaluatorFamily;
648
+ this.evaluatorSpecHash = init.evaluatorSpecHash;
649
+ this.metrics = { ...init.metrics };
650
+ this.hardGates = { ...init.hardGates };
651
+ this.confidence = init.confidence;
652
+ this.evidence = init.evidence;
653
+ this.actionableInformation = init.actionableInformation ?? [];
654
+ this.anomalies = init.anomalies ?? [];
655
+ }
656
+
657
+ validate(candidateId: string, spec: EvaluatorSpec): void {
658
+ if (this.candidateId !== candidateId) throw new Error("Evaluator returned wrong candidate_id");
659
+ if (this.evaluatorSpecHash !== spec.contentHash) throw new Error("Evaluator used a different evaluator specification");
660
+
661
+ const missingMetrics = spec.metrics.filter((m) => !(m in this.metrics)).sort();
662
+ if (missingMetrics.length) throw new Error(`Evaluator omitted metrics: ${JSON.stringify(missingMetrics)}`);
663
+
664
+ const missingGates = spec.hardGates.filter((g) => !(g in this.hardGates)).sort();
665
+ if (missingGates.length) throw new Error(`Evaluator omitted hard gates: ${JSON.stringify(missingGates)}`);
666
+
667
+ for (const name of spec.metrics) {
668
+ const value = this.metrics[name];
669
+ if (value < 0 || value > 1) throw new Error(`Metric ${JSON.stringify(name)}=${value} outside [0,1]`);
670
+ }
671
+
672
+ if (this.confidence < 0 || this.confidence > 1) throw new Error("Evaluator confidence outside [0,1]");
673
+ }
674
+ }
675
+
676
+ export interface AggregateReportInit {
677
+ candidateId: string;
678
+ evaluatorSpecHash: string;
679
+ metrics: Record<string, number>;
680
+ metricSpread: Record<string, number>;
681
+ hardGates: Record<string, boolean>;
682
+ confidence: number;
683
+ evidence: readonly string[];
684
+ actionableInformation: readonly string[];
685
+ anomalies: readonly string[];
686
+ evaluatorIds: readonly string[];
687
+ errors: readonly string[];
688
+ verified: boolean;
689
+ reports: readonly EvaluationReport[];
690
+ }
691
+
692
+ export class AggregateReport {
693
+ readonly candidateId: string;
694
+ readonly evaluatorSpecHash: string;
695
+ readonly metrics: Record<string, number>;
696
+ readonly metricSpread: Record<string, number>;
697
+ readonly hardGates: Record<string, boolean>;
698
+ readonly confidence: number;
699
+ readonly evidence: readonly string[];
700
+ readonly actionableInformation: readonly string[];
701
+ readonly anomalies: readonly string[];
702
+ readonly evaluatorIds: readonly string[];
703
+ readonly errors: readonly string[];
704
+ readonly verified: boolean;
705
+ readonly reports: readonly EvaluationReport[];
706
+
707
+ constructor(init: AggregateReportInit) {
708
+ Object.assign(this, init);
709
+ this.candidateId = init.candidateId;
710
+ this.evaluatorSpecHash = init.evaluatorSpecHash;
711
+ this.metrics = { ...init.metrics };
712
+ this.metricSpread = { ...init.metricSpread };
713
+ this.hardGates = { ...init.hardGates };
714
+ this.confidence = init.confidence;
715
+ this.evidence = init.evidence;
716
+ this.actionableInformation = init.actionableInformation;
717
+ this.anomalies = init.anomalies;
718
+ this.evaluatorIds = init.evaluatorIds;
719
+ this.errors = init.errors;
720
+ this.verified = init.verified;
721
+ this.reports = init.reports;
722
+ }
723
+ }
724
+
725
+ // ═══════════════════════════════════════════════════════════════════════
726
+ // 4. External adapter contracts — verbatim port of §4
727
+ // ═══════════════════════════════════════════════════════════════════════
728
+ export interface ToolRegistryLike {
729
+ callTool(name: string, args: readonly string[]): Promise<{ stdout: string; stderr: string; exitCode: number }>;
730
+ }
731
+
732
+ export interface CandidateProducer {
733
+ name: string;
734
+ family: string;
735
+ produce(request: GenerationRequest, tools: ToolRegistryLike): Promise<string> | string;
736
+ }
737
+
738
+ export interface CandidateEvaluator {
739
+ name: string;
740
+ family: string;
741
+ spec: EvaluatorSpec;
742
+ evaluate(candidate: BlindCandidate, goal: GoalSpec, tools: ToolRegistryLike): Promise<EvaluationReport> | EvaluationReport;
743
+ }
744
+
745
+ export class FunctionProducer implements CandidateProducer {
746
+ constructor(
747
+ public readonly name: string,
748
+ public readonly family: string,
749
+ private readonly fn: (request: GenerationRequest, tools: ToolRegistryLike) => Promise<string> | string,
750
+ ) {}
751
+ produce(request: GenerationRequest, tools: ToolRegistryLike) {
752
+ return this.fn(request, tools);
753
+ }
754
+ }
755
+
756
+ export class FunctionEvaluator implements CandidateEvaluator {
757
+ constructor(
758
+ public readonly name: string,
759
+ public readonly family: string,
760
+ public readonly spec: EvaluatorSpec,
761
+ private readonly fn: (candidate: BlindCandidate, goal: GoalSpec, tools: ToolRegistryLike) => Promise<EvaluationReport> | EvaluationReport,
762
+ ) {}
763
+ evaluate(candidate: BlindCandidate, goal: GoalSpec, tools: ToolRegistryLike) {
764
+ return this.fn(candidate, goal, tools);
765
+ }
766
+ }
767
+
768
+ export interface ReviewDecision {
769
+ approved: boolean;
770
+ reference: string;
771
+ rationale: string;
772
+ }
773
+
774
+ export interface GoalProposer {
775
+ name: string;
776
+ propose(currentGoal: GoalSpec, epochTrace: readonly Record<string, unknown>[]): GoalSpec | null;
777
+ }
778
+
779
+ export interface GoalReviewer {
780
+ name: string;
781
+ review(currentGoal: GoalSpec, proposedGoal: GoalSpec): ReviewDecision;
782
+ }
783
+
784
+ export interface EvaluatorProposer {
785
+ name: string;
786
+ propose(
787
+ currentSpec: EvaluatorSpec,
788
+ epochTrace: readonly Record<string, unknown>[],
789
+ ): [EvaluatorSpec, readonly CandidateEvaluator[]] | null;
790
+ }
791
+
792
+ // ═══════════════════════════════════════════════════════════════════════
793
+ // 5. Goal and evaluator mutation policies — verbatim port of §5
794
+ // ═══════════════════════════════════════════════════════════════════════
795
+ export interface GoalMutationPolicyOptions {
796
+ minimumApprovals?: number;
797
+ requireHumanApproval?: boolean;
798
+ }
799
+
800
+ export class GoalMutationPolicy {
801
+ readonly minimumApprovals: number;
802
+ readonly requireHumanApproval: boolean;
803
+
804
+ constructor(options: GoalMutationPolicyOptions = {}) {
805
+ this.minimumApprovals = options.minimumApprovals ?? 1;
806
+ this.requireHumanApproval = options.requireHumanApproval ?? false;
807
+ }
808
+
809
+ validate(parent: GoalSpec, proposed: GoalSpec, atEpochBoundary: boolean): string[] {
810
+ const errors: string[] = [];
811
+
812
+ if (!atEpochBoundary) errors.push("Goal mutation attempted inside an epoch");
813
+ if (proposed.version !== parent.version + 1) errors.push("Goal version must increment exactly once");
814
+ if (proposed.parentHash !== parent.contentHash) errors.push("Goal parent_hash does not match current goal");
815
+ if (!proposed.rationale.trim()) errors.push("Goal mutation lacks rationale");
816
+
817
+ const parentConstraints = new Set(parent.hardConstraints);
818
+ const proposedConstraints = new Set(proposed.hardConstraints);
819
+ for (const c of parentConstraints) {
820
+ if (!proposedConstraints.has(c)) {
821
+ errors.push("Goal mutation removed a hard constraint");
822
+ break;
823
+ }
824
+ }
825
+
826
+ if (proposed.approvals.length < this.minimumApprovals) errors.push("Goal mutation lacks sufficient approvals");
827
+
828
+ if (this.requireHumanApproval && !proposed.approvals.some((a) => a.startsWith("human:"))) {
829
+ errors.push("High-stakes goal mutation lacks human approval");
830
+ }
831
+
832
+ try {
833
+ proposed.validate();
834
+ } catch (exc) {
835
+ errors.push(exc instanceof Error ? exc.message : String(exc));
836
+ }
837
+
838
+ return errors;
839
+ }
840
+ }
841
+
842
+ export interface CalibrationCase {
843
+ artifact: string;
844
+ expectedHardGates: Record<string, boolean>;
845
+ }
846
+
847
+ export async function calibrateEvaluator(
848
+ evaluator: CandidateEvaluator,
849
+ cases: readonly CalibrationCase[],
850
+ goal: GoalSpec,
851
+ tools: ToolRegistryLike,
852
+ ): Promise<number> {
853
+ if (cases.length === 0) throw new Error("Evaluator calibration requires at least one case");
854
+
855
+ let correct = 0;
856
+ let total = 0;
857
+
858
+ for (let index = 0; index < cases.length; index++) {
859
+ const testCase = cases[index];
860
+ const artifactHash = sha256Text(testCase.artifact);
861
+ const candidate = new BlindCandidate(
862
+ `calibration-${index}-${artifactHash.slice(0, 12)}`,
863
+ "calibration",
864
+ -1,
865
+ goal.contentHash,
866
+ evaluator.spec.contentHash,
867
+ seedToGenome(index),
868
+ testCase.artifact,
869
+ artifactHash,
870
+ );
871
+
872
+ const report = await evaluator.evaluate(candidate, goal, tools);
873
+ report.validate(candidate.candidateId, evaluator.spec);
874
+
875
+ for (const [gate, expected] of Object.entries(testCase.expectedHardGates)) {
876
+ if (!(gate in report.hardGates)) {
877
+ total += 1;
878
+ continue;
879
+ }
880
+ correct += report.hardGates[gate] === expected ? 1 : 0;
881
+ total += 1;
882
+ }
883
+ }
884
+
885
+ return correct / Math.max(1, total);
886
+ }
887
+
888
+ // ═══════════════════════════════════════════════════════════════════════
889
+ // 6. Budget accounting — verbatim port of §6
890
+ // ═══════════════════════════════════════════════════════════════════════
891
+ export class BudgetExceeded extends Error {}
892
+
893
+ export interface BudgetLimitsInit {
894
+ candidates?: number;
895
+ evaluatorCalls?: number;
896
+ toolCalls?: number;
897
+ worldActions?: number;
898
+ reportedTokens?: number;
899
+ }
900
+
901
+ export class BudgetLimits {
902
+ readonly candidates: number;
903
+ readonly evaluatorCalls: number;
904
+ readonly toolCalls: number;
905
+ readonly worldActions: number;
906
+ readonly reportedTokens: number;
907
+
908
+ constructor(init: BudgetLimitsInit = {}) {
909
+ this.candidates = init.candidates ?? 32;
910
+ this.evaluatorCalls = init.evaluatorCalls ?? 128;
911
+ this.toolCalls = init.toolCalls ?? 128;
912
+ this.worldActions = init.worldActions ?? 32;
913
+ this.reportedTokens = init.reportedTokens ?? 2_000_000;
914
+ }
915
+ }
916
+
917
+ type BudgetResource = "candidates" | "evaluatorCalls" | "toolCalls" | "worldActions" | "reportedTokens";
918
+
919
+ export class BudgetState {
920
+ candidates = 0;
921
+ evaluatorCalls = 0;
922
+ toolCalls = 0;
923
+ worldActions = 0;
924
+ reportedTokens = 0;
925
+
926
+ constructor(public readonly limits: BudgetLimits) {}
927
+
928
+ consume(resource: BudgetResource, amount = 1): void {
929
+ if (amount < 0) throw new Error("Budget consumption cannot be negative");
930
+ const validResources: BudgetResource[] = ["candidates", "evaluatorCalls", "toolCalls", "worldActions", "reportedTokens"];
931
+ if (!validResources.includes(resource)) throw new Error(`Unknown budget resource ${JSON.stringify(resource)}`);
932
+
933
+ const current = this[resource];
934
+ const limit = this.limits[resource];
935
+
936
+ if (current + amount > limit) {
937
+ throw new BudgetExceeded(`${resource} budget exceeded: ${current}+${amount}>${limit}`);
938
+ }
939
+
940
+ this[resource] = current + amount;
941
+ }
942
+
943
+ toDict(): Record<string, unknown> {
944
+ return {
945
+ limits: {
946
+ candidates: this.limits.candidates,
947
+ evaluator_calls: this.limits.evaluatorCalls,
948
+ tool_calls: this.limits.toolCalls,
949
+ world_actions: this.limits.worldActions,
950
+ reported_tokens: this.limits.reportedTokens,
951
+ },
952
+ candidates: this.candidates,
953
+ evaluator_calls: this.evaluatorCalls,
954
+ tool_calls: this.toolCalls,
955
+ world_actions: this.worldActions,
956
+ reported_tokens: this.reportedTokens,
957
+ };
958
+ }
959
+ }
960
+
961
+ // ═══════════════════════════════════════════════════════════════════════
962
+ // 7. Tamper-evident, hash-chained event/memory/checkpoint store
963
+ // ---------------------------------------------------------------------
964
+ // DISCLOSED ADAPTATION (see file header): the Python spec used SQLite,
965
+ // which does not exist in a browser runtime. The hash-chain ALGORITHM given
966
+ // in the legible parts of §7 (event_hash = sha256(canonical_json({run_id,
967
+ // created_utc, kind, payload_json, prev_hash})); verify_chain walks rows
968
+ // checking prev_hash continuity and re-deriving each hash) is reproduced
969
+ // exactly, over an in-memory array persisted to localStorage instead of a
970
+ // .sqlite file, so the tamper-evidence property is real and testable.
971
+ // ═══════════════════════════════════════════════════════════════════════
972
+ interface EventRow {
973
+ runId: string;
974
+ seq: number;
975
+ createdUtc: string;
976
+ kind: string;
977
+ payloadJson: string;
978
+ prevHash: string;
979
+ eventHash: string;
980
+ }
981
+
982
+ interface CheckpointRow {
983
+ runId: string;
984
+ name: string;
985
+ createdUtc: string;
986
+ eventSeq: number;
987
+ stateJson: string;
988
+ stateHash: string;
989
+ }
990
+
991
+ interface MemoryRow {
992
+ memoryId: string;
993
+ runId: string;
994
+ kind: string;
995
+ status: "open" | "resolved";
996
+ priority: number;
997
+ payloadJson: string;
998
+ createdSeq: number;
999
+ updatedSeq: number;
1000
+ }
1001
+
1002
+ interface RunRow {
1003
+ runId: string;
1004
+ createdUtc: string;
1005
+ seed: number;
1006
+ domain: string;
1007
+ risk: RiskTier;
1008
+ status: string;
1009
+ configJson: string;
1010
+ }
1011
+
1012
+ export class EventStore {
1013
+ private runs = new Map<string, RunRow>();
1014
+ private events: EventRow[] = [];
1015
+ private checkpoints: CheckpointRow[] = [];
1016
+ private memories: MemoryRow[] = [];
1017
+ private nextSeq = 1;
1018
+
1019
+ constructor(private readonly persistenceKey: string | null = null) {
1020
+ if (this.persistenceKey) this.loadFromStorage();
1021
+ }
1022
+
1023
+ private loadFromStorage(): void {
1024
+ try {
1025
+ const raw = typeof localStorage !== "undefined" ? localStorage.getItem(this.persistenceKey!) : null;
1026
+ if (!raw) return;
1027
+ const parsed = JSON.parse(raw);
1028
+ this.runs = new Map(parsed.runs ?? []);
1029
+ this.events = parsed.events ?? [];
1030
+ this.checkpoints = parsed.checkpoints ?? [];
1031
+ this.memories = parsed.memories ?? [];
1032
+ this.nextSeq = parsed.nextSeq ?? 1;
1033
+ } catch {
1034
+ /* corrupted or absent storage — start fresh, never crash */
1035
+ }
1036
+ }
1037
+
1038
+ private persist(): void {
1039
+ if (!this.persistenceKey || typeof localStorage === "undefined") return;
1040
+ try {
1041
+ localStorage.setItem(
1042
+ this.persistenceKey,
1043
+ JSON.stringify({
1044
+ runs: [...this.runs.entries()],
1045
+ events: this.events,
1046
+ checkpoints: this.checkpoints,
1047
+ memories: this.memories,
1048
+ nextSeq: this.nextSeq,
1049
+ }),
1050
+ );
1051
+ } catch {
1052
+ /* storage full/unavailable — the in-memory chain remains authoritative for this session */
1053
+ }
1054
+ }
1055
+
1056
+ createRun(runId: string, seed: number, domain: string, risk: RiskTier, config: Record<string, unknown>): void {
1057
+ this.runs.set(runId, {
1058
+ runId,
1059
+ createdUtc: utcNow(),
1060
+ seed,
1061
+ domain,
1062
+ risk,
1063
+ status: "running",
1064
+ configJson: canonicalJson(config),
1065
+ });
1066
+ this.appendEvent(runId, "run_created", { seed, domain, risk });
1067
+ }
1068
+
1069
+ setRunStatus(runId: string, status: string): void {
1070
+ const run = this.runs.get(runId);
1071
+ if (run) run.status = status;
1072
+ this.persist();
1073
+ }
1074
+
1075
+ /** Exact hash-chain material and algorithm from the legible part of §7. */
1076
+ appendEvent(runId: string, kind: string, payload: Record<string, unknown>): number {
1077
+ const payloadJson = canonicalJson(payload);
1078
+ const created = utcNow();
1079
+
1080
+ const priorForRun = this.events.filter((e) => e.runId === runId);
1081
+ const prevHash = priorForRun.length > 0 ? priorForRun[priorForRun.length - 1].eventHash : ZERO_HASH;
1082
+
1083
+ const material = canonicalJson({
1084
+ run_id: runId,
1085
+ created_utc: created,
1086
+ kind,
1087
+ payload_json: payloadJson,
1088
+ prev_hash: prevHash,
1089
+ });
1090
+ const eventHash = sha256Text(material);
1091
+
1092
+ const seq = this.nextSeq++;
1093
+ this.events.push({ runId, seq, createdUtc: created, kind, payloadJson, prevHash, eventHash });
1094
+ this.persist();
1095
+ return seq;
1096
+ }
1097
+
1098
+ /**
1099
+ * Protected accessor so V4+ subclasses can re-derive their own chains from
1100
+ * the REAL stored payloads (not just link continuity). Additive: nothing
1101
+ * that already existed is changed.
1102
+ */
1103
+ protected eventRowsForRun(runId: string): ReadonlyArray<{
1104
+ runId: string;
1105
+ seq: number;
1106
+ createdUtc: string;
1107
+ kind: string;
1108
+ payloadJson: string;
1109
+ prevHash: string;
1110
+ eventHash: string;
1111
+ }> {
1112
+ return this.events.filter((e) => e.runId === runId).sort((a, b) => a.seq - b.seq);
1113
+ }
1114
+
1115
+ /** Test-only tamper hook: mutates a stored payload so chain verifiers can be proven to detect it. */
1116
+ _tamperPayloadForTest(runId: string, kind: string, newPayloadJson: string): boolean {
1117
+ const row = this.events.find((e) => e.runId === runId && e.kind === kind);
1118
+ if (!row) return false;
1119
+ row.payloadJson = newPayloadJson;
1120
+ return true;
1121
+ }
1122
+
1123
+ verifyChain(runId: string): boolean {
1124
+ const rows = this.events.filter((e) => e.runId === runId).sort((a, b) => a.seq - b.seq);
1125
+ let expectedPrev = ZERO_HASH;
1126
+
1127
+ for (const row of rows) {
1128
+ if (row.prevHash !== expectedPrev) return false;
1129
+
1130
+ const material = canonicalJson({
1131
+ run_id: row.runId,
1132
+ created_utc: row.createdUtc,
1133
+ kind: row.kind,
1134
+ payload_json: row.payloadJson,
1135
+ prev_hash: row.prevHash,
1136
+ });
1137
+ if (sha256Text(material) !== row.eventHash) return false;
1138
+
1139
+ expectedPrev = row.eventHash;
1140
+ }
1141
+
1142
+ return true;
1143
+ }
1144
+
1145
+ saveCheckpoint(runId: string, name: string, state: Record<string, unknown>): string {
1146
+ const eventsForRun = this.events.filter((e) => e.runId === runId);
1147
+ const eventSeq = eventsForRun.length > 0 ? eventsForRun[eventsForRun.length - 1].seq : 0;
1148
+ const stateJson = canonicalJson(state);
1149
+ const stateHash = sha256Text(stateJson);
1150
+
1151
+ this.checkpoints = this.checkpoints.filter((c) => !(c.runId === runId && c.name === name));
1152
+ this.checkpoints.push({ runId, name, createdUtc: utcNow(), eventSeq, stateJson, stateHash });
1153
+
1154
+ this.appendEvent(runId, "checkpoint_saved", { name, event_seq: eventSeq, state_hash: stateHash });
1155
+ return stateHash;
1156
+ }
1157
+
1158
+ loadCheckpoint(runId: string, name: string): Record<string, unknown> {
1159
+ const row = this.checkpoints.find((c) => c.runId === runId && c.name === name);
1160
+ if (!row) throw new Error(`Checkpoint ${JSON.stringify(name)} does not exist`);
1161
+ if (sha256Text(row.stateJson) !== row.stateHash) throw new Error("Checkpoint hash mismatch");
1162
+ return JSON.parse(row.stateJson);
1163
+ }
1164
+
1165
+ /** Internal accessor used by MemoryLedger — kept private-by-convention (not exported). */
1166
+ _memories(): MemoryRow[] {
1167
+ return this.memories;
1168
+ }
1169
+ _addMemoryRow(row: MemoryRow): void {
1170
+ this.memories.push(row);
1171
+ this.persist();
1172
+ }
1173
+ _updateMemoryRow(memoryId: string, runId: string, payloadJson: string, updatedSeq: number): void {
1174
+ const row = this.memories.find((m) => m.memoryId === memoryId && m.runId === runId);
1175
+ if (row) {
1176
+ row.payloadJson = payloadJson;
1177
+ row.status = "resolved";
1178
+ row.updatedSeq = updatedSeq;
1179
+ }
1180
+ this.persist();
1181
+ }
1182
+ }
1183
+
1184
+ export class MemoryLedger {
1185
+ constructor(
1186
+ private readonly store: EventStore,
1187
+ private readonly runId: string,
1188
+ ) {}
1189
+
1190
+ add(kind: string, payload: Record<string, unknown>, priority: number): string {
1191
+ if (priority < 0 || priority > 1) throw new Error("Memory priority outside [0,1]");
1192
+
1193
+ const createdSeq = this.store.appendEvent(this.runId, "memory_added", { kind, priority, payload: { ...payload } });
1194
+
1195
+ const memoryId = sha256Text(
1196
+ canonicalJson({ run_id: this.runId, kind, payload, created_seq: createdSeq }),
1197
+ );
1198
+
1199
+ this.store._addMemoryRow({
1200
+ memoryId,
1201
+ runId: this.runId,
1202
+ kind,
1203
+ status: "open",
1204
+ priority,
1205
+ payloadJson: canonicalJson(payload),
1206
+ createdSeq,
1207
+ updatedSeq: createdSeq,
1208
+ });
1209
+
1210
+ return memoryId;
1211
+ }
1212
+
1213
+ resolve(memoryId: string, resolution: Record<string, unknown>): void {
1214
+ const seq = this.store.appendEvent(this.runId, "memory_resolved", { memory_id: memoryId, resolution: { ...resolution } });
1215
+
1216
+ const row = this.store._memories().find((m) => m.memoryId === memoryId && m.runId === this.runId);
1217
+ if (!row) throw new Error(memoryId);
1218
+
1219
+ const payload = JSON.parse(row.payloadJson);
1220
+ payload.resolution = { ...resolution };
1221
+
1222
+ this.store._updateMemoryRow(memoryId, this.runId, canonicalJson(payload), seq);
1223
+ }
1224
+
1225
+ listOpen(options: { kinds?: readonly string[]; limit?: number } = {}): Array<Record<string, unknown>> {
1226
+ const limit = options.limit ?? 10;
1227
+ if (limit < 1) return [];
1228
+
1229
+ let rows = this.store._memories().filter((m) => m.runId === this.runId && m.status === "open");
1230
+ if (options.kinds && options.kinds.length > 0) {
1231
+ const kindSet = new Set(options.kinds);
1232
+ rows = rows.filter((r) => kindSet.has(r.kind));
1233
+ }
1234
+
1235
+ rows = rows.sort((a, b) => b.priority - a.priority || a.createdSeq - b.createdSeq);
1236
+
1237
+ return rows.slice(0, limit).map((r) => ({
1238
+ memory_id: r.memoryId,
1239
+ kind: r.kind,
1240
+ priority: r.priority,
1241
+ payload: JSON.parse(r.payloadJson),
1242
+ }));
1243
+ }
1244
+ }
1245
+
1246
+ // ═══════════════════════════════════════════════════════════════════════
1247
+ // 8. Browser-safe tool registry
1248
+ // ---------------------------------------------------------------------
1249
+ // DISCLOSED ADAPTATION: the pasted spec's docstring says "Local subprocess
1250
+ // adapter" with security properties "shell=False, exact allowlist, fixed
1251
+ // working directory, timeout, bounded captured output" — but arbitrary
1252
+ // subprocess execution is categorically unavailable and unsafe inside a
1253
+ // Vite single-page browser bundle (there is no child_process, no shell, no
1254
+ // filesystem). Faithfully translating the STATED SECURITY PROPERTIES rather
1255
+ // than the impossible mechanism: this registry (a) never invokes a shell,
1256
+ // (b) only runs functions from a fixed, explicit allowlist supplied at
1257
+ // construction, (c) enforces a timeout via Promise.race, (d) truncates
1258
+ // captured output to a bounded byte length, and (e) is fully budget-gated
1259
+ // through BudgetState, exactly like the Python tool-call accounting.
1260
+ // ═══════════════════════════════════════════════════════════════════════
1261
+ export type ToolFunction = (args: readonly string[]) => Promise<string> | string;
1262
+
1263
+ export interface ToolRegistryOptions {
1264
+ timeoutMs?: number;
1265
+ maxOutputBytes?: number;
1266
+ }
1267
+
1268
+ export class ToolRegistry implements ToolRegistryLike {
1269
+ private readonly allowlist = new Map<string, ToolFunction>();
1270
+ private readonly timeoutMs: number;
1271
+ private readonly maxOutputBytes: number;
1272
+
1273
+ constructor(
1274
+ public readonly capabilityGate: CapabilityGate,
1275
+ private readonly budget: BudgetState,
1276
+ options: ToolRegistryOptions = {},
1277
+ ) {
1278
+ this.timeoutMs = options.timeoutMs ?? 5_000;
1279
+ this.maxOutputBytes = options.maxOutputBytes ?? 65_536;
1280
+ }
1281
+
1282
+ register(name: string, fn: ToolFunction): void {
1283
+ this.allowlist.set(name, fn);
1284
+ }
1285
+
1286
+ async callTool(name: string, args: readonly string[]): Promise<{ stdout: string; stderr: string; exitCode: number }> {
1287
+ this.budget.consume("toolCalls", 1);
1288
+
1289
+ const fn = this.allowlist.get(name);
1290
+ if (!fn) {
1291
+ return { stdout: "", stderr: `tool not in allowlist: ${JSON.stringify(name)}`, exitCode: 127 };
1292
+ }
1293
+
1294
+ try {
1295
+ const timeout = new Promise<never>((_, reject) => {
1296
+ setTimeout(() => reject(new Error(`tool ${name} timed out after ${this.timeoutMs}ms`)), this.timeoutMs);
1297
+ });
1298
+ const stdout = await Promise.race([Promise.resolve(fn(args)), timeout]);
1299
+ return { stdout: stdout.slice(0, this.maxOutputBytes), stderr: "", exitCode: 0 };
1300
+ } catch (error) {
1301
+ return { stdout: "", stderr: error instanceof Error ? error.message : String(error), exitCode: 1 };
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ // ═══════════════════════════════════════════════════════════════════════
1307
+ // 9. Seven-dimensional descriptor + versioned MAP-Elites archive
1308
+ // ---------------------------------------------------------------------
1309
+ // DISCLOSED: the docstrings survived ("Seven-dimensional descriptor based
1310
+ // on V1 discovery blocks", "MAP-Elites style archive with versioning
1311
+ // logic... Scores are never compared across materially different Goal or
1312
+ // Evaluator specifications (The Versioning Invariant)") but the method
1313
+ // bodies did not. Implemented in full below, functioning and non-mocked:
1314
+ // the descriptor buckets each of V1's 7 discovery blocks (Problem Choice,
1315
+ // Anomaly Valuation, Embodiment, Analogy, Evaluator Revision, Taste, Social
1316
+ // Stabilization) into a coarse decile via the mean of that block's genome
1317
+ // dimensions, and the archive enforces the Versioning Invariant by keying
1318
+ // every bucket on `${goalHash}:${evaluatorSpecHash}` so scores under a
1319
+ // mutated Goal or Evaluator can never silently overwrite or compare against
1320
+ // scores from a materially different specification.
1321
+ // ═══════════════════════════════════════════════════════════════════════
1322
+ export function sevenDimensionalDescriptor(genome: Genome): readonly number[] {
1323
+ return Object.keys(DIMENSION_BLOCKS).map((block) => {
1324
+ const ids = DIMENSION_BLOCKS[block];
1325
+ const mean = ids.reduce((sum, id) => sum + (genome[id] ?? 0), 0) / Math.max(1, ids.length);
1326
+ return Math.floor(clamp01(mean) * 10); // decile bucket: 0-10
1327
+ });
1328
+ }
1329
+
1330
+ export interface ArchiveEntry {
1331
+ candidate: Candidate;
1332
+ report: AggregateReport;
1333
+ descriptor: readonly number[];
1334
+ }
1335
+
1336
+ function scoreOf(report: AggregateReport): number {
1337
+ const values = Object.values(report.metrics);
1338
+ return values.length ? values.reduce((a, b) => a + b, 0) / values.length : 0;
1339
+ }
1340
+
1341
+ export class VersionedArchive {
1342
+ readonly buckets = new Map<string, Map<string, ArchiveEntry>>();
1343
+
1344
+ private contextKey(goalHash: string, evaluatorSpecHash: string): string {
1345
+ return `${goalHash}:${evaluatorSpecHash}`;
1346
+ }
1347
+
1348
+ private cellKey(descriptor: readonly number[]): string {
1349
+ return descriptor.join(".");
1350
+ }
1351
+
1352
+ /** The Versioning Invariant: a candidate can only ever be compared to prior entries under the SAME (goalHash, evaluatorSpecHash) context. */
1353
+ add(candidate: Candidate, report: AggregateReport): boolean {
1354
+ const ctxKey = this.contextKey(candidate.goalHash, report.evaluatorSpecHash);
1355
+ if (!this.buckets.has(ctxKey)) this.buckets.set(ctxKey, new Map());
1356
+ const bucket = this.buckets.get(ctxKey)!;
1357
+
1358
+ const descriptor = sevenDimensionalDescriptor(candidate.genome);
1359
+ const cellKey = this.cellKey(descriptor);
1360
+ const existing = bucket.get(cellKey);
1361
+
1362
+ if (!existing || scoreOf(report) > scoreOf(existing.report)) {
1363
+ bucket.set(cellKey, { candidate, report, descriptor });
1364
+ return true;
1365
+ }
1366
+ return false;
1367
+ }
1368
+
1369
+ getBest(ctxKey: string): ArchiveEntry | null {
1370
+ const bucket = this.buckets.get(ctxKey);
1371
+ if (!bucket || bucket.size === 0) return null;
1372
+ let best: ArchiveEntry | null = null;
1373
+ for (const entry of bucket.values()) {
1374
+ if (!best || scoreOf(entry.report) > scoreOf(best.report)) best = entry;
1375
+ }
1376
+ return best;
1377
+ }
1378
+
1379
+ size(ctxKey: string): number {
1380
+ return this.buckets.get(ctxKey)?.size ?? 0;
1381
+ }
1382
+
1383
+ /** Retains temporarily inferior stepping stones (DGM open-ended branching): returns ALL entries in the context, not only the elite. */
1384
+ allEntries(ctxKey: string): ArchiveEntry[] {
1385
+ return [...(this.buckets.get(ctxKey)?.values() ?? [])];
1386
+ }
1387
+ }
1388
+
1389
+ // ═══════════════════════════════════════════════════════════════════════
1390
+ // 10. Structural-diversity monitor
1391
+ // ---------------------------------------------------------------------
1392
+ // Motivated by the file's own design rationale: "Structural-diversity
1393
+ // monitoring, because repeated LLM mutation can converge into narrow
1394
+ // structural attractors." No body was supplied for this in the truncated
1395
+ // spec; implemented here as a real, testable metric: mean pairwise
1396
+ // Euclidean distance across the 21-dimension genome vectors of an epoch's
1397
+ // candidates, flagged narrow if below a fixed threshold.
1398
+ // ═══════════════════════════════════════════════════════════════════════
1399
+ export interface DiversityReport {
1400
+ meanPairwiseDistance: number;
1401
+ narrowAttractor: boolean;
1402
+ populationSize: number;
1403
+ }
1404
+
1405
+ const NARROW_ATTRACTOR_THRESHOLD = 0.35;
1406
+
1407
+ export function assessStructuralDiversity(genomes: readonly Genome[]): DiversityReport {
1408
+ if (genomes.length < 2) {
1409
+ return { meanPairwiseDistance: 1, narrowAttractor: false, populationSize: genomes.length };
1410
+ }
1411
+
1412
+ const ids = dimensionIds();
1413
+ const vectors = genomes.map((g) => ids.map((id) => g[id] ?? 0));
1414
+
1415
+ let sum = 0;
1416
+ let count = 0;
1417
+ for (let i = 0; i < vectors.length; i++) {
1418
+ for (let j = i + 1; j < vectors.length; j++) {
1419
+ let squared = 0;
1420
+ for (let k = 0; k < ids.length; k++) squared += (vectors[i][k] - vectors[j][k]) ** 2;
1421
+ sum += Math.sqrt(squared);
1422
+ count += 1;
1423
+ }
1424
+ }
1425
+
1426
+ const meanDistance = count > 0 ? sum / count : 0;
1427
+ return {
1428
+ meanPairwiseDistance: Math.round(meanDistance * 10000) / 10000,
1429
+ narrowAttractor: meanDistance < NARROW_ATTRACTOR_THRESHOLD,
1430
+ populationSize: genomes.length,
1431
+ };
1432
+ }
1433
+
1434
+ // ═══════════════════════════════════════════════════════════════════════
1435
+ // 11. GEPA-style textual-feedback mutation engine
1436
+ // ---------------------------------------------------------------------
1437
+ // Design rationale from the file header: "Trajectory feedback and textual
1438
+ // diagnostic information, rather than scalar-only optimization, following
1439
+ // GEPA." Implemented here as real logic: scans an AggregateReport's
1440
+ // `actionableInformation` and `anomalies` strings for keywords naming a V1
1441
+ // discovery block (e.g. "evaluator", "anomaly", "taste"), and nudges every
1442
+ // dimension in that block toward its high pole using V2's real
1443
+ // `applyMutation("nudge", ...)` operator — never a scalar-only step.
1444
+ // ═══════════════════════════════════════════════════════════════════════
1445
+ const BLOCK_KEYWORDS: Readonly<Record<string, string>> = {
1446
+ "Problem Choice": "problem",
1447
+ "Anomaly Valuation": "anomaly",
1448
+ Embodiment: "world",
1449
+ Analogy: "analog",
1450
+ "Evaluator Revision": "evaluator",
1451
+ Taste: "taste",
1452
+ "Social Stabilization": "social",
1453
+ };
1454
+
1455
+ export function nudgeGenomeFromFeedback(
1456
+ genome: Genome,
1457
+ report: AggregateReport,
1458
+ parentSeed: number,
1459
+ operationIndex = 0,
1460
+ ): Genome {
1461
+ const feedbackText = [...report.actionableInformation, ...report.anomalies].join(" ").toLowerCase();
1462
+
1463
+ const targetedBlocks = Object.entries(BLOCK_KEYWORDS)
1464
+ .filter(([, keyword]) => feedbackText.includes(keyword))
1465
+ .map(([block]) => block);
1466
+
1467
+ if (targetedBlocks.length === 0) {
1468
+ return applyMutation(genome, parentSeed, "nudge", operationIndex);
1469
+ }
1470
+
1471
+ let mutated = { ...genome };
1472
+ for (const block of targetedBlocks) {
1473
+ const ids = DIMENSION_BLOCKS[block] ?? [];
1474
+ for (const id of ids) {
1475
+ mutated[id] = clamp01((mutated[id] ?? 0.5) + 0.1);
1476
+ }
1477
+ }
1478
+ return mutated;
1479
+ }
1480
+
1481
+ // ═══════════════════════════════════════════════════════════════════════
1482
+ // 12. Evaluation committee — committee aggregation, quorum, co-evolution
1483
+ // only at epoch boundaries
1484
+ // ═══════════════════════════════════════════════════════════════════════
1485
+ export interface CommitteePolicyOptions {
1486
+ quorum?: number;
1487
+ }
1488
+
1489
+ export class CommitteePolicy {
1490
+ readonly quorum: number;
1491
+ constructor(options: CommitteePolicyOptions = {}) {
1492
+ this.quorum = options.quorum ?? 1;
1493
+ }
1494
+ }
1495
+
1496
+ export class EvaluationCommittee {
1497
+ constructor(
1498
+ public readonly evaluators: readonly CandidateEvaluator[],
1499
+ public readonly policy: CommitteePolicy,
1500
+ ) {}
1501
+
1502
+ get spec(): EvaluatorSpec {
1503
+ return this.evaluators[0].spec;
1504
+ }
1505
+
1506
+ async evaluate(candidate: BlindCandidate, goal: GoalSpec, tools: ToolRegistryLike, budget: BudgetState): Promise<AggregateReport> {
1507
+ const reports: EvaluationReport[] = [];
1508
+ const errors: string[] = [];
1509
+
1510
+ for (const evaluator of this.evaluators) {
1511
+ try {
1512
+ budget.consume("evaluatorCalls", 1);
1513
+ const report = await evaluator.evaluate(candidate, goal, tools);
1514
+ report.validate(candidate.candidateId, evaluator.spec);
1515
+ reports.push(report);
1516
+ } catch (error) {
1517
+ errors.push(`${evaluator.name}: ${error instanceof Error ? error.message : String(error)}`);
1518
+ }
1519
+ }
1520
+
1521
+ const spec = this.spec;
1522
+ const metrics: Record<string, number> = {};
1523
+ const metricSpread: Record<string, number> = {};
1524
+
1525
+ for (const metric of spec.metrics) {
1526
+ const values = reports.map((r) => r.metrics[metric]).filter((v) => typeof v === "number");
1527
+ metrics[metric] = values.length ? values.reduce((a, b) => a + b, 0) / values.length : 0;
1528
+ metricSpread[metric] = values.length ? Math.max(...values) - Math.min(...values) : 0;
1529
+ }
1530
+
1531
+ // Hard-gate aggregation rule (this module's own, disclosed): a gate
1532
+ // passes for the committee only if EVERY reporting evaluator marks it
1533
+ // true — evaluator-family separation must not let one lenient evaluator
1534
+ // paper over another's rejection.
1535
+ const hardGates: Record<string, boolean> = {};
1536
+ for (const gate of spec.hardGates) {
1537
+ hardGates[gate] = reports.length > 0 && reports.every((r) => r.hardGates[gate] === true);
1538
+ }
1539
+
1540
+ const confidence = reports.length ? reports.reduce((a, r) => a + r.confidence, 0) / reports.length : 0;
1541
+ const verified = reports.length >= this.policy.quorum && errors.length === 0 && Object.values(hardGates).every(Boolean);
1542
+
1543
+ return new AggregateReport({
1544
+ candidateId: candidate.candidateId,
1545
+ evaluatorSpecHash: spec.contentHash,
1546
+ metrics,
1547
+ metricSpread,
1548
+ hardGates,
1549
+ confidence,
1550
+ evidence: reports.flatMap((r) => r.evidence),
1551
+ actionableInformation: reports.flatMap((r) => r.actionableInformation),
1552
+ anomalies: reports.flatMap((r) => r.anomalies),
1553
+ evaluatorIds: reports.map((r) => r.evaluatorId),
1554
+ errors,
1555
+ verified,
1556
+ reports,
1557
+ });
1558
+ }
1559
+ }
1560
+
1561
+ // ═══════════════════════════════════════════════════════════════════════
1562
+ // 13. Discovery engine — "High-horizon orchestrator enforcing the
1563
+ // Hashimoto-Fowler Harness Thesis" (docstring survived; body did not).
1564
+ // Implemented in full below as the described P/A/E/N/V/T/S-scheduled,
1565
+ // goal-versioned, budget-accounted, tamper-evident-logged epoch runner.
1566
+ // ═══════════════════════════════════════════════════════════════════════
1567
+ export interface DiscoveryEngineInit {
1568
+ runId: string;
1569
+ seed: number;
1570
+ domain: string;
1571
+ goal: GoalSpec;
1572
+ producers: readonly CandidateProducer[];
1573
+ committee: EvaluationCommittee;
1574
+ tools: ToolRegistryLike;
1575
+ store: EventStore;
1576
+ budget: BudgetState;
1577
+ risk?: RiskTier;
1578
+ }
1579
+
1580
+ export class DiscoveryEngine {
1581
+ readonly runId: string;
1582
+ readonly seed: number;
1583
+ readonly domain: string;
1584
+ goal: GoalSpec;
1585
+ readonly producers: readonly CandidateProducer[];
1586
+ readonly committee: EvaluationCommittee;
1587
+ readonly tools: ToolRegistryLike;
1588
+ readonly store: EventStore;
1589
+ readonly budget: BudgetState;
1590
+ readonly risk: RiskTier;
1591
+ readonly archive = new VersionedArchive();
1592
+ readonly memory: MemoryLedger;
1593
+
1594
+ private epochTrace: Array<Record<string, unknown>> = [];
1595
+
1596
+ constructor(init: DiscoveryEngineInit) {
1597
+ this.runId = init.runId;
1598
+ this.seed = init.seed;
1599
+ this.domain = init.domain;
1600
+ this.goal = init.goal;
1601
+ this.producers = init.producers;
1602
+ this.committee = init.committee;
1603
+ this.tools = init.tools;
1604
+ this.store = init.store;
1605
+ this.budget = init.budget;
1606
+ this.risk = init.risk ?? "medium";
1607
+ this.memory = new MemoryLedger(this.store, this.runId);
1608
+
1609
+ this.goal.validate();
1610
+ this.store.createRun(this.runId, this.seed, this.domain, this.risk, {
1611
+ goal_hash: this.goal.contentHash,
1612
+ evaluator_spec_hash: this.committee.spec.contentHash,
1613
+ });
1614
+ }
1615
+
1616
+ /** Runs one epoch: generates n candidates, evaluates each through the committee, updates the versioned archive, and enforces budget + safety gates throughout. Mirrors the Python CLI's `engine.run_epoch(epoch=1, n_candidates=2)`. */
1617
+ async runEpoch(epoch: number, nCandidates: number): Promise<Array<{ candidate: Candidate; report: AggregateReport }>> {
1618
+ if (nCandidates < 1) throw new Error("nCandidates must be >= 1");
1619
+
1620
+ const domainPack: DomainPack = DOMAIN_PACKS[this.domain] ?? DOMAIN_PACKS.general;
1621
+ const safetyGate = new SafetyGate(this.risk, domainPack);
1622
+
1623
+ const results: Array<{ candidate: Candidate; report: AggregateReport }> = [];
1624
+ const epochGenomes: Genome[] = [];
1625
+
1626
+ for (let index = 0; index < nCandidates; index++) {
1627
+ this.budget.consume("candidates", 1);
1628
+
1629
+ const candidateSeed = deriveSeed(this.runId, epoch, index, this.seed);
1630
+ let genome = seedToGenome(candidateSeed);
1631
+ genome = safetyGate.transformGenome(genome);
1632
+ epochGenomes.push(genome);
1633
+
1634
+ const persona = classifyPersonaExtended(genome);
1635
+ const path = selectPathExtended(genome);
1636
+ const schedule = new GraphLifeScheduler(candidateSeed, genome, path.id).build();
1637
+
1638
+ const promptBase = compileInnovationPrompt(genome, persona, path, this.goal.statement, this.domain);
1639
+ const prompt = promptBase + safetyGate.promptAddendum();
1640
+
1641
+ const request: GenerationRequest = {
1642
+ runId: this.runId,
1643
+ epoch,
1644
+ candidateIndex: index,
1645
+ candidateSeed,
1646
+ goal: this.goal,
1647
+ evaluatorSpec: this.committee.spec,
1648
+ genome,
1649
+ persona,
1650
+ path,
1651
+ schedule,
1652
+ prompt,
1653
+ };
1654
+
1655
+ this.store.appendEvent(this.runId, "candidate_requested", {
1656
+ epoch,
1657
+ candidate_index: index,
1658
+ candidate_seed: candidateSeed,
1659
+ persona: persona.name,
1660
+ path: path.id,
1661
+ });
1662
+
1663
+ const producer = this.producers[index % this.producers.length];
1664
+ const artifact = await producer.produce(request, this.tools);
1665
+ const artifactHash = sha256Text(artifact);
1666
+ const candidateId = sha256Text(canonicalJson({ runId: this.runId, epoch, index, artifactHash })).slice(0, 24);
1667
+
1668
+ const candidate = new Candidate(
1669
+ candidateId,
1670
+ this.runId,
1671
+ epoch,
1672
+ index,
1673
+ candidateSeed,
1674
+ this.goal.contentHash,
1675
+ this.committee.spec.contentHash,
1676
+ genome,
1677
+ persona,
1678
+ path,
1679
+ schedule,
1680
+ artifact,
1681
+ producer.name,
1682
+ producer.family,
1683
+ [],
1684
+ "initial generation",
1685
+ artifactHash,
1686
+ );
1687
+
1688
+ this.store.appendEvent(this.runId, "candidate_generated", { candidate_id: candidateId, artifact_hash: artifactHash });
1689
+
1690
+ const report = await this.committee.evaluate(candidate.blind(), this.goal, this.tools, this.budget);
1691
+
1692
+ this.store.appendEvent(this.runId, "candidate_evaluated", {
1693
+ candidate_id: candidateId,
1694
+ verified: report.verified,
1695
+ metrics: report.metrics,
1696
+ });
1697
+
1698
+ this.archive.add(candidate, report);
1699
+ results.push({ candidate, report });
1700
+ }
1701
+
1702
+ const diversity = assessStructuralDiversity(epochGenomes);
1703
+ this.store.appendEvent(this.runId, "epoch_completed", {
1704
+ epoch,
1705
+ n_candidates: nCandidates,
1706
+ mean_pairwise_distance: diversity.meanPairwiseDistance,
1707
+ narrow_attractor: diversity.narrowAttractor,
1708
+ });
1709
+
1710
+ this.epochTrace.push({
1711
+ epoch,
1712
+ n_candidates: nCandidates,
1713
+ results: results.map((r) => ({ candidate_id: r.candidate.candidateId, verified: r.report.verified })),
1714
+ diversity,
1715
+ });
1716
+
1717
+ return results;
1718
+ }
1719
+
1720
+ getEpochTrace(): readonly Record<string, unknown>[] {
1721
+ return this.epochTrace;
1722
+ }
1723
+ }
1724
+
1725
+ // ═══════════════════════════════════════════════════════════════════════
1726
+ // 14. Final verifiable receipt — port of `generate_v3_report`
1727
+ // ═══════════════════════════════════════════════════════════════════════
1728
+ export interface V3Report {
1729
+ sys: { version: string; status: string };
1730
+ run_id: string;
1731
+ goal: Record<string, unknown>;
1732
+ evaluator_spec: Record<string, unknown>;
1733
+ budget: Record<string, unknown>;
1734
+ archive_size: number;
1735
+ tamper_evident_seal: boolean;
1736
+ best_candidate?: {
1737
+ id: string;
1738
+ metrics: Record<string, number>;
1739
+ verified: boolean;
1740
+ artifact_preview: string;
1741
+ };
1742
+ }
1743
+
1744
+ export function generateV3Report(engine: DiscoveryEngine): V3Report {
1745
+ const ctxKey = `${engine.goal.contentHash}:${engine.committee.spec.contentHash}`;
1746
+ const bestEntry = engine.archive.getBest(ctxKey);
1747
+
1748
+ const report: V3Report = {
1749
+ sys: { version: "v3.1-OMEGA", status: "TERMINAL_SATURATION" },
1750
+ run_id: engine.runId,
1751
+ goal: {
1752
+ version: engine.goal.version,
1753
+ statement: engine.goal.statement,
1754
+ success_criteria: engine.goal.successCriteria,
1755
+ hard_constraints: engine.goal.hardConstraints,
1756
+ soft_objectives: engine.goal.softObjectives,
1757
+ parent_hash: engine.goal.parentHash,
1758
+ rationale: engine.goal.rationale,
1759
+ approvals: engine.goal.approvals,
1760
+ },
1761
+ evaluator_spec: {
1762
+ version: engine.committee.spec.version,
1763
+ metrics: engine.committee.spec.metrics,
1764
+ hard_gates: engine.committee.spec.hardGates,
1765
+ parent_hash: engine.committee.spec.parentHash,
1766
+ rationale: engine.committee.spec.rationale,
1767
+ },
1768
+ budget: engine.budget.toDict(),
1769
+ archive_size: engine.archive.size(ctxKey),
1770
+ tamper_evident_seal: engine.store.verifyChain(engine.runId),
1771
+ };
1772
+
1773
+ if (bestEntry) {
1774
+ report.best_candidate = {
1775
+ id: bestEntry.candidate.candidateId,
1776
+ metrics: bestEntry.report.metrics,
1777
+ verified: bestEntry.report.verified,
1778
+ artifact_preview: `${bestEntry.candidate.artifact.slice(0, 200)}...`,
1779
+ };
1780
+ }
1781
+
1782
+ return report;
1783
+ }
1784
+
1785
+ // ═══════════════════════════════════════════════════════════════════════
1786
+ // 15. CLI equivalent — port of `main()`. There is no argparse/stdout in a
1787
+ // browser; this exported async function performs EXACTLY the same
1788
+ // construction sequence and returns the same report `main()` prints.
1789
+ // ═══════════════════════════════════════════════════════════════════════
1790
+ export interface V3DemoOptions {
1791
+ problem: string;
1792
+ domain?: string;
1793
+ seed?: number;
1794
+ }
1795
+
1796
+ export async function runInnovationGenomeV3Demo(options: V3DemoOptions): Promise<V3Report> {
1797
+ const domain = options.domain ?? "mathematics";
1798
+ const seed = options.seed ?? Math.floor(Date.now() / 1000);
1799
+
1800
+ const goal = new GoalSpec({
1801
+ version: 1,
1802
+ statement: options.problem,
1803
+ successCriteria: ["Proof survives committee audit"],
1804
+ hardConstraints: ["Exact constants must be re-derived"],
1805
+ });
1806
+
1807
+ const spec = new EvaluatorSpec({ version: 1 });
1808
+
1809
+ const producer = new FunctionProducer("BaseLLM", "GPT", (request) => `Solved ${request.goal.statement} via ${request.path.id}`);
1810
+
1811
+ const evaluator = new FunctionEvaluator("StaticAudit", "Audit", spec, (candidate) =>
1812
+ new EvaluationReport({
1813
+ candidateId: candidate.candidateId,
1814
+ evaluatorId: "StaticAudit",
1815
+ evaluatorFamily: "Audit",
1816
+ evaluatorSpecHash: spec.contentHash,
1817
+ metrics: Object.fromEntries(spec.metrics.map((m) => [m, 0.8])),
1818
+ hardGates: Object.fromEntries(spec.hardGates.map((g) => [g, true])),
1819
+ confidence: 0.9,
1820
+ evidence: ["Evidence A"],
1821
+ }),
1822
+ );
1823
+
1824
+ const store = new EventStore();
1825
+ const budget = new BudgetState(new BudgetLimits());
1826
+ const registry = new ToolRegistry(new CapabilityGate(), budget);
1827
+ const committee = new EvaluationCommittee([evaluator], new CommitteePolicy({ quorum: 1 }));
1828
+
1829
+ const runId = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : sha256Text(String(Math.random()));
1830
+
1831
+ const engine = new DiscoveryEngine({
1832
+ runId,
1833
+ seed,
1834
+ domain,
1835
+ goal,
1836
+ producers: [producer],
1837
+ committee,
1838
+ tools: registry,
1839
+ store,
1840
+ budget,
1841
+ });
1842
+
1843
+ await engine.runEpoch(1, 2);
1844
+
1845
+ return generateV3Report(engine);
1846
+ }
1847
+
1848
+ // ═══════════════════════════════════════════════════════════════════════
1849
+ // 16. Diagnostics — the original test_innovation_genome_v3.py content was
1850
+ // never supplied in the task prompt (only its filename appeared in the
1851
+ // file tree), so it could not be ported. This suite independently
1852
+ // verifies every contract that IS legible in the spec, plus the SHA-256
1853
+ // implementation against the two published NIST test vectors.
1854
+ // ═══════════════════════════════════════════════════════════════════════
1855
+ export interface DiagnosticCheck {
1856
+ id: string;
1857
+ passed: boolean;
1858
+ detail: string;
1859
+ }
1860
+
1861
+ export async function runInnovationGenomeV3Diagnostics(): Promise<{ ok: boolean; checks: DiagnosticCheck[] }> {
1862
+ const checks: DiagnosticCheck[] = [];
1863
+ const add = (id: string, passed: boolean, detail: string) => checks.push({ id, passed, detail });
1864
+
1865
+ // SHA-256 against NIST test vectors (real cryptographic verification, no network needed).
1866
+ add("sha256-empty-string", sha256Text("") === "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "FIPS 180-4 vector");
1867
+ add("sha256-abc", sha256Text("abc") === "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "FIPS 180-4 vector");
1868
+
1869
+ // Genome validation.
1870
+ const genome = seedToGenome(42);
1871
+ try { validateGenome(genome); add("validate-genome-ok", true, "no throw on valid genome"); }
1872
+ catch { add("validate-genome-ok", false, "unexpected throw"); }
1873
+
1874
+ try {
1875
+ validateGenome({ ...genome, extra_dim: 0.5 });
1876
+ add("validate-genome-rejects-extra", false, "did not throw");
1877
+ } catch (e) {
1878
+ add("validate-genome-rejects-extra", e instanceof Error && e.message.includes("unknown dimensions"), String(e));
1879
+ }
1880
+
1881
+ // GoalSpec / EvaluatorSpec hashing determinism + validation.
1882
+ const goal = new GoalSpec({ version: 1, statement: "Prove X", successCriteria: ["c1"], hardConstraints: ["h1"] });
1883
+ const goal2 = new GoalSpec({ version: 1, statement: "Prove X", successCriteria: ["c1"], hardConstraints: ["h1"] });
1884
+ add("goal-hash-deterministic", goal.contentHash === goal2.contentHash, goal.contentHash);
1885
+ try { new GoalSpec({ version: 0, statement: "x", successCriteria: ["c"], hardConstraints: ["h"] }).validate(); add("goal-rejects-version-0", false, "no throw"); }
1886
+ catch { add("goal-rejects-version-0", true, "threw as expected"); }
1887
+
1888
+ const spec = new EvaluatorSpec({ version: 1 });
1889
+ try { spec.validate(); add("evaluator-spec-valid", true, "no throw"); }
1890
+ catch { add("evaluator-spec-valid", false, "unexpected throw"); }
1891
+
1892
+ // GraphLifeScheduler determinism + primary-path coverage guarantee.
1893
+ const scheduler1 = new GraphLifeScheduler(42, genome, "α");
1894
+ const scheduler2 = new GraphLifeScheduler(42, genome, "α");
1895
+ const waves1 = scheduler1.build();
1896
+ const waves2 = scheduler2.build();
1897
+ add("graph-life-deterministic", JSON.stringify(waves1.map((w) => w.toDict())) === JSON.stringify(waves2.map((w) => w.toDict())), `waves=${waves1.length}`);
1898
+
1899
+ const visitedNodes = new Set(waves1.flatMap((w) => w.nodes));
1900
+ const coversPrimary = PATH_NODES["α"].every((n) => visitedNodes.has(n));
1901
+ add("graph-life-covers-primary-path", coversPrimary, `visited=${[...visitedNodes].join(",")}`);
1902
+
1903
+ // GoalMutationPolicy.
1904
+ const policy = new GoalMutationPolicy();
1905
+ const proposedGoal = new GoalSpec({
1906
+ version: 2,
1907
+ statement: "Prove X, extended",
1908
+ successCriteria: ["c1"],
1909
+ hardConstraints: ["h1"],
1910
+ parentHash: goal.contentHash,
1911
+ rationale: "extend scope",
1912
+ approvals: ["reviewer:alice"],
1913
+ });
1914
+ const errors = policy.validate(goal, proposedGoal, true);
1915
+ add("goal-mutation-policy-accepts-valid", errors.length === 0, JSON.stringify(errors));
1916
+
1917
+ const badProposedGoal = new GoalSpec({
1918
+ version: 2,
1919
+ statement: "Prove X, extended",
1920
+ successCriteria: ["c1"],
1921
+ hardConstraints: [], // removed the hard constraint
1922
+ parentHash: goal.contentHash,
1923
+ rationale: "extend scope",
1924
+ approvals: ["reviewer:alice"],
1925
+ });
1926
+ const errors2 = policy.validate(goal, badProposedGoal, true);
1927
+ add("goal-mutation-policy-rejects-constraint-removal", errors2.some((e) => e.includes("hard constraint") || e.includes("must contain")), JSON.stringify(errors2));
1928
+
1929
+ // Budget accounting.
1930
+ const budget = new BudgetState(new BudgetLimits({ candidates: 2 }));
1931
+ budget.consume("candidates", 2);
1932
+ let budgetThrew = false;
1933
+ try { budget.consume("candidates", 1); } catch (e) { budgetThrew = e instanceof BudgetExceeded; }
1934
+ add("budget-exceeded-throws", budgetThrew, "BudgetExceeded raised at limit");
1935
+
1936
+ // EventStore hash chain.
1937
+ const store = new EventStore();
1938
+ store.createRun("test-run", 1, "general", "low", {});
1939
+ store.appendEvent("test-run", "custom_event", { a: 1 });
1940
+ store.appendEvent("test-run", "custom_event", { a: 2 });
1941
+ add("event-store-chain-verifies", store.verifyChain("test-run"), "3 events (run_created + 2 custom)");
1942
+
1943
+ // Checkpoint round-trip.
1944
+ const stateHash = store.saveCheckpoint("test-run", "cp1", { value: 42 });
1945
+ const loaded = store.loadCheckpoint("test-run", "cp1");
1946
+ add("checkpoint-roundtrip", (loaded as { value: number }).value === 42 && typeof stateHash === "string", stateHash);
1947
+
1948
+ // MemoryLedger.
1949
+ const memory = new MemoryLedger(store, "test-run");
1950
+ const memId = memory.add("insight", { text: "found a pattern" }, 0.8);
1951
+ add("memory-open-lists", memory.listOpen().some((m) => m.memory_id === memId), memId);
1952
+ memory.resolve(memId, { outcome: "confirmed" });
1953
+ add("memory-resolved-removed-from-open", !memory.listOpen().some((m) => m.memory_id === memId), "resolved");
1954
+
1955
+ // Calibration.
1956
+ const calibrationEvaluator = new FunctionEvaluator("Cal", "CalFam", spec, (candidate) =>
1957
+ new EvaluationReport({
1958
+ candidateId: candidate.candidateId,
1959
+ evaluatorId: "Cal",
1960
+ evaluatorFamily: "CalFam",
1961
+ evaluatorSpecHash: spec.contentHash,
1962
+ metrics: Object.fromEntries(spec.metrics.map((m) => [m, 0.5])),
1963
+ hardGates: Object.fromEntries(spec.hardGates.map((g) => [g, true])),
1964
+ confidence: 0.7,
1965
+ evidence: [],
1966
+ }),
1967
+ );
1968
+ const dummyTools: ToolRegistryLike = { callTool: async () => ({ stdout: "", stderr: "", exitCode: 0 }) };
1969
+ const calibrationScore = await calibrateEvaluator(
1970
+ calibrationEvaluator,
1971
+ [{ artifact: "artifact-1", expectedHardGates: { correctness: true } }],
1972
+ goal,
1973
+ dummyTools,
1974
+ );
1975
+ add("calibration-score-in-range", calibrationScore >= 0 && calibrationScore <= 1, String(calibrationScore));
1976
+
1977
+ // Versioned archive invariant: different goal hash must not share a bucket.
1978
+ const archive = new VersionedArchive();
1979
+ const dummyReport = new AggregateReport({
1980
+ candidateId: "c1",
1981
+ evaluatorSpecHash: spec.contentHash,
1982
+ metrics: { novelty: 0.5, utility: 0.5, tractability: 0.5, robustness: 0.5, taste: 0.5 },
1983
+ metricSpread: {},
1984
+ hardGates: { correctness: true, scope: true, evidence: true, safety: true },
1985
+ confidence: 0.8,
1986
+ evidence: [],
1987
+ actionableInformation: [],
1988
+ anomalies: [],
1989
+ evaluatorIds: ["e1"],
1990
+ errors: [],
1991
+ verified: true,
1992
+ reports: [],
1993
+ });
1994
+ const dummyCandidate = new Candidate(
1995
+ "c1", "run1", 1, 0, 1, goal.contentHash, spec.contentHash, genome,
1996
+ { name: "P", tagline: "t" }, { id: "α", name: "n", seq: "s" }, [],
1997
+ "artifact text", "prod", "fam", [], "initial", sha256Text("artifact text"),
1998
+ );
1999
+ archive.add(dummyCandidate, dummyReport);
2000
+ const ctxA = `${goal.contentHash}:${spec.contentHash}`;
2001
+ const ctxB = `${proposedGoal.contentHash}:${spec.contentHash}`;
2002
+ add("archive-versioning-invariant", archive.size(ctxA) === 1 && archive.size(ctxB) === 0, `sizeA=${archive.size(ctxA)} sizeB=${archive.size(ctxB)}`);
2003
+
2004
+ // Structural diversity monitor.
2005
+ const identicalGenomes = [genome, genome, genome];
2006
+ const diverse = assessStructuralDiversity(identicalGenomes);
2007
+ add("diversity-detects-narrow-attractor", diverse.narrowAttractor === true, JSON.stringify(diverse));
2008
+
2009
+ // Full end-to-end demo run (mirrors the CLI main()).
2010
+ const demoReport = await runInnovationGenomeV3Demo({ problem: "Prove X.", domain: "mathematics", seed: 42 });
2011
+ add("demo-report-sealed", demoReport.tamper_evident_seal === true, "hash chain verified end-to-end");
2012
+ add("demo-report-has-best-candidate", demoReport.best_candidate !== undefined, JSON.stringify(demoReport.best_candidate ?? null));
2013
+
2014
+ return { ok: checks.every((c) => c.passed), checks };
2015
+ }