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,1529 @@
1
+ /**
2
+ * canonical-portfolio-orchestrator.ts
3
+ * ============================================================================
4
+ * Portfolio orchestration over the existing canonical terminal engines.
5
+ *
6
+ * IMPORTANT:
7
+ * This file does NOT replace, flatten, merge, or alter any canonical engine.
8
+ * Each engine executes as a separate lane and returns its untouched raw
9
+ * result. The orchestrator only:
10
+ *
11
+ * 1. schedules lanes with bounded delayed hedging;
12
+ * 2. normalizes public output metadata for comparison;
13
+ * 3. chooses the best complete public result lexicographically;
14
+ * 4. preserves every raw lane result for inspection;
15
+ * 5. measures inter-engine evidence-block agreement.
16
+ *
17
+ * Default mode is "hedged":
18
+ * - start the highest-priority terminal engine;
19
+ * - after hedgeDelayMs, start another if no acceptable result exists;
20
+ * - cap concurrent full pipelines;
21
+ * - abort outstanding lanes once an acceptable output wins.
22
+ *
23
+ * "audit-all" mode runs every enabled canonical engine with bounded
24
+ * parallelism and returns every completed result.
25
+ *
26
+ * This avoids the earlier anti-pattern of replacing a feature-rich canonical
27
+ * stack with a much shorter monolith.
28
+ *
29
+ * ADDITIVE ONLY. No canonical module is modified.
30
+ * No new npm dependencies.
31
+ * Browser/static-build compatible.
32
+ *
33
+ * NOT EXECUTED in this environment.
34
+ * ============================================================================
35
+ */
36
+
37
+ import {
38
+ terminalWireGround,
39
+ } from "./terminal-wire";
40
+
41
+ import {
42
+ sentinelGround as sentinelOrchestratorGround,
43
+ } from "./sentinel-orchestrator";
44
+
45
+ import {
46
+ groundWithSentinelOmega,
47
+ } from "./sentinel-omega";
48
+
49
+ import {
50
+ vanguardGround,
51
+ } from "./vanguard-titanium";
52
+
53
+ import {
54
+ structuredSearch,
55
+ } from "./structured-source-adapter";
56
+
57
+ import {
58
+ omniNexusGround,
59
+ } from "../omni-nexus";
60
+
61
+ // ═══════════════════════════════════════════════════════════════════════════
62
+ // Public types
63
+ // ═══════════════════════════════════════════════════════════════════════════
64
+
65
+ export type CanonicalLaneId =
66
+ | "terminal-wire"
67
+ | "sentinel-orchestrator"
68
+ | "vanguard-packer"
69
+ | "sentinel-omega"
70
+ | "omni-nexus"
71
+ | "structured-search";
72
+
73
+ export type PortfolioMode =
74
+ | "hedged"
75
+ | "audit-all";
76
+
77
+ export interface PortfolioOptions {
78
+ signal?: AbortSignal;
79
+
80
+ mode?: PortfolioMode;
81
+
82
+ depth?: number;
83
+ maxContextTokens?: number;
84
+ charsPerToken?: number;
85
+
86
+ allowJina?: boolean;
87
+ allowPublicProxies?: boolean;
88
+ allowWayback?: boolean;
89
+
90
+ openAlexApiKey?: string;
91
+
92
+ maxParallelLanes?: number;
93
+ hedgeDelayMs?: number;
94
+ laneTimeoutMs?: number;
95
+ overallTimeoutMs?: number;
96
+
97
+ enableLanes?: Partial<
98
+ Record<CanonicalLaneId, boolean>
99
+ >;
100
+
101
+ /**
102
+ * Google Translate/AMP identity-borrowing remains disabled by default.
103
+ * The canonical modules remain independently callable; this orchestrator
104
+ * does not activate those lanes.
105
+ */
106
+ enableExperimentalTitanium?: boolean;
107
+
108
+ onDebug?: (message: string) => void;
109
+ }
110
+
111
+ export interface StandardSource {
112
+ title: string;
113
+ url: string;
114
+ content: string;
115
+ }
116
+
117
+ export interface NormalizedLaneResult {
118
+ ok: boolean;
119
+ eligibleForWinner: boolean;
120
+ acceptable: boolean;
121
+
122
+ provider: string;
123
+ evidenceBlock: string;
124
+ sources: StandardSource[];
125
+
126
+ sourceCount: number;
127
+ claimCount: number;
128
+ structuredItemCount: number;
129
+
130
+ attestedCount: number;
131
+ supportedCount: number;
132
+ conflictedCount: number;
133
+
134
+ proof:
135
+ | "verified"
136
+ | "bound"
137
+ | "unavailable"
138
+ | "invalid"
139
+ | "unknown";
140
+
141
+ qualityVector: readonly [
142
+ acceptable: number,
143
+ proofRank: number,
144
+ attested: number,
145
+ supported: number,
146
+ claims: number,
147
+ sources: number,
148
+ blockLength: number,
149
+ ];
150
+ }
151
+
152
+ export interface LaneExecution {
153
+ id: CanonicalLaneId;
154
+ priority: number;
155
+
156
+ status:
157
+ | "fulfilled"
158
+ | "rejected"
159
+ | "aborted"
160
+ | "timed-out";
161
+
162
+ elapsedMs: number;
163
+ error?: string;
164
+
165
+ normalized?: NormalizedLaneResult;
166
+
167
+ /**
168
+ * Exact untouched canonical engine output.
169
+ */
170
+ raw?: unknown;
171
+ }
172
+
173
+ export interface AgreementCell {
174
+ left: CanonicalLaneId;
175
+ right: CanonicalLaneId;
176
+ tokenJaccard: number;
177
+ }
178
+
179
+ export interface PortfolioGroundingResult {
180
+ ok: boolean;
181
+
182
+ provider: string;
183
+ winnerLane?: CanonicalLaneId;
184
+
185
+ count: number;
186
+ sources: StandardSource[];
187
+ evidenceBlock: string;
188
+
189
+ laneResults: LaneExecution[];
190
+ agreement: AgreementCell[];
191
+
192
+ /**
193
+ * Untouched output of the selected canonical engine.
194
+ */
195
+ winnerRaw?: unknown;
196
+ }
197
+
198
+ // ═══════════════════════════════════════════════════════════════════════════
199
+ // Internal types
200
+ // ═══════════════════════════════════════════════════════════════════════════
201
+
202
+ interface LaneSpec {
203
+ id: CanonicalLaneId;
204
+ priority: number;
205
+ eligibleForWinner: boolean;
206
+
207
+ run: (
208
+ signal: AbortSignal,
209
+ ) => Promise<unknown>;
210
+ }
211
+
212
+ type UnknownRecord = Record<
213
+ string,
214
+ unknown
215
+ >;
216
+
217
+ // ═══════════════════════════════════════════════════════════════════════════
218
+ // Helpers
219
+ // ═══════════════════════════════════════════════════════════════════════════
220
+
221
+ function isRecord(
222
+ value: unknown,
223
+ ): value is UnknownRecord {
224
+ return (
225
+ typeof value === "object" &&
226
+ value !== null &&
227
+ !Array.isArray(value)
228
+ );
229
+ }
230
+
231
+ function asString(
232
+ value: unknown,
233
+ ): string {
234
+ return typeof value === "string"
235
+ ? value
236
+ : "";
237
+ }
238
+
239
+ function asFiniteNumber(
240
+ value: unknown,
241
+ ): number {
242
+ return typeof value === "number" &&
243
+ Number.isFinite(value)
244
+ ? value
245
+ : 0;
246
+ }
247
+
248
+ function nowMs(): number {
249
+ return typeof performance !== "undefined"
250
+ ? performance.now()
251
+ : Date.now();
252
+ }
253
+
254
+ function clampInteger(
255
+ value: number | undefined,
256
+ fallback: number,
257
+ minimum: number,
258
+ maximum: number,
259
+ ): number {
260
+ if (
261
+ value === undefined ||
262
+ !Number.isFinite(value)
263
+ ) {
264
+ return fallback;
265
+ }
266
+
267
+ return Math.max(
268
+ minimum,
269
+ Math.min(
270
+ maximum,
271
+ Math.floor(value),
272
+ ),
273
+ );
274
+ }
275
+
276
+ function linkSignal(
277
+ parent: AbortSignal | undefined,
278
+ timeoutMs: number,
279
+ ): {
280
+ signal: AbortSignal;
281
+ cleanup: () => void;
282
+ timedOut: () => boolean;
283
+ } {
284
+ const controller =
285
+ new AbortController();
286
+
287
+ let timeoutReached = false;
288
+
289
+ const onAbort = () => {
290
+ if (!controller.signal.aborted) {
291
+ controller.abort();
292
+ }
293
+ };
294
+
295
+ if (parent?.aborted) {
296
+ controller.abort();
297
+ } else {
298
+ parent?.addEventListener(
299
+ "abort",
300
+ onAbort,
301
+ { once: true },
302
+ );
303
+ }
304
+
305
+ const timer = setTimeout(() => {
306
+ timeoutReached = true;
307
+ onAbort();
308
+ }, timeoutMs);
309
+
310
+ return {
311
+ signal: controller.signal,
312
+
313
+ cleanup: () => {
314
+ clearTimeout(timer);
315
+ parent?.removeEventListener(
316
+ "abort",
317
+ onAbort,
318
+ );
319
+ },
320
+
321
+ timedOut: () => timeoutReached,
322
+ };
323
+ }
324
+
325
+ function readProof(
326
+ object: UnknownRecord,
327
+ ): NormalizedLaneResult["proof"] {
328
+ const direct =
329
+ asString(object.surfaceProof) ||
330
+ asString(object.provenanceProof);
331
+
332
+ if (
333
+ direct === "verified" ||
334
+ direct === "bound" ||
335
+ direct === "unavailable" ||
336
+ direct === "invalid"
337
+ ) {
338
+ return direct;
339
+ }
340
+
341
+ const provenance = isRecord(
342
+ object.provenance,
343
+ )
344
+ ? object.provenance
345
+ : undefined;
346
+
347
+ const nested = asString(
348
+ provenance?.proof,
349
+ );
350
+
351
+ if (
352
+ nested === "verified" ||
353
+ nested === "bound" ||
354
+ nested === "unavailable" ||
355
+ nested === "invalid"
356
+ ) {
357
+ return nested;
358
+ }
359
+
360
+ return "unknown";
361
+ }
362
+
363
+ function proofRank(
364
+ proof: NormalizedLaneResult["proof"],
365
+ ): number {
366
+ switch (proof) {
367
+ case "verified":
368
+ return 4;
369
+ case "bound":
370
+ return 3;
371
+ case "unknown":
372
+ return 2;
373
+ case "unavailable":
374
+ return 1;
375
+ case "invalid":
376
+ return 0;
377
+ }
378
+ }
379
+
380
+ function normalizeSource(
381
+ value: unknown,
382
+ ): StandardSource | null {
383
+ if (!isRecord(value)) return null;
384
+
385
+ const title =
386
+ asString(value.title) ||
387
+ "Untitled";
388
+
389
+ const url =
390
+ asString(value.canonicalUrl) ||
391
+ asString(value.url) ||
392
+ asString(value.externalUrl);
393
+
394
+ const content =
395
+ asString(value.content) ||
396
+ asString(value.pageContent) ||
397
+ asString(value.abstract) ||
398
+ asString(value.snippet);
399
+
400
+ if (!url && !content) return null;
401
+
402
+ return {
403
+ title,
404
+ url,
405
+ content,
406
+ };
407
+ }
408
+
409
+ function normalizeSources(
410
+ object: UnknownRecord,
411
+ ): {
412
+ sources: StandardSource[];
413
+ structuredItemCount: number;
414
+ } {
415
+ const direct = Array.isArray(
416
+ object.sources,
417
+ )
418
+ ? object.sources
419
+ : [];
420
+
421
+ const structured = Array.isArray(
422
+ object.structuredItems,
423
+ )
424
+ ? object.structuredItems
425
+ : [];
426
+
427
+ const items = [
428
+ ...direct,
429
+ ...structured,
430
+ ];
431
+
432
+ const seen = new Set<string>();
433
+ const sources: StandardSource[] = [];
434
+
435
+ for (const item of items) {
436
+ const source = normalizeSource(item);
437
+ if (!source) continue;
438
+
439
+ const key =
440
+ source.url ||
441
+ `${source.title}\u0000${source.content.slice(
442
+ 0,
443
+ 80,
444
+ )}`;
445
+
446
+ if (seen.has(key)) continue;
447
+ seen.add(key);
448
+ sources.push(source);
449
+ }
450
+
451
+ return {
452
+ sources,
453
+ structuredItemCount:
454
+ structured.length,
455
+ };
456
+ }
457
+
458
+ function readCount(
459
+ object: UnknownRecord,
460
+ field: string,
461
+ ): number {
462
+ const direct =
463
+ asFiniteNumber(object[field]);
464
+
465
+ if (direct > 0) return direct;
466
+
467
+ const counts = isRecord(object.counts)
468
+ ? object.counts
469
+ : isRecord(object.dispositionCounts)
470
+ ? object.dispositionCounts
471
+ : undefined;
472
+
473
+ return asFiniteNumber(
474
+ counts?.[field],
475
+ );
476
+ }
477
+
478
+ function normalizeLaneOutput(
479
+ raw: unknown,
480
+ eligibleForWinner: boolean,
481
+ ): NormalizedLaneResult {
482
+ const object = isRecord(raw)
483
+ ? raw
484
+ : {};
485
+
486
+ const sourceData =
487
+ normalizeSources(object);
488
+
489
+ const claims = Array.isArray(
490
+ object.claims,
491
+ )
492
+ ? object.claims
493
+ : [];
494
+
495
+ const evidenceBlock = asString(
496
+ object.evidenceBlock,
497
+ );
498
+
499
+ const provider =
500
+ asString(object.provider) ||
501
+ "unknown-provider";
502
+
503
+ const proof = readProof(object);
504
+
505
+ const attestedCount =
506
+ readCount(object, "attested") ||
507
+ readCount(
508
+ isRecord(object.stats)
509
+ ? object.stats
510
+ : {},
511
+ "attestedClaims",
512
+ );
513
+
514
+ const supportedCount =
515
+ readCount(object, "supported") ||
516
+ readCount(
517
+ isRecord(object.stats)
518
+ ? object.stats
519
+ : {},
520
+ "supportedClaims",
521
+ );
522
+
523
+ const conflictedCount =
524
+ readCount(object, "conflicted") ||
525
+ readCount(
526
+ isRecord(object.stats)
527
+ ? object.stats
528
+ : {},
529
+ "conflictedClaims",
530
+ );
531
+
532
+ const explicitCount =
533
+ asFiniteNumber(object.count);
534
+
535
+ const sourceCount = Math.max(
536
+ sourceData.sources.length,
537
+ explicitCount,
538
+ );
539
+
540
+ const claimCount = claims.length;
541
+
542
+ const rawOk =
543
+ object.ok === true;
544
+
545
+ const acceptable =
546
+ eligibleForWinner &&
547
+ rawOk &&
548
+ evidenceBlock.length >= 128 &&
549
+ (sourceCount >= 1 ||
550
+ claimCount >= 1 ||
551
+ sourceData.structuredItemCount >= 2);
552
+
553
+ const qualityVector =
554
+ [
555
+ acceptable ? 1 : 0,
556
+ proofRank(proof),
557
+ attestedCount,
558
+ supportedCount,
559
+ claimCount,
560
+ sourceCount,
561
+ evidenceBlock.length,
562
+ ] as const;
563
+
564
+ return {
565
+ ok: rawOk,
566
+ eligibleForWinner,
567
+ acceptable,
568
+ provider,
569
+ evidenceBlock,
570
+ sources: sourceData.sources,
571
+ sourceCount,
572
+ claimCount,
573
+ structuredItemCount:
574
+ sourceData.structuredItemCount,
575
+ attestedCount,
576
+ supportedCount,
577
+ conflictedCount,
578
+ proof,
579
+ qualityVector,
580
+ };
581
+ }
582
+
583
+ function compareNormalized(
584
+ left: NormalizedLaneResult,
585
+ right: NormalizedLaneResult,
586
+ ): number {
587
+ for (
588
+ let index = 0;
589
+ index <
590
+ left.qualityVector.length;
591
+ index += 1
592
+ ) {
593
+ const delta =
594
+ left.qualityVector[index] -
595
+ right.qualityVector[index];
596
+
597
+ if (delta !== 0) return delta;
598
+ }
599
+
600
+ return 0;
601
+ }
602
+
603
+ function chooseBest(
604
+ results: LaneExecution[],
605
+ ): LaneExecution | undefined {
606
+ return results
607
+ .filter(
608
+ (
609
+ result,
610
+ ): result is LaneExecution & {
611
+ normalized: NormalizedLaneResult;
612
+ } =>
613
+ result.status === "fulfilled" &&
614
+ result.normalized !== undefined &&
615
+ result.normalized
616
+ .eligibleForWinner,
617
+ )
618
+ .sort((left, right) => {
619
+ const quality =
620
+ compareNormalized(
621
+ right.normalized,
622
+ left.normalized,
623
+ );
624
+
625
+ if (quality !== 0) return quality;
626
+
627
+ return (
628
+ right.priority -
629
+ left.priority
630
+ );
631
+ })[0];
632
+ }
633
+
634
+ function tokenSet(
635
+ text: string,
636
+ ): Set<string> {
637
+ const tokens = (
638
+ text.toLowerCase().match(
639
+ /[\p{L}\p{N}]+/gu,
640
+ ) ?? []
641
+ ).filter(
642
+ (token) => token.length > 2,
643
+ );
644
+
645
+ return new Set(tokens);
646
+ }
647
+
648
+ function tokenJaccard(
649
+ left: string,
650
+ right: string,
651
+ ): number {
652
+ const a = tokenSet(left);
653
+ const b = tokenSet(right);
654
+
655
+ if (a.size === 0 || b.size === 0) {
656
+ return 0;
657
+ }
658
+
659
+ let intersection = 0;
660
+
661
+ for (const token of a) {
662
+ if (b.has(token)) {
663
+ intersection += 1;
664
+ }
665
+ }
666
+
667
+ const union =
668
+ a.size + b.size - intersection;
669
+
670
+ return union > 0
671
+ ? intersection / union
672
+ : 0;
673
+ }
674
+
675
+ function buildAgreement(
676
+ results: LaneExecution[],
677
+ ): AgreementCell[] {
678
+ const successful = results.filter(
679
+ (
680
+ result,
681
+ ): result is LaneExecution & {
682
+ normalized: NormalizedLaneResult;
683
+ } =>
684
+ result.status === "fulfilled" &&
685
+ result.normalized !== undefined &&
686
+ result.normalized.evidenceBlock.length >
687
+ 0,
688
+ );
689
+
690
+ const agreement: AgreementCell[] = [];
691
+
692
+ for (
693
+ let left = 0;
694
+ left < successful.length;
695
+ left += 1
696
+ ) {
697
+ for (
698
+ let right = left + 1;
699
+ right < successful.length;
700
+ right += 1
701
+ ) {
702
+ agreement.push({
703
+ left: successful[left].id,
704
+ right: successful[right].id,
705
+ tokenJaccard: tokenJaccard(
706
+ successful[left].normalized
707
+ .evidenceBlock,
708
+ successful[right].normalized
709
+ .evidenceBlock,
710
+ ),
711
+ });
712
+ }
713
+ }
714
+
715
+ return agreement;
716
+ }
717
+
718
+ // ═══════════════════════════════════════════════════════════════════════════
719
+ // Canonical lane definitions
720
+ // ═══════════════════════════════════════════════════════════════════════════
721
+
722
+ async function invokeQueryRunner(
723
+ runner: unknown,
724
+ query: string,
725
+ options: Record<string, unknown>,
726
+ ): Promise<unknown> {
727
+ if (typeof runner !== "function") {
728
+ throw new TypeError(
729
+ "canonical runner is not a function",
730
+ );
731
+ }
732
+
733
+ return (
734
+ runner as (
735
+ query: string,
736
+ options?: Record<string, unknown>,
737
+ ) => Promise<unknown>
738
+ )(query, options);
739
+ }
740
+
741
+ function buildLaneSpecs(
742
+ query: string,
743
+ options: PortfolioOptions,
744
+ ): LaneSpec[] {
745
+ const debug =
746
+ options.onDebug ?? (() => {});
747
+
748
+ const common = {
749
+ depth: options.depth,
750
+ maxContextTokens:
751
+ options.maxContextTokens,
752
+ charsPerToken:
753
+ options.charsPerToken,
754
+
755
+ allowJina:
756
+ options.allowJina,
757
+
758
+ allowPublicProxies:
759
+ options.allowPublicProxies,
760
+
761
+ allowProxies:
762
+ options.allowPublicProxies,
763
+
764
+ allowWayback:
765
+ options.allowWayback,
766
+
767
+ openAlexApiKey:
768
+ options.openAlexApiKey,
769
+
770
+ allowTitanium:
771
+ options.enableExperimentalTitanium ===
772
+ true,
773
+
774
+ allowAmp:
775
+ options.enableExperimentalTitanium ===
776
+ true,
777
+
778
+ onDebug: debug,
779
+ };
780
+
781
+ const enabled = (
782
+ id: CanonicalLaneId,
783
+ fallback = true,
784
+ ): boolean =>
785
+ options.enableLanes?.[id] ??
786
+ fallback;
787
+
788
+ const specs: LaneSpec[] = [];
789
+
790
+ if (enabled("terminal-wire")) {
791
+ specs.push({
792
+ id: "terminal-wire",
793
+ priority: 100,
794
+ eligibleForWinner: true,
795
+
796
+ run: (signal) =>
797
+ invokeQueryRunner(
798
+ terminalWireGround,
799
+ query,
800
+ {
801
+ ...common,
802
+ signal,
803
+ },
804
+ ),
805
+ });
806
+ }
807
+
808
+ if (enabled("sentinel-orchestrator")) {
809
+ specs.push({
810
+ id: "sentinel-orchestrator",
811
+ priority: 95,
812
+ eligibleForWinner: true,
813
+
814
+ run: (signal) =>
815
+ invokeQueryRunner(
816
+ sentinelOrchestratorGround,
817
+ query,
818
+ {
819
+ ...common,
820
+ signal,
821
+ },
822
+ ),
823
+ });
824
+ }
825
+
826
+ if (enabled("vanguard-packer")) {
827
+ specs.push({
828
+ id: "vanguard-packer",
829
+ priority: 85,
830
+ eligibleForWinner: true,
831
+
832
+ run: (signal) =>
833
+ invokeQueryRunner(
834
+ vanguardGround,
835
+ query,
836
+ {
837
+ ...common,
838
+ signal,
839
+ },
840
+ ),
841
+ });
842
+ }
843
+
844
+ if (enabled("sentinel-omega")) {
845
+ specs.push({
846
+ id: "sentinel-omega",
847
+ priority: 75,
848
+ eligibleForWinner: true,
849
+
850
+ run: (signal) =>
851
+ invokeQueryRunner(
852
+ groundWithSentinelOmega,
853
+ query,
854
+ {
855
+ ...common,
856
+ signal,
857
+ },
858
+ ),
859
+ });
860
+ }
861
+
862
+ if (enabled("omni-nexus")) {
863
+ specs.push({
864
+ id: "omni-nexus",
865
+ priority: 60,
866
+ eligibleForWinner: true,
867
+
868
+ run: async (signal) => {
869
+ if (
870
+ typeof omniNexusGround !==
871
+ "function"
872
+ ) {
873
+ throw new TypeError(
874
+ "omniNexusGround is unavailable",
875
+ );
876
+ }
877
+
878
+ return (
879
+ omniNexusGround as unknown as (
880
+ options: Record<
881
+ string,
882
+ unknown
883
+ >,
884
+ ) => Promise<unknown>
885
+ )({
886
+ query,
887
+ depth: options.depth,
888
+ maxTokens:
889
+ options.maxContextTokens,
890
+ concurrency:
891
+ options.maxParallelLanes,
892
+ signal,
893
+ onDebug: debug,
894
+ });
895
+ },
896
+ });
897
+ }
898
+
899
+ if (enabled("structured-search")) {
900
+ specs.push({
901
+ id: "structured-search",
902
+ priority: 50,
903
+ eligibleForWinner: false,
904
+
905
+ run: (signal) =>
906
+ invokeQueryRunner(
907
+ structuredSearch,
908
+ query,
909
+ {
910
+ signal,
911
+ limitPerSource: 6,
912
+ openAlexApiKey:
913
+ options.openAlexApiKey,
914
+ },
915
+ ),
916
+ });
917
+ }
918
+
919
+ return specs.sort(
920
+ (left, right) =>
921
+ right.priority - left.priority,
922
+ );
923
+ }
924
+
925
+ // ═══════════════════════════════════════════════════════════════════════════
926
+ // Lane execution
927
+ // ═══════════════════════════════════════════════════════════════════════════
928
+
929
+ async function runLane(
930
+ spec: LaneSpec,
931
+ parentSignal: AbortSignal | undefined,
932
+ timeoutMs: number,
933
+ ): Promise<LaneExecution> {
934
+ const startedAt = nowMs();
935
+
936
+ const linked = linkSignal(
937
+ parentSignal,
938
+ timeoutMs,
939
+ );
940
+
941
+ try {
942
+ const raw = await spec.run(
943
+ linked.signal,
944
+ );
945
+
946
+ return {
947
+ id: spec.id,
948
+ priority: spec.priority,
949
+ status: "fulfilled",
950
+ elapsedMs: Math.round(
951
+ nowMs() - startedAt,
952
+ ),
953
+ raw,
954
+ normalized: normalizeLaneOutput(
955
+ raw,
956
+ spec.eligibleForWinner,
957
+ ),
958
+ };
959
+ } catch (error) {
960
+ const isAb =
961
+ error instanceof Error &&
962
+ (error.name === "AbortError" ||
963
+ error.message === "ABORTED");
964
+
965
+ const status: LaneExecution["status"] =
966
+ linked.timedOut()
967
+ ? "timed-out"
968
+ : isAb
969
+ ? "aborted"
970
+ : "rejected";
971
+
972
+ return {
973
+ id: spec.id,
974
+ priority: spec.priority,
975
+ status,
976
+ elapsedMs: Math.round(
977
+ nowMs() - startedAt,
978
+ ),
979
+ error:
980
+ error instanceof Error
981
+ ? error.message
982
+ : String(error),
983
+ };
984
+ } finally {
985
+ linked.cleanup();
986
+ }
987
+ }
988
+
989
+ async function runAuditAll(
990
+ specs: LaneSpec[],
991
+ options: PortfolioOptions,
992
+ ): Promise<LaneExecution[]> {
993
+ const concurrency = clampInteger(
994
+ options.maxParallelLanes,
995
+ 2,
996
+ 1,
997
+ 4,
998
+ );
999
+
1000
+ const timeout = clampInteger(
1001
+ options.laneTimeoutMs,
1002
+ 45_000,
1003
+ 1_000,
1004
+ 300_000,
1005
+ );
1006
+
1007
+ const results =
1008
+ new Array<LaneExecution>(
1009
+ specs.length,
1010
+ );
1011
+
1012
+ let cursor = 0;
1013
+
1014
+ const workers = Array.from(
1015
+ {
1016
+ length: Math.min(
1017
+ concurrency,
1018
+ specs.length,
1019
+ ),
1020
+ },
1021
+ async () => {
1022
+ while (true) {
1023
+ if (options.signal?.aborted) {
1024
+ return;
1025
+ }
1026
+
1027
+ const index = cursor;
1028
+ cursor += 1;
1029
+
1030
+ if (index >= specs.length) {
1031
+ return;
1032
+ }
1033
+
1034
+ results[index] = await runLane(
1035
+ specs[index],
1036
+ options.signal,
1037
+ timeout,
1038
+ );
1039
+ }
1040
+ },
1041
+ );
1042
+
1043
+ await Promise.all(workers);
1044
+
1045
+ return results.filter(Boolean);
1046
+ }
1047
+
1048
+ async function runHedged(
1049
+ specs: LaneSpec[],
1050
+ options: PortfolioOptions,
1051
+ ): Promise<LaneExecution[]> {
1052
+ if (specs.length === 0) return [];
1053
+
1054
+ const maximumParallel = clampInteger(
1055
+ options.maxParallelLanes,
1056
+ 2,
1057
+ 1,
1058
+ 4,
1059
+ );
1060
+
1061
+ const hedgeDelay = clampInteger(
1062
+ options.hedgeDelayMs,
1063
+ 800,
1064
+ 0,
1065
+ 30_000,
1066
+ );
1067
+
1068
+ const laneTimeout = clampInteger(
1069
+ options.laneTimeoutMs,
1070
+ 45_000,
1071
+ 1_000,
1072
+ 300_000,
1073
+ );
1074
+
1075
+ const overallTimeout = clampInteger(
1076
+ options.overallTimeoutMs,
1077
+ 90_000,
1078
+ 2_000,
1079
+ 600_000,
1080
+ );
1081
+
1082
+ const controller =
1083
+ new AbortController();
1084
+
1085
+ const onParentAbort = () => {
1086
+ if (!controller.signal.aborted) {
1087
+ controller.abort();
1088
+ }
1089
+ };
1090
+
1091
+ options.signal?.addEventListener(
1092
+ "abort",
1093
+ onParentAbort,
1094
+ { once: true },
1095
+ );
1096
+
1097
+ if (options.signal?.aborted) {
1098
+ controller.abort();
1099
+ }
1100
+
1101
+ return new Promise((resolve) => {
1102
+ const results: LaneExecution[] = [];
1103
+
1104
+ let nextIndex = 0;
1105
+ let active = 0;
1106
+ let finished = false;
1107
+
1108
+ let hedgeTimer:
1109
+ | ReturnType<typeof setTimeout>
1110
+ | undefined;
1111
+
1112
+ const overallTimer = setTimeout(
1113
+ () => finish(),
1114
+ overallTimeout,
1115
+ );
1116
+
1117
+ const cleanup = () => {
1118
+ clearTimeout(overallTimer);
1119
+
1120
+ if (hedgeTimer !== undefined) {
1121
+ clearTimeout(hedgeTimer);
1122
+ }
1123
+
1124
+ options.signal?.removeEventListener(
1125
+ "abort",
1126
+ onParentAbort,
1127
+ );
1128
+ };
1129
+
1130
+ const finish = () => {
1131
+ if (finished) return;
1132
+ finished = true;
1133
+ cleanup();
1134
+
1135
+ if (!controller.signal.aborted) {
1136
+ controller.abort();
1137
+ }
1138
+
1139
+ resolve(
1140
+ results
1141
+ .slice()
1142
+ .sort(
1143
+ (left, right) =>
1144
+ right.priority -
1145
+ left.priority,
1146
+ ),
1147
+ );
1148
+ };
1149
+
1150
+ const hasAcceptable = () =>
1151
+ results.some(
1152
+ (result) =>
1153
+ result.normalized
1154
+ ?.acceptable === true,
1155
+ );
1156
+
1157
+ const maybeFinish = () => {
1158
+ if (hasAcceptable()) {
1159
+ finish();
1160
+ return;
1161
+ }
1162
+
1163
+ if (
1164
+ active === 0 &&
1165
+ nextIndex >= specs.length
1166
+ ) {
1167
+ finish();
1168
+ }
1169
+ };
1170
+
1171
+ const scheduleHedge = () => {
1172
+ if (
1173
+ finished ||
1174
+ nextIndex >= specs.length
1175
+ ) {
1176
+ return;
1177
+ }
1178
+
1179
+ hedgeTimer = setTimeout(() => {
1180
+ hedgeTimer = undefined;
1181
+
1182
+ if (
1183
+ !finished &&
1184
+ !hasAcceptable()
1185
+ ) {
1186
+ startNext();
1187
+ scheduleHedge();
1188
+ }
1189
+ }, hedgeDelay);
1190
+ };
1191
+
1192
+ const startNext = () => {
1193
+ if (
1194
+ finished ||
1195
+ active >= maximumParallel ||
1196
+ nextIndex >= specs.length
1197
+ ) {
1198
+ return;
1199
+ }
1200
+
1201
+ const spec = specs[nextIndex];
1202
+ nextIndex += 1;
1203
+ active += 1;
1204
+
1205
+ options.onDebug?.(
1206
+ `portfolio: starting ${spec.id}`,
1207
+ );
1208
+
1209
+ void runLane(
1210
+ spec,
1211
+ controller.signal,
1212
+ laneTimeout,
1213
+ ).then((result) => {
1214
+ active = Math.max(0, active - 1);
1215
+ results.push(result);
1216
+
1217
+ options.onDebug?.(
1218
+ `portfolio: ${spec.id} ${result.status} in ${result.elapsedMs}ms`,
1219
+ );
1220
+
1221
+ if (
1222
+ result.normalized
1223
+ ?.acceptable === true
1224
+ ) {
1225
+ finish();
1226
+ return;
1227
+ }
1228
+
1229
+ if (
1230
+ active <
1231
+ maximumParallel &&
1232
+ nextIndex < specs.length
1233
+ ) {
1234
+ startNext();
1235
+ }
1236
+
1237
+ maybeFinish();
1238
+ });
1239
+ };
1240
+
1241
+ startNext();
1242
+ scheduleHedge();
1243
+
1244
+ if (controller.signal.aborted) {
1245
+ finish();
1246
+ }
1247
+ });
1248
+ }
1249
+
1250
+ // ═══════════════════════════════════════════════════════════════════════════
1251
+ // Public entry point
1252
+ // ═══════════════════════════════════════════════════════════════════════════
1253
+
1254
+ export async function groundWithCanonicalPortfolio(
1255
+ question: string,
1256
+ options: PortfolioOptions = {},
1257
+ ): Promise<PortfolioGroundingResult> {
1258
+ const normalizedQuestion =
1259
+ question.replace(/\s+/g, " ").trim();
1260
+
1261
+ if (!normalizedQuestion) {
1262
+ return {
1263
+ ok: false,
1264
+ provider:
1265
+ "canonical-portfolio(empty)",
1266
+ count: 0,
1267
+ sources: [],
1268
+ evidenceBlock: "",
1269
+ laneResults: [],
1270
+ agreement: [],
1271
+ };
1272
+ }
1273
+
1274
+ const specs = buildLaneSpecs(
1275
+ normalizedQuestion,
1276
+ options,
1277
+ );
1278
+
1279
+ if (specs.length === 0) {
1280
+ return {
1281
+ ok: false,
1282
+ provider:
1283
+ "canonical-portfolio(no-lanes)",
1284
+ count: 0,
1285
+ sources: [],
1286
+ evidenceBlock: "",
1287
+ laneResults: [],
1288
+ agreement: [],
1289
+ };
1290
+ }
1291
+
1292
+ const mode =
1293
+ options.mode ?? "hedged";
1294
+
1295
+ const laneResults =
1296
+ mode === "audit-all"
1297
+ ? await runAuditAll(
1298
+ specs,
1299
+ options,
1300
+ )
1301
+ : await runHedged(
1302
+ specs,
1303
+ options,
1304
+ );
1305
+
1306
+ const winner =
1307
+ chooseBest(laneResults);
1308
+
1309
+ const agreement =
1310
+ buildAgreement(laneResults);
1311
+
1312
+ if (
1313
+ !winner?.normalized ||
1314
+ !winner.normalized.acceptable
1315
+ ) {
1316
+ return {
1317
+ ok: false,
1318
+ provider:
1319
+ "canonical-portfolio(exhausted)",
1320
+ count: 0,
1321
+ sources: [],
1322
+ evidenceBlock: "",
1323
+ laneResults,
1324
+ agreement,
1325
+ winnerRaw: winner?.raw,
1326
+ };
1327
+ }
1328
+
1329
+ return {
1330
+ ok: true,
1331
+
1332
+ provider:
1333
+ `canonical-portfolio(${winner.id}→${winner.normalized.provider})`,
1334
+
1335
+ winnerLane: winner.id,
1336
+
1337
+ count:
1338
+ winner.normalized.sourceCount,
1339
+
1340
+ sources:
1341
+ winner.normalized.sources,
1342
+
1343
+ evidenceBlock:
1344
+ winner.normalized.evidenceBlock,
1345
+
1346
+ laneResults,
1347
+ agreement,
1348
+
1349
+ winnerRaw: winner.raw,
1350
+ };
1351
+ }
1352
+
1353
+ // ═══════════════════════════════════════════════════════════════════════════
1354
+ // Diagnostics
1355
+ // ═══════════════════════════════════════════════════════════════════════════
1356
+
1357
+ export function runCanonicalPortfolioDiagnostics(): {
1358
+ ok: boolean;
1359
+ checks: Array<{
1360
+ id: string;
1361
+ passed: boolean;
1362
+ detail: string;
1363
+ }>;
1364
+ } {
1365
+ const checks: Array<{
1366
+ id: string;
1367
+ passed: boolean;
1368
+ detail: string;
1369
+ }> = [];
1370
+
1371
+ const add = (
1372
+ id: string,
1373
+ passed: boolean,
1374
+ detail: string,
1375
+ ) => {
1376
+ checks.push({
1377
+ id,
1378
+ passed,
1379
+ detail,
1380
+ });
1381
+ };
1382
+
1383
+ const base = {
1384
+ ok: true,
1385
+ provider: "test",
1386
+ evidenceBlock:
1387
+ "A sufficiently long evidence block. ".repeat(
1388
+ 20,
1389
+ ),
1390
+ sources: [
1391
+ {
1392
+ title: "Source",
1393
+ url: "https://example.com",
1394
+ content: "Content",
1395
+ },
1396
+ ],
1397
+ claims: [
1398
+ {
1399
+ id: "C1",
1400
+ },
1401
+ ],
1402
+ counts: {
1403
+ attested: 1,
1404
+ supported: 0,
1405
+ conflicted: 0,
1406
+ },
1407
+ provenance: {
1408
+ proof: "verified",
1409
+ },
1410
+ };
1411
+
1412
+ const normalized =
1413
+ normalizeLaneOutput(
1414
+ base,
1415
+ true,
1416
+ );
1417
+
1418
+ add(
1419
+ "normalization-acceptable",
1420
+ normalized.acceptable,
1421
+ `acceptable=${normalized.acceptable}`,
1422
+ );
1423
+
1424
+ add(
1425
+ "normalization-proof",
1426
+ normalized.proof === "verified",
1427
+ `proof=${normalized.proof}`,
1428
+ );
1429
+
1430
+ add(
1431
+ "normalization-counts",
1432
+ normalized.sourceCount === 1 &&
1433
+ normalized.claimCount === 1 &&
1434
+ normalized.attestedCount === 1,
1435
+ `sources=${normalized.sourceCount} claims=${normalized.claimCount} attested=${normalized.attestedCount}`,
1436
+ );
1437
+
1438
+ const weaker =
1439
+ normalizeLaneOutput(
1440
+ {
1441
+ ...base,
1442
+ evidenceBlock:
1443
+ "Another long evidence block. ".repeat(
1444
+ 20,
1445
+ ),
1446
+ counts: {
1447
+ attested: 0,
1448
+ supported: 1,
1449
+ },
1450
+ provenance: {
1451
+ proof: "bound",
1452
+ },
1453
+ },
1454
+ true,
1455
+ );
1456
+
1457
+ add(
1458
+ "lexicographic-selection",
1459
+ compareNormalized(
1460
+ normalized,
1461
+ weaker,
1462
+ ) > 0,
1463
+ `strong=${normalized.qualityVector.join(
1464
+ ",",
1465
+ )} weak=${weaker.qualityVector.join(
1466
+ ",",
1467
+ )}`,
1468
+ );
1469
+
1470
+ const jSame = tokenJaccard(
1471
+ "alpha beta gamma",
1472
+ "alpha beta gamma",
1473
+ );
1474
+
1475
+ const jDifferent = tokenJaccard(
1476
+ "alpha beta gamma",
1477
+ "quartz violin nebula",
1478
+ );
1479
+
1480
+ add(
1481
+ "agreement-identical",
1482
+ jSame === 1,
1483
+ `j=${jSame}`,
1484
+ );
1485
+
1486
+ add(
1487
+ "agreement-different",
1488
+ jDifferent === 0,
1489
+ `j=${jDifferent}`,
1490
+ );
1491
+
1492
+ const structured =
1493
+ normalizeLaneOutput(
1494
+ {
1495
+ ok: true,
1496
+ structuredItems: [
1497
+ {
1498
+ title: "Paper",
1499
+ externalUrl:
1500
+ "https://doi.org/example",
1501
+ pageContent:
1502
+ "Structured metadata",
1503
+ },
1504
+ {
1505
+ title: "Paper 2",
1506
+ externalUrl:
1507
+ "https://doi.org/example2",
1508
+ pageContent:
1509
+ "Structured metadata 2",
1510
+ },
1511
+ ],
1512
+ },
1513
+ false,
1514
+ );
1515
+
1516
+ add(
1517
+ "auxiliary-not-final",
1518
+ !structured.acceptable &&
1519
+ structured.structuredItemCount === 2,
1520
+ `acceptable=${structured.acceptable} items=${structured.structuredItemCount}`,
1521
+ );
1522
+
1523
+ return {
1524
+ ok: checks.every(
1525
+ (check) => check.passed,
1526
+ ),
1527
+ checks,
1528
+ };
1529
+ }