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,415 @@
1
+ /**
2
+ * self-test.ts — NET-NEW (Type C). See flatten-guide.md.
3
+ * ===========================================================================
4
+ * EXECUTABLE VERIFICATION for the pure workspace primitives.
5
+ *
6
+ * Every function under test here is PURE — no network, no model, no clock —
7
+ * so these are real assertions, not smoke tests. They run in the browser from
8
+ * the Debug Console ("Self-Test" tab) and return structured results.
9
+ *
10
+ * HONESTY: the authoring model cannot execute this file. It is compile-
11
+ * verified only. Running it in the browser is what turns these into evidence.
12
+ * A test that has never been run is a claim, not a verification.
13
+ * ===========================================================================
14
+ */
15
+ import {
16
+ extractCitationIds,
17
+ looksLikeBoilerplate,
18
+ endsOnDanglingConnector,
19
+ computeDeterministicFloor,
20
+ annotateEvidenceStarvedSections,
21
+ insertMissingSectionStubs,
22
+ } from "@/lib/v15-pipeline";
23
+ import {
24
+ extractFacets,
25
+ buildLatticeQueries,
26
+ facetCoherence,
27
+ isLikelyDriftResult,
28
+ renderLatticeDirective,
29
+ enrichLatticeWithLlm,
30
+ } from "@/lib/debug/intent-lattice";
31
+ import { isPlaceholderUrl } from "@/lib/debug/scraper-forensics";
32
+ import {
33
+ extractMainSemanticContent,
34
+ buildAccessibilityTree,
35
+ } from "@/lib/debug/veritas-hybrid-scraper";
36
+ import { ARCHITECTURE_SPEC, prescribe, renderPrescription } from "@/lib/debug/architecture-prescription";
37
+ import { absoluteUrl, dedupeSources, filterRelevantSources, filterRelevantSourcesAny, hardenRetrievalQuery } from "@/lib/debug/retrieval-hardener";
38
+ import { SCRAPER_LANE_ROADMAP } from "@/lib/debug/scraper-lane-roadmap";
39
+ import { clearRetrievalContext, registerRetrievalContext, resolveRetrievalQueries } from "@/lib/debug/retrieval-context";
40
+ import { buildUnifiedInnovationPlan, expandPath, stableSeed } from "@/lib/debug/unified-innovation";
41
+ import { buildDeterministicResearchQueries, longestPromptQuote, queryIsDecomposed } from "@/lib/debug/research-phase";
42
+ import type { RunRecord } from "@/lib/debug/pipeline-trace-bus";
43
+
44
+ export interface TestResult {
45
+ suite: string;
46
+ name: string;
47
+ passed: boolean;
48
+ detail: string;
49
+ }
50
+
51
+ export interface SelfTestReport {
52
+ ranAt: number;
53
+ results: TestResult[];
54
+ passed: number;
55
+ failed: number;
56
+ suites: string[];
57
+ }
58
+
59
+ export async function runSelfTests(): Promise<SelfTestReport> {
60
+ const results: TestResult[] = [];
61
+ let suite = "";
62
+ const check = (name: string, passed: boolean, detail = "") =>
63
+ results.push({ suite, name, passed, detail });
64
+
65
+ // ── Pure text primitives ─────────────────────────────────────────────────
66
+ suite = "text-primitives";
67
+ try {
68
+ check("extractCitationIds: single tags", JSON.stringify(extractCitationIds("a [S1] b [S3]")) === "[1,3]", JSON.stringify(extractCitationIds("a [S1] b [S3]")));
69
+ check("extractCitationIds: grouped tags", JSON.stringify(extractCitationIds("x [S4, S10] y")) === "[4,10]", JSON.stringify(extractCitationIds("x [S4, S10] y")));
70
+ check("extractCitationIds: dedupes", JSON.stringify(extractCitationIds("[S2] [S2] [S2]")) === "[2]", JSON.stringify(extractCitationIds("[S2] [S2] [S2]")));
71
+ check("extractCitationIds: empty on none", extractCitationIds("no citations here").length === 0, "empty array");
72
+
73
+ check("looksLikeBoilerplate: flags CSS reset", looksLikeBoilerplate("table, caption, tbody, tfoot {margin: 0;padding: 0;border: 0;}") === true, "CSS reset detected");
74
+ check("looksLikeBoilerplate: flags font var block", looksLikeBoilerplate("body {font-family: var(--font-Inter);}") === true, "font chrome detected");
75
+ check("looksLikeBoilerplate: keeps real prose", looksLikeBoilerplate("Cannabis use significantly increases heart rate in the minutes following inhalation.") === false, "real content retained");
76
+ check("looksLikeBoilerplate: empty is boilerplate", looksLikeBoilerplate("") === true, "empty rejected");
77
+
78
+ check("endsOnDanglingConnector: flags trailing 'and'", endsOnDanglingConnector("The market is large and") === true, "dangling connector caught");
79
+ check("endsOnDanglingConnector: flags trailing 'because'", endsOnDanglingConnector("This matters because") === true, "dangling connector caught");
80
+ check("endsOnDanglingConnector: clean sentence passes", endsOnDanglingConnector("The market is large.") === false, "complete sentence retained");
81
+ } catch (e) {
82
+ check("text-primitives: threw", false, String(e));
83
+ }
84
+
85
+ // ── Deterministic floor ──────────────────────────────────────────────────
86
+ suite = "deterministic-floor";
87
+ try {
88
+ const perfect = computeDeterministicFloor({ templateCoverage: 1, citationTrustRatio: 1, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: false });
89
+ const broken = computeDeterministicFloor({ templateCoverage: 0.5, citationTrustRatio: 0.2, placeholderDensity: 0.01, placeholderUrlRatio: 0.8, truncated: true });
90
+ check("floor: perfect input caps at 9.5", perfect === 9.5, `perfect = ${perfect}`);
91
+ check("floor: broken input scores low", broken < 4, `broken = ${broken}`);
92
+ check("floor: monotone in template coverage",
93
+ computeDeterministicFloor({ templateCoverage: 1, citationTrustRatio: 0.5, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: false }) >
94
+ computeDeterministicFloor({ templateCoverage: 0.5, citationTrustRatio: 0.5, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: false }),
95
+ "higher coverage ⇒ higher floor");
96
+ check("floor: monotone in citation trust",
97
+ computeDeterministicFloor({ templateCoverage: 1, citationTrustRatio: 1, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: false }) >
98
+ computeDeterministicFloor({ templateCoverage: 1, citationTrustRatio: 0, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: false }),
99
+ "higher trust ⇒ higher floor");
100
+ check("floor: truncation is penalised",
101
+ computeDeterministicFloor({ templateCoverage: 1, citationTrustRatio: 1, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: true }) <
102
+ computeDeterministicFloor({ templateCoverage: 1, citationTrustRatio: 1, placeholderDensity: 0, placeholderUrlRatio: 0, truncated: false }),
103
+ "truncated ⇒ lower floor");
104
+ check("floor: never below 1", computeDeterministicFloor({ templateCoverage: 0, citationTrustRatio: 0, placeholderDensity: 1, placeholderUrlRatio: 1, truncated: true }) >= 1, "floor >= 1");
105
+ check("floor: never above 9.5 (not a judge score)", perfect <= 9.5, "floor <= 9.5 — cannot masquerade as a 10");
106
+ } catch (e) {
107
+ check("deterministic-floor: threw", false, String(e));
108
+ }
109
+
110
+ // ── Placeholder URL classification ───────────────────────────────────────
111
+ suite = "url-classification";
112
+ try {
113
+ check("isPlaceholderUrl: source-N is placeholder", isPlaceholderUrl("source-3") === true, "index-derived url rejected");
114
+ check("isPlaceholderUrl: vanguard-attested is placeholder", isPlaceholderUrl("vanguard-attested") === true, "attestation token rejected");
115
+ check("isPlaceholderUrl: real doi is not placeholder", isPlaceholderUrl("https://doi.org/10.1089/can.2024.0030") === false, "real URL retained");
116
+ check("isPlaceholderUrl: undefined is placeholder", isPlaceholderUrl(undefined) === true, "missing url rejected");
117
+ } catch (e) {
118
+ check("url-classification: threw", false, String(e));
119
+ }
120
+
121
+ // ── insertMissingSectionStubs ────────────────────────────────────────────
122
+ suite = "missing-section-stubs";
123
+ try {
124
+ const partial = "## §1 BLUF\n\nThesis.\n\n## §2 Situation (SCQA)\n\nBaseline.";
125
+ const { text, inserted } = insertMissingSectionStubs(partial, "OMEGA-STRATEGY");
126
+ check("insertMissingSectionStubs: detects the absent Appendix", inserted.includes("Appendix (T-Body)"), `inserted = ${JSON.stringify(inserted)}`);
127
+ check("insertMissingSectionStubs: emits machine-readable open item", text.includes("[MISSING SECTION — please supply]"), "stub marker present");
128
+ check("insertMissingSectionStubs: preserves present sections", text.includes("## §1 BLUF") && text.includes("Baseline."), "no existing content altered");
129
+ check("insertMissingSectionStubs: output grows (insertion-only)", text.length > partial.length, `${partial.length} → ${text.length} chars`);
130
+ const { inserted: none } = insertMissingSectionStubs(text, "OMEGA-STRATEGY");
131
+ check("insertMissingSectionStubs: idempotent (stub now counts as present)", !none.includes("Appendix (T-Body)"), `second pass inserted = ${JSON.stringify(none)}`);
132
+ const { inserted: noTpl } = insertMissingSectionStubs(partial, undefined);
133
+ check("insertMissingSectionStubs: no template ⇒ no-op", noTpl.length === 0, "safe without a template id");
134
+ } catch (e) {
135
+ check("insertMissingSectionStubs: threw", false, String(e));
136
+ }
137
+
138
+ // ── annotateEvidenceStarvedSections ──────────────────────────────────────
139
+ suite = "evidence-starvation";
140
+ try {
141
+ const doc = "## BLUF\n\nClaim without evidence.\n\n## Diagnostic (T-Bar)\n\nMore text.";
142
+ const { text, annotated } = annotateEvidenceStarvedSections(doc, ["BLUF"]);
143
+ check("annotateEvidenceStarvedSections: marks the starved section", annotated.includes("BLUF"), `annotated = ${JSON.stringify(annotated)}`);
144
+ check("annotateEvidenceStarvedSections: emits the marker", text.includes("[EVIDENCE_STARVED]"), "marker present");
145
+ check("annotateEvidenceStarvedSections: leaves other sections alone", text.includes("## Diagnostic (T-Bar)\n\nMore text."), "untouched section preserved");
146
+ const { annotated: again } = annotateEvidenceStarvedSections(text, ["BLUF"]);
147
+ check("annotateEvidenceStarvedSections: idempotent", again.length === 0, `second pass annotated = ${JSON.stringify(again)}`);
148
+ const { annotated: missing } = annotateEvidenceStarvedSections(doc, ["Nonexistent Section"]);
149
+ check("annotateEvidenceStarvedSections: skips absent sections", missing.length === 0, "no phantom annotation");
150
+ } catch (e) {
151
+ check("annotateEvidenceStarvedSections: threw", false, String(e));
152
+ }
153
+
154
+ // ── Intent Facet Lattice ─────────────────────────────────────────────────
155
+ suite = "intent-facet-lattice";
156
+ try {
157
+ const q = "Find me a product that doesn't exist but solves a large unmet demand and can be made using existing technology in the cannabis space";
158
+ const facets = extractFacets(q);
159
+ check("extractFacets: finds the cannabis domain facet", facets.some(f => f.axis === "domain" && f.phrase === "cannabis"), `facets = ${facets.map(f => `${f.axis}:${f.phrase}`).join(", ")}`);
160
+ check("extractFacets: finds the 'existing technology' constraint", facets.some(f => f.axis === "constraint" && /existing technology/.test(f.phrase)), "constraint facet present");
161
+ check("extractFacets: finds the 'unmet demand' constraint", facets.some(f => f.axis === "constraint" && /unmet demand/.test(f.phrase)), "constraint facet present");
162
+ check("extractFacets: deterministic (same input ⇒ same output)", JSON.stringify(extractFacets(q)) === JSON.stringify(facets), "stable across calls");
163
+ check("extractFacets: every phrase is a keyword, not a sentence", facets.every(f => f.phrase.split(/\s+/).length <= 6), "no sentence-length facets");
164
+
165
+ const lattice = buildLatticeQueries(q, ["BLUF", "Diagnostic (T-Bar)"]);
166
+ check("buildLatticeQueries: produces per-section queries",
167
+ lattice.queries.length >= 2 && lattice.queries.some(x => x.section === "Diagnostic (T-Bar)"),
168
+ `queries = ${lattice.queries.map(x => `[${x.section}] ${x.q}`).join(" | ")}`);
169
+ check("buildLatticeQueries: no query is the raw prompt", lattice.queries.every(x => x.q !== q && x.q.length < q.length), "every query is decomposed, not the raw prompt");
170
+ check("buildLatticeQueries: every query anchors on the domain", lattice.queries.every(x => x.q.toLowerCase().includes("cannabis")), "domain anchor present in all queries");
171
+ check("buildLatticeQueries: each query carries facet provenance", lattice.queries.every(x => x.facets.length > 0 && x.axes.length > 0), "provenance attached");
172
+ check("buildLatticeQueries: sections get distinct queries",
173
+ new Set(lattice.queries.map(x => x.q)).size > 1, "queries are not all identical (the observed defect)");
174
+ check("buildLatticeQueries: unknown section falls back to general", buildLatticeQueries(q, ["Totally Unknown Section"]).queries.length > 0, "graceful fallback");
175
+
176
+ const cannabisQuery = lattice.queries[0];
177
+ const onTopic = "Cannabis vaporizer market size and growth 2024";
178
+ const offTopic = "Competitive Landscape and Strategic Adjustments of CHAGEE's Market Share tea beverage";
179
+ check("facetCoherence: on-topic scores higher than off-topic",
180
+ facetCoherence(cannabisQuery, onTopic) > facetCoherence(cannabisQuery, offTopic),
181
+ `on=${facetCoherence(cannabisQuery, onTopic)} off=${facetCoherence(cannabisQuery, offTopic)}`);
182
+ check("facetCoherence: bounded 0..1",
183
+ [onTopic, offTopic, ""].every(t => { const c = facetCoherence(cannabisQuery, t); return c >= 0 && c <= 1; }),
184
+ "score in range");
185
+ check("isLikelyDriftResult: flags the CHAGEE-tea noise result", isLikelyDriftResult(offTopic, cannabisQuery) === true, "known drift pattern detected");
186
+ check("isLikelyDriftResult: keeps the on-topic result", isLikelyDriftResult(onTopic, cannabisQuery) === false, "on-topic retained");
187
+ check("isLikelyDriftResult: flags the CSS-reset blob", isLikelyDriftResult("table, caption, tbody {margin:0;padding:0}", cannabisQuery) === true, "boilerplate is drift");
188
+
189
+ const directive = renderLatticeDirective(lattice);
190
+ check("renderLatticeDirective: contains the lattice header", directive.includes("RETRIEVAL INTENT LATTICE"), "header present");
191
+ check("renderLatticeDirective: lists every query", lattice.queries.every(x => directive.includes(x.q)), "no query dropped from the directive");
192
+ check("renderLatticeDirective: forbids raw-prompt fallback", /do not fall back to the raw user prompt/i.test(directive), "explicit instruction present");
193
+ check("renderLatticeDirective: nothing truncated", !directive.includes("…") && !directive.includes("[truncated]"), "no ellipsis or truncation marker");
194
+ } catch (e) {
195
+ check("intent-facet-lattice: threw", false, String(e));
196
+ }
197
+
198
+ // ── LLM enrichment fail-safe (no network — injected fakes) ───────────────
199
+ suite = "lattice-enrichment-failsafe";
200
+ try {
201
+ const base = buildLatticeQueries("cannabis vaporizer market size 2024", ["BLUF"]);
202
+
203
+ const on429 = await enrichLatticeWithLlm(base, async () => ({ ok: false, text: "", error: "HTTP 429 quota" }));
204
+ check("enrich: 429 returns the deterministic floor unchanged", on429.ok === false && on429.lattice === base, "floor retained on 429");
205
+
206
+ const onGarbage = await enrichLatticeWithLlm(base, async () => ({ ok: true, text: "this is not json at all" }));
207
+ check("enrich: unparseable response keeps the floor", onGarbage.lattice.queries.length === base.queries.length, "floor retained on parse failure");
208
+
209
+ const onThrow = await enrichLatticeWithLlm(base, async () => { throw new Error("network down"); });
210
+ check("enrich: thrown error keeps the floor", onThrow.ok === false && onThrow.lattice === base, "floor retained on throw");
211
+
212
+ const onGood = await enrichLatticeWithLlm(base, async () => ({ ok: true, text: '[{"axis":"metric","phrase":"retail sell-through rate"}]' }));
213
+ check("enrich: valid facets are merged", onGood.ok === true && onGood.lattice.facets.some(f => f.phrase === "retail sell-through rate"), "facet added");
214
+ check("enrich: llmEnriched flag set on success", onGood.lattice.llmEnriched === true, "flag set");
215
+ check("enrich: floor facets survive enrichment", base.facets.every(bf => onGood.lattice.facets.some(f => f.phrase === bf.phrase)), "no deterministic facet removed");
216
+
217
+ const onBadAxis = await enrichLatticeWithLlm(base, async () => ({ ok: true, text: '[{"axis":"nonsense","phrase":"x"}]' }));
218
+ check("enrich: rejects invalid axis", !onBadAxis.lattice.facets.some(f => f.phrase === "x"), "invalid axis dropped");
219
+ } catch (e) {
220
+ check("lattice-enrichment-failsafe: threw", false, String(e));
221
+ }
222
+
223
+ // ── Architecture prescription ────────────────────────────────────────────
224
+ suite = "architecture-prescription";
225
+ try {
226
+ check("spec: every component has a patch anchor", ARCHITECTURE_SPEC.every(c => c.patch.anchor.length > 0), `${ARCHITECTURE_SPEC.length} components`);
227
+ check("spec: every component has a verify predicate", ARCHITECTURE_SPEC.every(c => c.patch.verify.length > 0), "all verifiable");
228
+ check("spec: ceilings are in (0,10]", ARCHITECTURE_SPEC.every(c => c.ceilingWithout > 0 && c.ceilingWithout <= 10), "ceilings sane");
229
+ check("spec: component ids are unique", new Set(ARCHITECTURE_SPEC.map(c => c.id)).size === ARCHITECTURE_SPEC.length, "no duplicate ids");
230
+ check("spec: all four planes represented",
231
+ new Set(ARCHITECTURE_SPEC.map(c => c.plane)).size === 4,
232
+ `planes = ${[...new Set(ARCHITECTURE_SPEC.map(c => c.plane))].join(", ")}`);
233
+
234
+ // Synthetic run reproducing the WORST observed log (guard 4.4).
235
+ const brokenRun = {
236
+ id: "synthetic-broken", mode: "v15", question: "cannabis product market size",
237
+ startedAt: 0, endedAt: 1, status: "complete", events: [], phaseStats: {}, passes: [], sources: [],
238
+ input: {}, finalText: "## BLUF\n\nClaim [S1] with [DATA GAP] value.",
239
+ guardScore: 4.4, judgeScore: null,
240
+ output: {
241
+ runSettings: { templateId: "OMEGA-STRATEGY", depth: 4 },
242
+ judgeExcluded: [{ model: "gemini-2.5-pro", reason: "429" }],
243
+ citationAudit: { entries: [{ id: 1, url: "source-1", title: "PCB failure analysis" }], totalCitations: 1, trustedCount: 0, untrustedCount: 1 },
244
+ },
245
+ } as unknown as RunRecord;
246
+
247
+ const p = prescribe(brokenRun);
248
+ check("prescribe: projects a ceiling below 9 for the broken run", p.projectedCeiling < 9, `projectedCeiling = ${p.projectedCeiling}`);
249
+ check("prescribe: names a binding constraint", p.bindingConstraint !== null, `binding = ${p.bindingConstraint?.id}`);
250
+ check("prescribe: ceiling equals the MIN over absent components (not a sum)",
251
+ p.ordered.length === 0 || p.projectedCeiling === Math.min(...p.ordered.map(a => a.component.ceilingWithout)),
252
+ `ceiling=${p.projectedCeiling} min=${p.ordered.length ? Math.min(...p.ordered.map(a => a.component.ceilingWithout)) : "n/a"}`);
253
+ check("prescribe: detects the placeholder-URL break",
254
+ p.assessments.some(a => a.component.id === "url-backed-provenance" && (a.presence === "absent" || a.presence === "degraded")),
255
+ "provenance flagged");
256
+ check("prescribe: detects the surviving bare placeholder",
257
+ p.assessments.some(a => a.component.id === "placeholder-resolution-gate" && a.presence === "absent"),
258
+ "placeholder gate flagged");
259
+ check("prescribe: detects the missing intent lattice",
260
+ p.assessments.some(a => a.component.id === "intent-decomposition" && a.presence === "absent"),
261
+ "lattice absence flagged");
262
+ check("prescribe: detects the missing judge signal",
263
+ p.assessments.some(a => a.component.id === "independent-or-floor-signal" && a.presence === "absent"),
264
+ "judge/floor gap flagged");
265
+ check("prescribe: splits reachability", p.workspaceToday.length + p.needsPackageEdit.length === p.ordered.length, "split is exhaustive");
266
+ check("prescribe: ordered is ascending by ceiling",
267
+ p.ordered.every((a, i) => i === 0 || p.ordered[i - 1].component.ceilingWithout <= a.component.ceilingWithout),
268
+ "most-blocking first");
269
+
270
+ const md = renderPrescription(p);
271
+ check("renderPrescription: emits the ceiling model", md.includes("MIN(ceilingWithout)"), "model stated");
272
+ check("renderPrescription: states the honesty caveat", /calibrated estimate|NOT measured bounds/i.test(md), "estimate disclosed");
273
+ check("renderPrescription: names files and anchors", md.includes("anchor:") && md.includes("file:"), "actionable coordinates present");
274
+
275
+ // A healthy synthetic run must NOT be told to fix everything.
276
+ const healthyRun = {
277
+ ...brokenRun, id: "synthetic-healthy",
278
+ finalText: "## BLUF\n\nClaim [S1].\n\n## Situation (SCQA)\n\nx\n\n## Diagnostic (T-Bar)\n\nx\n\n## Options Tournament\n\nx\n\n## Recommendation & Value Bridge\n\nx\n\n## Implementation (Wave Architecture)\n\nx\n\n## Risk Register & Assumption Ledger\n\nx\n\n## Appendix (T-Body)\n\nx",
279
+ events: [
280
+ { seq: 1, ts: 0, dt: 0, phase: "init", source: "system", message: "G7 Intent Facet Lattice · 9 facets · 16 per-section queries" },
281
+ { seq: 2, ts: 0, dt: 1, phase: "grounding", source: "progress", message: "workspace-relevance-gate: portfolio accepted 2, rejected 0" },
282
+ ],
283
+ guardScore: 9.1,
284
+ output: {
285
+ ...(brokenRun.output as Record<string, unknown>),
286
+ judgeScore: 9.2,
287
+ citationAudit: { entries: [{ id: 1, url: "https://doi.org/10.1089/can.2024.0030", title: "cannabis market" }], totalCitations: 1, trustedCount: 1, untrustedCount: 0 },
288
+ },
289
+ } as unknown as RunRecord;
290
+ const ph = prescribe(healthyRun);
291
+ check("prescribe: healthy run projects a higher ceiling than broken", ph.projectedCeiling > p.projectedCeiling, `healthy=${ph.projectedCeiling} broken=${p.projectedCeiling}`);
292
+ check("prescribe: healthy run detects the lattice as present",
293
+ ph.assessments.some(a => a.component.id === "intent-decomposition" && a.presence === "present"), "lattice present");
294
+ check("prescribe: healthy run has no bare-placeholder defect",
295
+ ph.assessments.some(a => a.component.id === "placeholder-resolution-gate" && a.presence === "present"), "placeholders clean");
296
+ } catch (e) {
297
+ check("architecture-prescription: threw", false, String(e));
298
+ }
299
+
300
+ // ── Veritas Hybrid Scraper Engine ───────────────────────────────────────
301
+ suite = "veritas-hybrid-scraper";
302
+ try {
303
+ const testHtml = `
304
+ <!doctype html>
305
+ <html>
306
+ <head><title>Test Article Title</title></head>
307
+ <body>
308
+ <main>
309
+ <article>
310
+ <h1>Main Topic of Interest</h1>
311
+ <p>This is the main semantic body text representing highly relevant evidence.</p>
312
+ <a href="https://doi.org/10.1089/can.2024.0030" title="THC study">Read the cannabis heart-rate study</a>
313
+ <button id="buy" role="button">Purchase product</button>
314
+ </article>
315
+ </main>
316
+ </body>
317
+ </html>
318
+ `;
319
+ const parsed = extractMainSemanticContent(testHtml);
320
+ check("hybrid-scraper: parses correct title", parsed.title === "Test Article Title", parsed.title);
321
+ check("hybrid-scraper: extracts main paragraph text", parsed.body.includes("highly relevant evidence"), parsed.body);
322
+
323
+ const { tree, nodes } = buildAccessibilityTree(testHtml);
324
+ check("hybrid-scraper: builds PinchTab-style tree", tree.includes("HEADING") && tree.includes("LINK") && tree.includes("BUTTON"), tree);
325
+ check("hybrid-scraper: parses link node with correct absolute url", nodes.some(n => n.role === "link" && n.url === "https://doi.org/10.1089/can.2024.0030"), JSON.stringify(nodes));
326
+ } catch (e) {
327
+ check("veritas-hybrid-scraper: threw", false, String(e));
328
+ }
329
+
330
+ // ── Retrieval hardener + lane roadmap ───────────────────────────────────
331
+ suite = "retrieval-hardener";
332
+ try {
333
+ const query = "Find a cannabis product using existing technology for a large unmet demand";
334
+ const h = hardenRetrievalQuery(query, "Diagnostic (T-Bar)");
335
+ check("hardener: emits compact whole-token query", h.query.length > 5 && h.query.length < query.length, h.query);
336
+ check("hardener: preserves cannabis domain anchor", /cannabis/i.test(h.query), h.query);
337
+ check("hardener: emits alternatives", h.alternatives.length >= 1, `${h.alternatives.length} alternatives`);
338
+
339
+ const good = {
340
+ title: "Cannabis product market and cannabinoid delivery technology",
341
+ url: "https://doi.org/10.1089/can.2024.0030",
342
+ content: "Cannabis cannabinoid delivery technology addresses product safety and market demand. ".repeat(3),
343
+ };
344
+ const tea = {
345
+ title: "Competitive Landscape of CHAGEE Tea Beverages",
346
+ url: "https://example.com/tea",
347
+ content: "Tea beverage market competition and store growth. ".repeat(3),
348
+ };
349
+ const fake = { title: "Cannabis claim", url: "source-1", content: "Cannabis market claim. ".repeat(5) };
350
+ const css = { title: "CSS", url: "https://example.com/css", content: "table, caption, tbody {margin:0;padding:0;border:0;}".repeat(3) };
351
+ const gated = filterRelevantSources([good, tea, fake, css], h.latticeQuery);
352
+ check("hardener: keeps on-topic URL-backed source", gated.accepted.includes(good), `accepted=${gated.accepted.length}`);
353
+ check("hardener: rejects CHAGEE tea drift", gated.rejected.some((r) => r.source === tea && r.reason === "facet-drift"), JSON.stringify(gated.rejected.map((r) => r.reason)));
354
+ check("hardener: rejects source-N URL", gated.rejected.some((r) => r.source === fake && r.reason === "non-resolvable-url"), "placeholder URL rejected");
355
+ check("hardener: rejects thin/CSS content", gated.rejected.some((r) => r.source === css), "boilerplate rejected");
356
+ check("absoluteUrl: normalizes bare DOI", absoluteUrl({ doi: "10.1089/can.2024.0030" }) === "https://doi.org/10.1089/can.2024.0030", absoluteUrl({ doi: "10.1089/can.2024.0030" }));
357
+ check("dedupeSources: dedupes by absolute URL", dedupeSources([good, { ...good }]).length === 1, "one retained");
358
+
359
+ const full = buildLatticeQueries(query, ["BLUF", "Diagnostic (T-Bar)"], 2);
360
+ registerRetrievalContext("test-run", query, full);
361
+ const resolved = resolveRetrievalQueries("market size growth", "general");
362
+ check("context: recovers full-prompt lattice from truncated/package query", !!resolved && resolved.original === query, resolved?.original ?? "none");
363
+ check("context: selects section-relevant alternatives", !!resolved && resolved.queries.some((q) => /market size|TAM|SOM/i.test(q.q)), resolved?.queries.map((q) => q.q).join(" | ") ?? "none");
364
+ const anyGate = filterRelevantSourcesAny([good, tea], resolved?.queries ?? [h.latticeQuery]);
365
+ check("hardener-any: accepts against any coherent facet alternative", anyGate.accepted.includes(good), `accepted=${anyGate.accepted.length}`);
366
+ check("hardener-any: still rejects drift across every alternative", anyGate.rejected.some((r) => r.source === tea), `rejected=${anyGate.rejected.length}`);
367
+ clearRetrievalContext("test-run");
368
+
369
+ check("roadmap: covers >=12 mechanisms", SCRAPER_LANE_ROADMAP.length >= 12, `${SCRAPER_LANE_ROADMAP.length} entries`);
370
+ check("roadmap: every lane has file + falsification test", SCRAPER_LANE_ROADMAP.every((r) => r.workspaceFile && r.test), "all actionable");
371
+ check("roadmap: all live @-imported terminal lanes hardened",
372
+ ["vanguard", "palisade", "arbiter-omega", "sibyl", "strata", "nexus", "hydra", "native-vnext"].every((lane) =>
373
+ SCRAPER_LANE_ROADMAP.some((r) => r.lane === lane && r.status !== "observability-only")
374
+ ), "terminal lanes covered");
375
+ } catch (e) {
376
+ check("retrieval-hardener: threw", false, String(e));
377
+ }
378
+
379
+ // ── Unified v1+v2 genome + separated research planner ───────────────────
380
+ suite = "unified-innovation-research";
381
+ try {
382
+ const prompt = "Find me a product that doesn't exist but solves a large unmet demand and can be made using existing technology in the cannabis space";
383
+ const seedA = stableSeed(prompt, "product");
384
+ const seedB = stableSeed(prompt, "product");
385
+ check("unified: stable seed deterministic", seedA === seedB, `${seedA}`);
386
+ const plan = buildUnifiedInnovationPlan(prompt, { seed: seedA, personaSeed: seedA });
387
+ check("unified: v1 and v2 share one seed", plan.base.seed === plan.expansion.seed && plan.seed === seedA, `${plan.base.seed}/${plan.expansion.seed}`);
388
+ check("unified: v2 labelled expansion pack", /V2 IS AN EXPANSION PACK/.test(plan.directive), "explicit contract");
389
+ check("unified: path has full words", /Problem Choice|Anomaly Valuation|Evaluator Revision/.test(plan.expandedPath), plan.expandedPath);
390
+ check("unified: prompt contains no arrow abbreviations", !/[PAENVTS]→[PAENVTS]/.test(plan.directive), "expanded only");
391
+ check("unified: six exploration branches", plan.exploration.length === 6, `${plan.exploration.length}`);
392
+ check("unified: every branch path expanded", plan.exploration.every((b) => /1\. /.test(b.expandedPath) && !b.expandedPath.includes("→")), "full words");
393
+ check("unified: Williams persona shares seed", plan.williams.seed === seedA, `${plan.williams.seed}`);
394
+ check("expandPath: maps canonical symbols", expandPath({ id: "x", name: "test", seq: "P→V→A" }).includes("Evaluator Revision"), expandPath({ id: "x", name: "test", seq: "P→V→A" }));
395
+
396
+ const queries = buildDeterministicResearchQueries(prompt, plan);
397
+ check("research: starts with pain points", queries[0]?.kind === "pain-point", queries[0]?.kind ?? "none");
398
+ check("research: includes complaints + failed workarounds", queries.some((q) => q.kind === "complaint") && queries.some((q) => q.kind === "failed-workaround"), queries.map((q) => q.kind).join(","));
399
+ check("research: every query passes no-quote invariant", queries.every((q) => queryIsDecomposed(prompt, q.query)), queries.map((q) => longestPromptQuote(prompt, q.query)).join(","));
400
+ check("research: no query copies >3 prompt words", queries.every((q) => longestPromptQuote(prompt, q.query) <= 3), `max=${Math.max(...queries.map((q) => longestPromptQuote(prompt, q.query)))}`);
401
+ check("research: path nodes use full words", queries.every((q) => !/^[PAENVTS]$/.test(q.pathNode)), queries.map((q) => q.pathNode).join(" | "));
402
+ check("research: rejects raw prompt as query", !queryIsDecomposed(prompt, prompt), `quoteRun=${longestPromptQuote(prompt, prompt)}`);
403
+ } catch (e) {
404
+ check("unified-innovation-research: threw", false, String(e));
405
+ }
406
+
407
+ const passed = results.filter(r => r.passed).length;
408
+ return {
409
+ ranAt: Date.now(),
410
+ results,
411
+ passed,
412
+ failed: results.length - passed,
413
+ suites: [...new Set(results.map(r => r.suite))],
414
+ };
415
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * step-attribution.ts — NET-NEW (Type C). See flatten-guide.md.
3
+ * ===========================================================================
4
+ * ANSWERS "which pipeline step wrote this sentence?"
5
+ *
6
+ * The V15 pipeline records intermediate texts at each stage. This module
7
+ * walks them in the ORDER they were produced and assigns each final-output
8
+ * sentence to the earliest stage where a sufficiently-similar sentence first
9
+ * appeared. That earliest match is the stage that ORIGINATED the sentence;
10
+ * any later stage that changed it also earns a "modified" attribution.
11
+ *
12
+ * Attribution stages (from actual pipeline traces, verbatim):
13
+ * outline — best-of-N outline candidates
14
+ * draft — expansion of the winning outline
15
+ * depth-N — each accepted repair pass in passHistory (N = 1..maxDepth)
16
+ * adv-repair — adversarial monotonic repair, if accepted
17
+ * polish — polish pass, if applied
18
+ * covea — targeted CoVe/Adversarial repair we run in this workspace
19
+ *
20
+ * Similarity metric: token Jaccard on a normalised sentence. Tolerates
21
+ * whitespace, punctuation, casing, minor edits (≤~30% token drift).
22
+ * ===========================================================================
23
+ */
24
+
25
+ export type StageKind =
26
+ | "outline"
27
+ | "draft"
28
+ | "depth"
29
+ | "adv-repair"
30
+ | "polish"
31
+ | "covea";
32
+
33
+ export interface StageSnapshot {
34
+ kind: StageKind;
35
+ label: string;
36
+ order: number;
37
+ text: string;
38
+ }
39
+
40
+ export interface SentenceAttribution {
41
+ index: number;
42
+ sentence: string;
43
+ originStage: StageSnapshot | null;
44
+ modifiedByStages: StageSnapshot[];
45
+ /** How much of the sentence's tokens survive to the final version (0..1). */
46
+ survivalScore: number;
47
+ }
48
+
49
+ export interface AttributionReport {
50
+ stages: StageSnapshot[];
51
+ sentences: SentenceAttribution[];
52
+ /** Aggregate: how many final sentences each stage originated. */
53
+ originCounts: Record<string, number>;
54
+ /** Aggregate: how many final sentences each stage modified. */
55
+ modifiedCounts: Record<string, number>;
56
+ /** Sentences whose origin we could not locate — usually the model added them ex nihilo. */
57
+ unattributed: number;
58
+ }
59
+
60
+ // ── Sentence split & normalise ─────────────────────────────────────────────
61
+
62
+ const SENT_SPLIT = /(?<=[.!?])\s+(?=[A-Z0-9*\-#[])/g;
63
+ export function splitSentences(text: string): string[] {
64
+ if (!text) return [];
65
+ return text
66
+ .replace(/\r\n/g, "\n")
67
+ .split(SENT_SPLIT)
68
+ .map((s) => s.trim())
69
+ .filter((s) => s.length > 0);
70
+ }
71
+
72
+ function tokens(s: string): Set<string> {
73
+ return new Set(
74
+ s
75
+ .toLowerCase()
76
+ .replace(/\[[Ss]?\d+\]/g, "") // strip citation markers so citation churn does not count
77
+ .match(/[a-z0-9][a-z0-9'-]{1,}/g) ?? []
78
+ );
79
+ }
80
+
81
+ function jaccard(a: Set<string>, b: Set<string>): number {
82
+ if (a.size === 0 && b.size === 0) return 1;
83
+ if (a.size === 0 || b.size === 0) return 0;
84
+ let inter = 0;
85
+ for (const t of a) if (b.has(t)) inter++;
86
+ return inter / (a.size + b.size - inter);
87
+ }
88
+
89
+ // ── Build stage list from a RunRecord's outcome ────────────────────────────
90
+
91
+ export function buildStages(input: {
92
+ bestOfNCandidates?: Array<{ index: number; snippet?: string; charCount?: number; chosen?: boolean; stage?: string }>;
93
+ draft?: string;
94
+ passHistory?: Array<{ text?: string; pass?: number; note?: string; guardScore?: number }>;
95
+ advRepairText?: string;
96
+ polishText?: string;
97
+ coveaText?: string;
98
+ }): StageSnapshot[] {
99
+ const out: StageSnapshot[] = [];
100
+ let order = 0;
101
+ if (Array.isArray(input.bestOfNCandidates)) {
102
+ for (const c of input.bestOfNCandidates) {
103
+ if (c.snippet && c.chosen) {
104
+ out.push({ kind: "outline", label: `outline #${(c.index ?? 0) + 1} (chosen)`, order: order++, text: c.snippet });
105
+ }
106
+ }
107
+ }
108
+ if (input.draft) out.push({ kind: "draft", label: "best-of-N expansion", order: order++, text: input.draft });
109
+ if (Array.isArray(input.passHistory)) {
110
+ input.passHistory.forEach((p, i) => {
111
+ if (typeof p.text === "string" && p.text.length > 0) {
112
+ out.push({
113
+ kind: "depth",
114
+ label: `depth ${p.pass ?? i + 1}${p.note ? ` (${p.note})` : ""}${p.guardScore != null ? ` · guard=${p.guardScore.toFixed(2)}` : ""}`,
115
+ order: order++,
116
+ text: p.text,
117
+ });
118
+ }
119
+ });
120
+ }
121
+ if (input.advRepairText) out.push({ kind: "adv-repair", label: "adversarial repair", order: order++, text: input.advRepairText });
122
+ if (input.polishText) out.push({ kind: "polish", label: "polish pass", order: order++, text: input.polishText });
123
+ if (input.coveaText) out.push({ kind: "covea", label: "COVEA targeted repair", order: order++, text: input.coveaText });
124
+ return out;
125
+ }
126
+
127
+ // ── Attribute each final sentence ──────────────────────────────────────────
128
+
129
+ const SIM_THRESHOLD_ORIGIN = 0.62; // sentence considered "same" across stages
130
+ const SIM_THRESHOLD_MODIFIED = 0.4; // sentence considered "modified but derived"
131
+
132
+ export function attributeSentences(
133
+ finalText: string,
134
+ stages: StageSnapshot[]
135
+ ): AttributionReport {
136
+ const finals = splitSentences(finalText);
137
+ // Precompute stage sentence token sets, keeping ordering.
138
+ const stageSentences = stages.map((s) => {
139
+ const sents = splitSentences(s.text);
140
+ return { stage: s, sents, toks: sents.map(tokens) };
141
+ });
142
+
143
+ const originCounts: Record<string, number> = {};
144
+ const modifiedCounts: Record<string, number> = {};
145
+ let unattributed = 0;
146
+
147
+ const sentences: SentenceAttribution[] = finals.map((sent, idx) => {
148
+ const ft = tokens(sent);
149
+ // Earliest stage where a similar sentence appears = origin.
150
+ let origin: StageSnapshot | null = null;
151
+ let originSurv = 0;
152
+ const modifiedBy: StageSnapshot[] = [];
153
+
154
+ for (const { stage, toks } of stageSentences) {
155
+ let best = 0;
156
+ for (const st of toks) {
157
+ const j = jaccard(ft, st);
158
+ if (j > best) best = j;
159
+ }
160
+ if (best >= SIM_THRESHOLD_ORIGIN) {
161
+ if (!origin) {
162
+ origin = stage;
163
+ originSurv = best;
164
+ } else if (best < 0.98) {
165
+ // Later stage differs enough → counts as a modification of this sentence.
166
+ modifiedBy.push(stage);
167
+ }
168
+ } else if (best >= SIM_THRESHOLD_MODIFIED && origin) {
169
+ modifiedBy.push(stage);
170
+ }
171
+ }
172
+
173
+ if (origin) {
174
+ originCounts[originLabel(origin)] = (originCounts[originLabel(origin)] ?? 0) + 1;
175
+ } else {
176
+ unattributed++;
177
+ }
178
+ for (const m of modifiedBy) {
179
+ modifiedCounts[originLabel(m)] = (modifiedCounts[originLabel(m)] ?? 0) + 1;
180
+ }
181
+
182
+ return {
183
+ index: idx,
184
+ sentence: sent,
185
+ originStage: origin,
186
+ modifiedByStages: modifiedBy,
187
+ survivalScore: originSurv,
188
+ };
189
+ });
190
+
191
+ return { stages, sentences, originCounts, modifiedCounts, unattributed };
192
+ }
193
+
194
+ function originLabel(s: StageSnapshot): string {
195
+ return `${s.kind}:${s.order}:${s.label}`;
196
+ }
197
+
198
+ /** Group sentences that trace back to the same stage — useful for the UI. */
199
+ export function bucketByOrigin(report: AttributionReport): Array<{
200
+ stage: StageSnapshot | null;
201
+ sentences: SentenceAttribution[];
202
+ }> {
203
+ const map = new Map<string, { stage: StageSnapshot | null; sentences: SentenceAttribution[] }>();
204
+ for (const s of report.sentences) {
205
+ const key = s.originStage ? originLabel(s.originStage) : "(unattributed)";
206
+ const bucket = map.get(key) ?? { stage: s.originStage, sentences: [] };
207
+ bucket.sentences.push(s);
208
+ map.set(key, bucket);
209
+ }
210
+ return [...map.values()];
211
+ }