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,769 @@
1
+ /**
2
+ * V15 Pipeline entry — Multi-Agent Refinement with Rotation & Elo Consensus.
3
+ *
4
+ * Flow: Draft → scanUniversalFlaws → autoFix → re-scan → parallel Elo Judges.
5
+ * If score < 9.0 or critical issues remain, enters iterative multi-agent loop
6
+ * (Critique → Editor) up to maxDepth using fast model rotation.
7
+ */
8
+ import { ensureFlawsLoaded } from "./flaws";
9
+ import { runFlawScan, runAutoFix, type ScanContext } from "./flaw-registry";
10
+ import { generateWithRotation, parallelJudgeRotation, getActiveRotationPool } from "./model-rotator";
11
+ import { calculateEloConsensus, type EloConsensusResult } from "./elo-registry";
12
+ import { proposeGateWithLLM, runTestbedGates, type TestbedGate } from "./v15-gate-testbed";
13
+ import { ensureOriginalDefensePackLoaded } from "./flaws/original-defenses-pack";
14
+ import { groundQuestion } from "./v15-grounding";
15
+ import { runAdversarialRedTeam } from "@/lib/adversarial-engine";
16
+
17
+ /**
18
+ * V15 Pipeline Profile — mirrors the original 4-stage / N-Deep / Cluster /
19
+ * SLOOP knobs from the base app so calibration can benchmark any single
20
+ * profile, any combination, or all together with variable quantities.
21
+ *
22
+ * All fields are OPTIONAL and default to a lightweight profile so nothing
23
+ * breaks when callers don't opt in. When any of the four flags is true,
24
+ * V15 injects the corresponding synthesis-side directives into the drafting
25
+ * system-prompt (still purely additive — the deterministic critique/editor
26
+ * refinement loop and Elo judging run identically underneath).
27
+ */
28
+ export interface V15Profile {
29
+ fourStage?: boolean; // enable 4-stage micro-agent framing
30
+ nDeep?: boolean; // enable N-Deep recursive adversarial refinement
31
+ nDeepPasses?: number; // depth cap (1..8), default 4
32
+ cluster?: boolean; // enable clustered hypothesis synthesis
33
+ clusterSize?: number; // parallel breadth (1..16), default 8
34
+ sloop?: boolean; // enable SLOOP long-form report mode
35
+ sloopPages?: number; // target pages (1..32), default 4
36
+ templateId?: string; // e.g. "OMEGA-STRATEGY", "NIH-GRANT-SRF"
37
+ styleOverride?: string; // e.g. "--mckinsey-classic"
38
+ useOriginalDefensePack?: boolean; // register + scan original 246-defense pack
39
+ williamsPersona?: string; // Williams-style persona archetype to test (e.g. "The Architect")
40
+ adversarial?: boolean; // run the adversarial red-team engine on the draft
41
+ webSearch?: boolean; // enable live grounding retrieval
42
+ webBackends?: { ogScraper?: boolean; prismafetch?: boolean; jina?: boolean };
43
+ }
44
+
45
+ /**
46
+ * Independent Comparative Judge — a THIRD judge with a fresh context that sees
47
+ * the QUESTION and BOTH answers (baseline + V15) together and scores each,
48
+ * computes the gap, and lists the concrete improvements each needs to reach 9.9.
49
+ * This is distinct from the per-answer Elo panel (which never sees both answers).
50
+ */
51
+ export interface ComparativeJudgeResult {
52
+ baselineScore: number;
53
+ v15Score: number;
54
+ gap: number;
55
+ winner: "baseline" | "v15" | "tie";
56
+ baselineImprovements: string[];
57
+ v15Improvements: string[];
58
+ rationale: string;
59
+ judgeModel: string;
60
+ ok: boolean;
61
+ error?: string;
62
+ }
63
+
64
+ export interface V15RunOutcome {
65
+ question: string;
66
+ draft: string; // raw model output
67
+ fixed: string; // after deterministic auto-fix & multi-agent refinement
68
+ issues: { code: string; severity: string; message: string }[];
69
+ autoFixesApplied: string[];
70
+ guardScore: number; // deterministic 0-10
71
+ judgeScore: number | null; // Elo-weighted consensus score 0-10
72
+ judgeNote: string;
73
+ eloConsensus?: EloConsensusResult;
74
+ testbedGatesProposed?: TestbedGate[];
75
+ judgeRoster?: { model: string; elo: number; tier?: string; ok: boolean; latencyMs: number; score?: number }[];
76
+ modelUsed: string;
77
+ passes: number;
78
+ stable: boolean;
79
+ totalLatencyMs: number;
80
+ error?: string;
81
+ /** Exact settings this run used (shown per-question in the UI). */
82
+ runSettings?: {
83
+ depth: number; fourStage: boolean; cluster: boolean; clusterSize: number;
84
+ sloop: boolean; sloopPages: number; templateId?: string; styleOverride?: string;
85
+ williamsPersona?: string; adversarial: boolean; webSearch: boolean;
86
+ defensePack: boolean; advancedGates: boolean; singleJudge: boolean;
87
+ };
88
+ groundingProvider?: string;
89
+ groundingCount?: number;
90
+ }
91
+
92
+ /**
93
+ * Deterministic per-question model seed — distributes the STARTING preferred
94
+ * model across the rotation pool based on a stable hash of the question text.
95
+ * This is purely an efficiency improvement: generateWithRotation() already
96
+ * falls back across the full pool on any single failure, but when many
97
+ * questions run concurrently (as the calibration dialog now does), having
98
+ * them all start on the identical "preferred" model concentrates collision
99
+ * risk on one endpoint. Spreading the starting point avoids that without
100
+ * changing any scoring, judging, or fallback semantics.
101
+ */
102
+ function pickRotationSeed(text: string, pool: string[]): string {
103
+ let h = 0;
104
+ for (let i = 0; i < text.length; i++) h = (h * 31 + text.charCodeAt(i)) | 0;
105
+ const idx = Math.abs(h) % pool.length;
106
+ return pool[idx];
107
+ }
108
+
109
+ /**
110
+ * Completion / fragmentation check (from the guard-vs-judge divergence critique).
111
+ * A structurally truncated or mid-sentence answer is a hard failure — the LLM
112
+ * judge correctly zeroes these while the regex guard historically under-
113
+ * penalized. We detect it deterministically so the pipeline can Fail-and-Retry
114
+ * BEFORE wasting a judge call on broken content.
115
+ */
116
+ export function detectTruncation(text: string, opts?: { longForm?: boolean; targetPages?: number }): { truncated: boolean; reason: string } {
117
+ const t = text.trim();
118
+ if (t.length === 0) return { truncated: true, reason: "empty output" };
119
+ const lastLine = t.slice(t.lastIndexOf("\n") + 1).trim();
120
+ // Hanging structural markers / mid-sentence cut-offs.
121
+ const danglingHyphen = /[-–—]\s*$/.test(lastLine) || /\b\\times\s*$/.test(lastLine);
122
+ const danglingConnector = /[,;:]\s*$|\b(and|or|but|the|a|an|to|of|with|for|in|on|as|by|that|which|because|however|therefore|thus|since|while|where|when|is|are|was|were)\s*$/i.test(lastLine);
123
+ const noTerminal = !/[.!?)"'»”\]\}`]\s*$/.test(lastLine) && !/^[#>|*\-+\d]/.test(lastLine) && /\w$/.test(lastLine) && lastLine.length > 0;
124
+ const openFence = (t.match(/```/g) ?? []).length % 2 !== 0;
125
+ const openMath = (t.match(/\$\$/g) ?? []).length % 2 !== 0;
126
+ // Long-form under-length: requested N pages but got a fragment.
127
+ const longFormShort = !!opts?.longForm && t.length < Math.max(1200, (opts.targetPages ?? 4) * 900);
128
+
129
+ if (danglingHyphen) return { truncated: true, reason: "hanging hyphen / mid-formula cut-off" };
130
+ if (danglingConnector) return { truncated: true, reason: "sentence ends on a dangling connector word" };
131
+ if (openFence) return { truncated: true, reason: "unclosed code fence" };
132
+ if (openMath) return { truncated: true, reason: "unclosed math delimiter" };
133
+ if (noTerminal) return { truncated: true, reason: "final line lacks terminal punctuation (mid-sentence cut-off)" };
134
+ if (longFormShort) return { truncated: true, reason: `long-form report far below requested length (${t.length} chars for ~${opts?.targetPages ?? 4} pages)` };
135
+ return { truncated: false, reason: "" };
136
+ }
137
+
138
+ function sevRank(s: string): number {
139
+ return s === "critical" ? 4 : s === "major" ? 3 : s === "warning" ? 2 : 1;
140
+ }
141
+
142
+ /**
143
+ * Run the independent comparative judge (fresh context) over both answers.
144
+ */
145
+ export async function runComparativeJudge(opts: {
146
+ apiKey: string;
147
+ question: string;
148
+ baselineAnswer: string;
149
+ v15Answer: string;
150
+ judgeModel?: string;
151
+ }): Promise<ComparativeJudgeResult> {
152
+ const pool = getActiveRotationPool();
153
+ const model = opts.judgeModel ?? pool[Math.min(1, pool.length - 1)]; // distinct 2nd-Elo model by default
154
+ const nonce = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
155
+ const prompt = `You are an INDEPENDENT comparative judge with a completely fresh context (nonce ${nonce}). You are shown a QUESTION and TWO candidate answers (A = baseline, B = V15). Score EACH answer 0-10, compute the gap, and list the SPECIFIC improvements each answer needs to reach a 9.9.
156
+
157
+ HARD CAPS (apply the lowest that fits, to BOTH answers independently):
158
+ - Truncated / mid-sentence / fragment → cap 1
159
+ - Formula-only or partial calc with no explanation → cap 3
160
+ - Restates question / requires reader to already know the answer → cap 5
161
+ - Missing required units, jurisdiction, or scope → cap 6
162
+
163
+ Reserve 9+ only for answers a competent non-expert could act on immediately.
164
+
165
+ QUESTION:
166
+ ${opts.question}
167
+
168
+ ANSWER A (baseline):
169
+ ${opts.baselineAnswer.slice(0, 6000)}
170
+
171
+ ANSWER B (V15):
172
+ ${opts.v15Answer.slice(0, 6000)}
173
+
174
+ Return STRICT JSON:
175
+ {"baselineScore": <0-10>, "v15Score": <0-10>, "winner": "baseline"|"v15"|"tie", "rationale": "one paragraph", "baselineImprovements": ["...to reach 9.9"], "v15Improvements": ["...to reach 9.9"]}`;
176
+
177
+ const res = await generateWithRotation({ apiKey: opts.apiKey, prompt, preferredModel: model, maxOutputTokens: 800 });
178
+ if (!res.ok) {
179
+ return { baselineScore: 0, v15Score: 0, gap: 0, winner: "tie", baselineImprovements: [], v15Improvements: [], rationale: "", judgeModel: res.modelUsed, ok: false, error: res.error };
180
+ }
181
+ try {
182
+ const m = res.text.match(/\{[\s\S]*\}/);
183
+ const j = JSON.parse(m ? m[0] : res.text);
184
+ const b = Math.max(0, Math.min(10, Number(j.baselineScore) || 0));
185
+ const v = Math.max(0, Math.min(10, Number(j.v15Score) || 0));
186
+ return {
187
+ baselineScore: b, v15Score: v, gap: Math.round((v - b) * 100) / 100,
188
+ winner: (j.winner === "baseline" || j.winner === "v15" || j.winner === "tie") ? j.winner : (v > b ? "v15" : v < b ? "baseline" : "tie"),
189
+ baselineImprovements: Array.isArray(j.baselineImprovements) ? j.baselineImprovements.map(String).slice(0, 6) : [],
190
+ v15Improvements: Array.isArray(j.v15Improvements) ? j.v15Improvements.map(String).slice(0, 6) : [],
191
+ rationale: String(j.rationale ?? "").slice(0, 600),
192
+ judgeModel: res.modelUsed, ok: true,
193
+ };
194
+ } catch {
195
+ return { baselineScore: 0, v15Score: 0, gap: 0, winner: "tie", baselineImprovements: [], v15Improvements: [], rationale: "parse failure", judgeModel: res.modelUsed, ok: false, error: "json parse" };
196
+ }
197
+ }
198
+
199
+ function scoreFromIssues(issues: { severity: string }[], draftLen: number): number {
200
+ let err = 10, math = 10, style = 9.5, hall = 0;
201
+ for (const i of issues) {
202
+ if (i.severity === "critical") { err -= 2.5; math -= 2.0; hall += 2.5; }
203
+ else if (i.severity === "major") { err -= 1.2; math -= 1.5; hall += 1.2; }
204
+ else if (i.severity === "warning") { err -= 0.4; math -= 0.4; hall += 0.4; }
205
+ }
206
+ if (draftLen < 150) style -= 1.0;
207
+ const clamp = (n: number) => Math.max(0, Math.min(10, n));
208
+ err = clamp(err); math = clamp(math); style = clamp(style); hall = clamp(hall);
209
+ const combined = 0.40 * err + 0.30 * math + 0.20 * style + 0.10 * (10 - hall);
210
+ return Math.round(combined * 100) / 100;
211
+ }
212
+
213
+ /**
214
+ * Full V15 run against one question with multi-agent loop and rotation.
215
+ */
216
+ export async function runV15OnQuestion(opts: {
217
+ apiKey: string;
218
+ question: string;
219
+ draftModel?: string;
220
+ judgeModels?: string[];
221
+ runJudge?: boolean;
222
+ singleJudge?: boolean; // when true, use exactly 1 judge (fastest, less consensus)
223
+ judgeSampleSize?: number; // when set (2..9), use that many rotated judges
224
+ maxDepth?: number;
225
+ advancedGates?: boolean;
226
+ profile?: V15Profile; // 4-stage / N-Deep / Cluster / SLOOP knobs
227
+ onProgress?: (stage: string) => void;
228
+ }): Promise<V15RunOutcome> {
229
+ ensureFlawsLoaded();
230
+ const profile = opts.profile ?? {};
231
+ if (profile.useOriginalDefensePack) ensureOriginalDefensePackLoaded();
232
+ const t0 = Date.now();
233
+ const { apiKey, question, runJudge = true, maxDepth = 3, onProgress } = opts;
234
+ const draftModel = opts.draftModel ?? pickRotationSeed(question, getActiveRotationPool());
235
+
236
+ // Build the drafting system prompt with any profile directives active.
237
+ const directives: string[] = [
238
+ "You are an elite, highly calibrated domain expert.",
239
+ "Answer directly and comprehensively so the reader can act on it without further research.",
240
+ "Always: state assumptions, define variables, give worked numbers with units, and add jurisdiction/scope caveats when relevant.",
241
+ "Never respond with a formula alone — always show what it evaluates to for a concrete example even if the user did not provide inputs.",
242
+ ];
243
+ if (profile.fourStage) directives.push("Use the 4-Stage micro-agent framing internally (Plan → Draft → Critique → Polish), emit only the polished final answer.");
244
+ if (profile.nDeep) directives.push(`Use N-Deep adversarial refinement across ${Math.max(1, Math.min(8, profile.nDeepPasses ?? 4))} internal passes to catch missed edge cases.`);
245
+ if (profile.cluster) directives.push(`Cluster-synthesize across ${Math.max(1, Math.min(16, profile.clusterSize ?? 8))} parallel hypotheses internally, then present the merged best answer.`);
246
+ if (profile.sloop) directives.push(`SLOOP long-form report mode: target approximately ${Math.max(1, Math.min(32, profile.sloopPages ?? 4))} pages with substantive prose in every section (no stubs, no bare headers).`);
247
+ if (profile.templateId) directives.push(`Follow the "${profile.templateId}" template's section structure exactly (base OMEGA templates set).`);
248
+ if (profile.styleOverride) directives.push(`Apply the "${profile.styleOverride}" style-override modulation silently.`);
249
+ if (profile.williamsPersona) directives.push(`Write in the "${profile.williamsPersona}" Williams-style persona (Joseph Williams "Style: Toward Clarity and Grace") — apply its stylistic profile invisibly; never name the persona.`);
250
+
251
+ // ── Live grounding (threaded through EVERY pass) ──────────────────────────
252
+ let evidenceBlock = "";
253
+ let groundingProvider: string | undefined;
254
+ let groundingCount = 0;
255
+ if (profile.webSearch) {
256
+ onProgress?.("web grounding (retrieval)");
257
+ const grounded = await groundQuestion({
258
+ question,
259
+ backends: profile.webBackends ?? { ogScraper: true },
260
+ onDebug: (m: string) => onProgress?.(`grounding · ${m}`),
261
+ });
262
+ if (grounded.ok) {
263
+ evidenceBlock = grounded.evidenceBlock;
264
+ groundingProvider = grounded.provider;
265
+ groundingCount = grounded.count;
266
+ onProgress?.(`grounded via ${grounded.provider} · ${grounded.count} sources`);
267
+ } else {
268
+ groundingProvider = `unavailable: ${grounded.error}`;
269
+ onProgress?.(`grounding unavailable (${grounded.error}) — proceeding ungrounded`);
270
+ }
271
+ }
272
+
273
+ onProgress?.("drafting (rotated)");
274
+ const draftRes = await generateWithRotation({
275
+ apiKey,
276
+ prompt: evidenceBlock ? `${evidenceBlock}\n\nUSER QUESTION:\n${question}` : question,
277
+ preferredModel: draftModel,
278
+ systemInstruction: directives.join("\n"),
279
+ maxOutputTokens: profile.sloop ? Math.max(2400, (profile.sloopPages ?? 4) * 700) : 1400,
280
+ });
281
+
282
+ if (!draftRes.ok) {
283
+ return {
284
+ question, draft: "", fixed: "", issues: [], autoFixesApplied: [],
285
+ guardScore: 0, judgeScore: null, judgeNote: "", modelUsed: draftRes.modelUsed,
286
+ passes: 0, stable: false, totalLatencyMs: Date.now() - t0, error: draftRes.error,
287
+ };
288
+ }
289
+
290
+ let currentText = draftRes.text;
291
+ const allFixes: string[] = [];
292
+ let passes = 1;
293
+ let guardScore = 10;
294
+ let finalIssues: { code: string; severity: string; message: string; remediation?: string }[] = [];
295
+ let eloConsensus: EloConsensusResult | undefined;
296
+ const testbedGatesProposed: TestbedGate[] = [];
297
+
298
+ // ── HYPOTHESIS-DRIVEN ITERATIVE GROUNDING (HDIG) — ACL 2025 "Agentic
299
+ // Reasoning" pattern: the LLM identifies its OWN knowledge gaps in the
300
+ // draft, generates targeted search queries per gap, retrieves evidence,
301
+ // and the evidence is threaded into ALL subsequent N-Deep editor passes.
302
+ // This is strictly additive — when web grounding is OFF, HDIG is skipped.
303
+ if (profile.webSearch && groundingCount > 0) {
304
+ onProgress?.("hypothesis-driven iterative grounding (HDIG)");
305
+ try {
306
+ const gapRes = await generateWithRotation({
307
+ apiKey,
308
+ prompt: `You just drafted an answer to: "${question.slice(0, 400)}"\n\nYour draft:\n${currentText.slice(0, 3000)}\n\nIdentify up to 3 specific factual claims in your draft that would benefit from verification via web search. For each, output a targeted search query.\n\nReturn ONLY strict JSON:\n{"gaps": [{"claim": "...", "searchQuery": "..."}]}`,
309
+ maxOutputTokens: 300,
310
+ });
311
+ if (gapRes.ok) {
312
+ try {
313
+ const m = gapRes.text.match(/\{[\s\S]*\}/);
314
+ const j = JSON.parse(m ? m[0] : gapRes.text);
315
+ const gaps: { claim: string; searchQuery: string }[] = Array.isArray(j.gaps) ? j.gaps.slice(0, 3) : [];
316
+ if (gaps.length > 0) {
317
+ onProgress?.(`HDIG: ${gaps.length} knowledge gap(s) identified — searching`);
318
+ for (const gap of gaps) {
319
+ const hitRes = await groundQuestion({
320
+ question: gap.searchQuery,
321
+ backends: profile.webBackends ?? { ogScraper: true },
322
+ depth: 3,
323
+ onDebug: (dm: string) => onProgress?.(`HDIG · ${dm}`),
324
+ });
325
+ if (hitRes.ok && hitRes.sources.length > 0) {
326
+ // Thread the new evidence into the existing evidence block so
327
+ // ALL subsequent N-Deep editor passes see it.
328
+ const newEvidence = hitRes.sources.slice(0, 2).map((s, k) =>
329
+ `[S${groundingCount + k + 1}] ${s.title}\n${s.content}`
330
+ ).join("\n---\n");
331
+ evidenceBlock += `\n\nHDIG VERIFICATION for "${gap.claim.slice(0, 80)}":\n${newEvidence}`;
332
+ groundingCount += hitRes.sources.length;
333
+ onProgress?.(`HDIG: +${hitRes.sources.length} source(s) for "${gap.claim.slice(0, 40)}…"`);
334
+ }
335
+ }
336
+ }
337
+ } catch { /* JSON parse failure — skip silently, HDIG is best-effort */ }
338
+ }
339
+ } catch { onProgress?.("HDIG: gap analysis unavailable — continuing with existing evidence"); }
340
+ }
341
+
342
+ for (let d = 1; d <= maxDepth; d++) {
343
+ passes = d;
344
+ onProgress?.(`depth ${d}: scanning`);
345
+ const ctx: ScanContext = {
346
+ prompt: question,
347
+ answer: currentText,
348
+ lowerAnswer: currentText.toLowerCase(),
349
+ computeRecords: [],
350
+ constraints: { explicitComparisonTargets: [], exclusions: [], formatHints: [], namedEntities: [] } as any,
351
+ };
352
+ runFlawScan(ctx);
353
+
354
+ onProgress?.(`depth ${d}: auto-fixing`);
355
+ const af = runAutoFix(currentText, ctx);
356
+ currentText = af.text;
357
+ if (af.applied.length > 0) allFixes.push(...af.applied);
358
+
359
+ const ctx2 = { ...ctx, answer: currentText, lowerAnswer: currentText.toLowerCase() };
360
+ const scanned = runFlawScan(ctx2);
361
+ const testbedIssues = runTestbedGates(currentText);
362
+ finalIssues = [
363
+ ...scanned.map(i => ({ code: i.code, severity: i.severity, message: i.message, remediation: i.remediation })),
364
+ ...testbedIssues.map(i => ({ code: i.code, severity: i.severity, message: i.message, remediation: i.remediation })),
365
+ ];
366
+
367
+ // Completion-Check (from divergence critique): a truncated/fragmented answer
368
+ // is a hard failure. Record it as a critical issue so the editor MUST fix it
369
+ // and the guard score reflects it (Fail-and-Retry, not silent pass).
370
+ const trunc = detectTruncation(currentText, { longForm: !!profile.sloop, targetPages: profile.sloopPages });
371
+ if (trunc.truncated) {
372
+ finalIssues.unshift({ code: "TRUNCATED_OPENING", severity: "critical", message: `Structural truncation: ${trunc.reason}.`, remediation: "Regenerate a COMPLETE answer end-to-end. Do not stop mid-sentence, mid-formula, or mid-section." });
373
+ }
374
+ guardScore = scoreFromIssues(finalIssues, currentText.length);
375
+
376
+ // Per-depth advanced-gate mining: if enabled, mine NEW gates on EACH draft
377
+ // (not just at the very end) so the editor can address them next pass.
378
+ if (opts.advancedGates && d < maxDepth) {
379
+ const proposed = await proposeGateWithLLM({ apiKey, question, answer: currentText, judgeNote: finalIssues.slice(0, 5).map(i => i.code).join(", "), model: "gemini-3.1-flash-lite" });
380
+ if (proposed && !testbedGatesProposed.some(g => g.code === proposed.code)) testbedGatesProposed.push(proposed);
381
+ }
382
+
383
+ // Depth-honor mode: only allow early exit if the user did NOT explicitly
384
+ // request maxDepth ≥ 3, AND there is no truncation. When calibrating
385
+ // N-Deep=3+ we run ALL passes to exercise the full pipeline.
386
+ if (maxDepth <= 2 && !trunc.truncated && guardScore >= 9.2 && !finalIssues.some(i => i.severity === "critical" || i.severity === "major")) {
387
+ break;
388
+ }
389
+
390
+ if (d < maxDepth) {
391
+ onProgress?.(`depth ${d}: refining via Critique -> Editor (${finalIssues.length} flaws${testbedGatesProposed.length ? ` + ${testbedGatesProposed.length} testbed proposals` : ""})`);
392
+ // Cap the injected flaw list so the editor prompt stays focused on the
393
+ // highest-severity issues (critical > major > warning > info), but ALWAYS
394
+ // include truncation + all critical/major first.
395
+ const ordered = [...finalIssues].sort((a, b) => sevRank(b.severity) - sevRank(a.severity)).slice(0, 40);
396
+ const issuesBlock = ordered.map(i => `- [${i.code}] (${i.severity}): ${i.remediation || i.message}`).join("\n");
397
+ const testbedBlock = testbedGatesProposed.length > 0
398
+ ? `\n\nCUTTING-EDGE TESTBED GATES (also satisfy these newly-discovered patterns):\n${testbedGatesProposed.map(g => `- [${g.code}] ${g.message} → ${g.remediation}`).join("\n")}`
399
+ : "";
400
+ const editorPrompt = `You are a meticulous technical editor performing recursive refinement pass ${d + 1}. Revise the DRAFT to fix EVERY listed compliance flaw while preserving all correct factual content and rigor. Produce a COMPLETE answer — never truncate, never stop mid-sentence or mid-section. State assumptions, define variables, give worked numbers WITH units, and add jurisdiction/scope caveats when relevant. If a formula is used, always show the concrete evaluated result.
401
+
402
+ DETECTED FLAWS (fix all — ordered by severity):
403
+ ${issuesBlock || "Enhance clarity, completeness, and rigor."}${testbedBlock}
404
+ ${evidenceBlock ? `\n\n${evidenceBlock}\n(Ground every factual claim in the evidence above; cite [S#].)` : ""}
405
+
406
+ USER PROMPT:
407
+ ${question}
408
+
409
+ DRAFT TO REVISE:
410
+ ${currentText}`;
411
+
412
+ const activePool = getActiveRotationPool();
413
+ const editRes = await generateWithRotation({
414
+ apiKey,
415
+ prompt: editorPrompt,
416
+ preferredModel: pickRotationSeed(`${question}::edit${d}`, activePool),
417
+ maxOutputTokens: profile.sloop ? Math.max(2400, (profile.sloopPages ?? 4) * 700) : 1600,
418
+ });
419
+ if (editRes.ok && editRes.text.trim().length > 50) {
420
+ currentText = editRes.text.trim();
421
+ }
422
+ }
423
+ }
424
+
425
+ let judgeScore: number | null = null;
426
+ let judgeNote = "";
427
+ let judgeRoster: V15RunOutcome["judgeRoster"] = [];
428
+
429
+ if (runJudge) {
430
+ const activePool = getActiveRotationPool();
431
+ // Judge selection: explicit judgeModels list > singleJudge > judgeSampleSize > full 9-model roster.
432
+ let selectedJudgeModels: string[] | undefined = opts.judgeModels;
433
+ if (!selectedJudgeModels && opts.singleJudge) {
434
+ selectedJudgeModels = [activePool[0]]; // top-Elo model only
435
+ }
436
+ if (!selectedJudgeModels && opts.judgeSampleSize && opts.judgeSampleSize > 0) {
437
+ selectedJudgeModels = activePool.slice(0, Math.min(opts.judgeSampleSize, activePool.length));
438
+ }
439
+
440
+ onProgress?.(opts.singleJudge ? "single-judge (fastest)" : `parallel judging (${selectedJudgeModels?.length ?? activePool.length} judges, Elo consensus)`);
441
+ const judgeRun = await parallelJudgeRotation({
442
+ apiKey,
443
+ question,
444
+ answer: currentText,
445
+ judgeModels: selectedJudgeModels ?? activePool,
446
+ });
447
+
448
+ judgeRoster = judgeRun.attempts.map(a => {
449
+ const j = judgeRun.judgments.find(x => x.model === a.model);
450
+ return { model: a.model, elo: a.elo, tier: a.tier, ok: a.ok, latencyMs: a.latencyMs, score: j?.score };
451
+ });
452
+
453
+ if (judgeRun.judgments.length > 0) {
454
+ eloConsensus = calculateEloConsensus(judgeRun.judgments);
455
+ judgeScore = eloConsensus.weightedScore;
456
+ judgeNote = eloConsensus.rationale;
457
+
458
+ if (opts.advancedGates && (judgeScore < 9 || finalIssues.length === 0)) {
459
+ onProgress?.("advanced gate mining");
460
+ const proposed = await proposeGateWithLLM({
461
+ apiKey,
462
+ question,
463
+ answer: currentText,
464
+ judgeNote,
465
+ model: "gemini-3.1-flash-lite",
466
+ });
467
+ if (proposed) testbedGatesProposed.push(proposed);
468
+ }
469
+ } else {
470
+ judgeNote = "Judges temporarily rate-limited";
471
+ }
472
+ }
473
+
474
+ // ── Adversarial red-team (additive — same engine as the base app) ─────────
475
+ if (profile.adversarial) {
476
+ onProgress?.("adversarial red-team");
477
+ try {
478
+ const adv = await runAdversarialRedTeam(currentText, question, {
479
+ provider: "gemini", model: draftModel, apiKey, userMessage: question, conversationHistory: [],
480
+ } as any, { onDebug: (m: string) => onProgress?.(`adversarial · ${m}`) });
481
+ const blocking = (adv?.defects ?? []).filter((d) => d.severity === "critical" || d.severity === "major");
482
+ for (const d of blocking.slice(0, 8)) {
483
+ finalIssues.push({ code: `ADV_${String(d.category ?? d.id ?? "DEFECT").toUpperCase().replace(/\s+/g, "_")}`, severity: d.severity, message: String(d.detail ?? "adversarial defect") });
484
+ }
485
+ guardScore = scoreFromIssues(finalIssues, currentText.length);
486
+ } catch (e) {
487
+ onProgress?.(`adversarial engine unavailable: ${(e as Error).message}`);
488
+ }
489
+ }
490
+
491
+ onProgress?.("done");
492
+ const combined = judgeScore !== null ? Math.min(guardScore, judgeScore) : guardScore;
493
+ const stable = combined >= 9.0 && !finalIssues.some(i => i.severity === "critical");
494
+
495
+ return {
496
+ question,
497
+ draft: draftRes.text,
498
+ fixed: currentText,
499
+ issues: finalIssues,
500
+ autoFixesApplied: [...new Set(allFixes)],
501
+ guardScore,
502
+ judgeScore,
503
+ judgeNote,
504
+ eloConsensus,
505
+ testbedGatesProposed,
506
+ judgeRoster,
507
+ modelUsed: draftRes.modelUsed,
508
+ passes,
509
+ stable,
510
+ totalLatencyMs: Date.now() - t0,
511
+ groundingProvider,
512
+ groundingCount,
513
+ runSettings: {
514
+ depth: maxDepth,
515
+ fourStage: !!profile.fourStage,
516
+ cluster: !!profile.cluster, clusterSize: profile.clusterSize ?? 8,
517
+ sloop: !!profile.sloop, sloopPages: profile.sloopPages ?? 4,
518
+ templateId: profile.templateId, styleOverride: profile.styleOverride,
519
+ williamsPersona: profile.williamsPersona,
520
+ adversarial: !!profile.adversarial, webSearch: !!profile.webSearch,
521
+ defensePack: !!profile.useOriginalDefensePack, advancedGates: !!opts.advancedGates,
522
+ singleJudge: !!opts.singleJudge,
523
+ },
524
+ };
525
+ }
526
+
527
+ /**
528
+ * Baseline: no V15 processing (draft only), judged by the SAME judge policy
529
+ * as V15 so the reported "judge" numbers are comparable side-by-side.
530
+ */
531
+ /**
532
+ * Divergence Analysis — when guardScore and judgeScore disagree, ask a
533
+ * high-Elo LLM to explain WHY and produce a structured improvement suggestion
534
+ * (single option OR list of alternative options). Additive: not called by
535
+ * default; the UI opts in per row / per batch.
536
+ */
537
+ export interface DivergenceSuggestion {
538
+ reason: string; // one-paragraph plain-English cause
539
+ category: "missing-gate" | "false-positive-gate" | "rubric-mismatch" | "context-window" | "other";
540
+ suggestions: Array<{
541
+ approach: "new-gate" | "modify-gate" | "extend-flaw-pack" | "adjust-scoring-weights" | "adjust-judge-rubric" | "new-domain-pack" | "other";
542
+ description: string;
543
+ estimatedImpact: "low" | "medium" | "high";
544
+ tradeoffs: string;
545
+ }>;
546
+ }
547
+
548
+ export interface DivergenceEntry {
549
+ timestamp: number;
550
+ question: string;
551
+ guardScore: number;
552
+ judgeScore: number;
553
+ delta: number;
554
+ suggestion: DivergenceSuggestion;
555
+ authorityModel: string;
556
+ /** Full judge panel that scored this answer (model + score + Elo). */
557
+ judgePanel?: Array<{ model: string; score: number; elo: number }>;
558
+ /** Engineer decision state for the improvement ledger. */
559
+ decision?: "pending-decision" | "accepted" | "rejected";
560
+ }
561
+
562
+ const DIVERGENCE_LOG_KEY = "veritas.v15.divergenceLog";
563
+
564
+ export function getDivergenceLog(): DivergenceEntry[] {
565
+ try {
566
+ const raw = localStorage.getItem(DIVERGENCE_LOG_KEY);
567
+ return raw ? JSON.parse(raw) : [];
568
+ } catch { return []; }
569
+ }
570
+
571
+ export function saveDivergenceEntry(entry: DivergenceEntry): void {
572
+ try {
573
+ const log = getDivergenceLog();
574
+ log.push({ decision: "pending-decision", ...entry });
575
+ // Keep last 200 entries
576
+ localStorage.setItem(DIVERGENCE_LOG_KEY, JSON.stringify(log.slice(-200)));
577
+ } catch { /* ignore */ }
578
+ }
579
+
580
+ export function clearDivergenceLog(): void {
581
+ try { localStorage.removeItem(DIVERGENCE_LOG_KEY); } catch { /* ignore */ }
582
+ }
583
+
584
+ export async function analyzeDivergence(opts: {
585
+ apiKey: string;
586
+ question: string;
587
+ answer: string;
588
+ guardScore: number;
589
+ judgeScore: number;
590
+ guardIssues: { code: string; severity: string; message: string }[];
591
+ judgeNote: string;
592
+ }): Promise<DivergenceSuggestion | null> {
593
+ const prompt = `You are a system-improvement analyst. The V15 Rigor Guard's deterministic gate score and the independent third-party LLM judge score DIVERGED significantly on the following case. Analyze WHY and propose concrete improvements.
594
+
595
+ QUESTION:
596
+ ${opts.question}
597
+
598
+ ANSWER UNDER EVALUATION:
599
+ ${opts.answer.slice(0, 3000)}
600
+
601
+ GUARD SCORE: ${opts.guardScore}/10
602
+ GUARD ISSUES: ${JSON.stringify(opts.guardIssues.slice(0, 10))}
603
+ JUDGE SCORE: ${opts.judgeScore}/10
604
+ JUDGE NOTE: ${opts.judgeNote}
605
+ DELTA: ${(opts.judgeScore - opts.guardScore).toFixed(2)}
606
+
607
+ Produce STRICT JSON:
608
+ {
609
+ "reason": "one paragraph explaining the divergence",
610
+ "category": "missing-gate" | "false-positive-gate" | "rubric-mismatch" | "context-window" | "other",
611
+ "suggestions": [
612
+ { "approach": "new-gate" | "modify-gate" | "extend-flaw-pack" | "adjust-scoring-weights" | "adjust-judge-rubric" | "new-domain-pack" | "other",
613
+ "description": "specific code-level change to implement",
614
+ "estimatedImpact": "low" | "medium" | "high",
615
+ "tradeoffs": "risks or downsides"
616
+ }
617
+ ]
618
+ }
619
+
620
+ Include MULTIPLE suggestions (2-4) when the divergence can plausibly be fixed several ways so an engineer can choose. Return ONLY the JSON.`;
621
+
622
+ const activePool = getActiveRotationPool();
623
+ const res = await generateWithRotation({
624
+ apiKey: opts.apiKey,
625
+ prompt,
626
+ preferredModel: activePool[0],
627
+ maxOutputTokens: 900,
628
+ });
629
+ if (!res.ok) return null;
630
+ try {
631
+ const match = res.text.match(/\{[\s\S]*\}/);
632
+ const j = JSON.parse(match ? match[0] : res.text);
633
+ if (!j.reason || !Array.isArray(j.suggestions)) return null;
634
+ return j as DivergenceSuggestion;
635
+ } catch { return null; }
636
+ }
637
+
638
+ /**
639
+ * Long-Report Cohesion Pass — additive post-processor. Takes a long report
640
+ * (from the real app's 4-Stage / N-Deep / cluster / SLOOP pipeline) and runs
641
+ * a deterministic cohesion audit + rewrite of ONLY defective sections. Never
642
+ * touches non-defective content. Returns the improved text + a diff summary.
643
+ */
644
+ export interface CohesionPassResult {
645
+ original: string;
646
+ improved: string;
647
+ sectionsRewritten: number;
648
+ cohesionIssues: string[];
649
+ ok: boolean;
650
+ error?: string;
651
+ }
652
+
653
+ export async function runCohesionPass(opts: {
654
+ apiKey: string;
655
+ question: string;
656
+ report: string;
657
+ onProgress?: (stage: string) => void;
658
+ }): Promise<CohesionPassResult> {
659
+ const { apiKey, question, report, onProgress } = opts;
660
+
661
+ onProgress?.("cohesion audit");
662
+ // Deterministic issue scan first.
663
+ const cohesionIssues: string[] = [];
664
+ const sections = report.split(/\n(?=#{1,3}\s)/);
665
+ const stubbySections = sections.filter(s => {
666
+ const body = s.replace(/^#{1,3}[^\n]*\n/, "").trim();
667
+ return body.length < 120 || /^\[|^TBD|^\(placeholder\)/i.test(body);
668
+ });
669
+ if (stubbySections.length > 0) cohesionIssues.push(`${stubbySections.length} section(s) below cohesion floor (stub/placeholder/thin).`);
670
+ if (!/^#\s/m.test(report)) cohesionIssues.push("Report lacks an H1 thesis header.");
671
+ if (!/^(##\s.*Executive|##\s.*Summary|##\s.*BLUF|##\s.*TL;DR)/mi.test(report)) cohesionIssues.push("Missing executive-summary / BLUF section.");
672
+ if (!/(?:^|\n)#{1,3}\s.*(?:Conclusion|Recommend|Next Steps|Implications)/mi.test(report)) cohesionIssues.push("Missing conclusion / recommendation section.");
673
+
674
+ if (cohesionIssues.length === 0) {
675
+ onProgress?.("no cohesion issues found");
676
+ return { original: report, improved: report, sectionsRewritten: 0, cohesionIssues: [], ok: true };
677
+ }
678
+
679
+ onProgress?.(`rewriting ${stubbySections.length} defective section(s)`);
680
+ const editorPrompt = `You are a senior report editor. A long-form report was generated. Do a MINIMAL cohesion repair — rewrite ONLY the sections listed as defective, PRESERVE every other section byte-for-byte. Add an executive summary if missing. Add a conclusion if missing. Return the FULL revised report (all sections in original order).
681
+
682
+ USER PROMPT:
683
+ ${question}
684
+
685
+ COHESION ISSUES:
686
+ ${cohesionIssues.map(i => `- ${i}`).join("\n")}
687
+
688
+ REPORT TO REVISE:
689
+ ${report.slice(0, 20000)}`;
690
+
691
+ const activePool = getActiveRotationPool();
692
+ const res = await generateWithRotation({
693
+ apiKey, prompt: editorPrompt,
694
+ preferredModel: activePool[0],
695
+ maxOutputTokens: Math.max(3000, Math.min(8000, report.length / 3 + 1000)),
696
+ });
697
+ if (!res.ok) return { original: report, improved: report, sectionsRewritten: 0, cohesionIssues, ok: false, error: res.error };
698
+ return {
699
+ original: report,
700
+ improved: res.text.trim() || report,
701
+ sectionsRewritten: stubbySections.length,
702
+ cohesionIssues,
703
+ ok: true,
704
+ };
705
+ }
706
+
707
+ export async function runBaselineOnQuestion(opts: {
708
+ apiKey: string;
709
+ question: string;
710
+ draftModel?: string;
711
+ singleJudge?: boolean;
712
+ judgeSampleSize?: number;
713
+ onProgress?: (stage: string) => void;
714
+ }): Promise<V15RunOutcome> {
715
+ const t0 = Date.now();
716
+ const { apiKey, question, draftModel = "gemini-2.5-flash-lite", onProgress } = opts;
717
+
718
+ onProgress?.("drafting baseline");
719
+ const draftRes = await generateWithRotation({
720
+ apiKey, prompt: question, preferredModel: draftModel, maxOutputTokens: 900,
721
+ });
722
+ if (!draftRes.ok) {
723
+ return {
724
+ question, draft: "", fixed: "", issues: [], autoFixesApplied: [],
725
+ guardScore: 0, judgeScore: null, judgeNote: "", modelUsed: draftModel,
726
+ passes: 1, stable: false, totalLatencyMs: Date.now() - t0, error: draftRes.error,
727
+ };
728
+ }
729
+
730
+ onProgress?.("judging baseline");
731
+ let selectedJudgeModels: string[] | undefined;
732
+ const activePool = getActiveRotationPool();
733
+ if (opts.singleJudge) selectedJudgeModels = [activePool[0]];
734
+ else if (opts.judgeSampleSize && opts.judgeSampleSize > 0) selectedJudgeModels = activePool.slice(0, Math.min(opts.judgeSampleSize, activePool.length));
735
+ else selectedJudgeModels = activePool;
736
+ const judgeRun = await parallelJudgeRotation({
737
+ apiKey, question, answer: draftRes.text, judgeModels: selectedJudgeModels,
738
+ });
739
+
740
+ let judgeScore: number | null = null;
741
+ let judgeNote = "";
742
+ let judgeRoster: V15RunOutcome["judgeRoster"] = [];
743
+ if (judgeRun.judgments.length > 0) {
744
+ const elo = calculateEloConsensus(judgeRun.judgments);
745
+ judgeScore = elo.weightedScore;
746
+ judgeNote = elo.rationale;
747
+ }
748
+ judgeRoster = judgeRun.attempts.map(a => {
749
+ const j = judgeRun.judgments.find(x => x.model === a.model);
750
+ return { model: a.model, elo: a.elo, tier: a.tier, ok: a.ok, latencyMs: a.latencyMs, score: j?.score };
751
+ });
752
+
753
+ onProgress?.("done");
754
+ return {
755
+ question,
756
+ draft: draftRes.text,
757
+ fixed: draftRes.text,
758
+ issues: [],
759
+ autoFixesApplied: [],
760
+ guardScore: 0,
761
+ judgeScore,
762
+ judgeNote,
763
+ judgeRoster,
764
+ modelUsed: draftRes.modelUsed,
765
+ passes: 1,
766
+ stable: judgeScore !== null && judgeScore >= 9.0,
767
+ totalLatencyMs: Date.now() - t0,
768
+ };
769
+ }