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,678 @@
1
+ /**
2
+ * prompt-forge.ts — NET-NEW WORKSPACE MODULE (Type C seam)
3
+ * ===========================================================================
4
+ * SELF-IMPROVEMENT ENGINE
5
+ *
6
+ * Intent: paste in an output produced by the logic system (or by any other
7
+ * LLM), and get back a SPECIFIC, ADDRESSED diagnosis of which part of the
8
+ * prompt is capping the score — plus a concrete patch that should move a
9
+ * third-party judge from ~6-7 to 9-10.
10
+ *
11
+ * DESIGN PROVENANCE (web-researched, 2026)
12
+ * · ProTeGi / TextGrad — "textual gradients": an LLM critiques failing
13
+ * examples; the critique is applied as an edit. Most interpretable family.
14
+ * We implement the critique→patch step and expose the critique verbatim.
15
+ * · OPRO — condition the optimizer on a (prompt, score) TRAJECTORY rather
16
+ * than a single critique. We persist a score history per prompt lineage.
17
+ * · GEPA — reflection over traces with a Pareto front across multiple
18
+ * objectives. We keep all rubric dimensions separate and never collapse
19
+ * them into a single number before showing the user the breakdown.
20
+ * · Prometheus-2 — judges need EXPLICIT custom rubrics with per-dimension
21
+ * anchors, or they score on vibes.
22
+ *
23
+ * THE KNOWN FAILURE MODE, HANDLED EXPLICITLY
24
+ * "The optimizer is only as good as the signal it maximizes. A vague or
25
+ * biased scorer produces a prompt that games the scorer, not a better
26
+ * prompt." — Automatic Prompt Optimization in 2026 (futureagi.com, 2026-05-29)
27
+ *
28
+ * Mitigation implemented here:
29
+ * 1. A DETERMINISTIC scorer runs ALWAYS. It is pure text analysis — no
30
+ * model, no network, fully reproducible, cannot be flattered.
31
+ * 2. The LLM judge is OPTIONAL and runs against an explicit anchored
32
+ * rubric with a forced JSON contract.
33
+ * 3. Both are displayed side by side. DIVERGENCE IS SURFACED, never
34
+ * averaged away. A large gap means the judge is being gamed OR the
35
+ * deterministic proxy is blind — either way the user must look.
36
+ * ===========================================================================
37
+ */
38
+
39
+ import { geminiGenerate } from '@/lib/v15-gemini';
40
+ import { getGeminiKey } from "@/lib/v15-state";
41
+
42
+ // ───────────────────────────────────────────────────────────────────────────
43
+ // PROMPT REGIONS — the addressable "parameters" of the prompt
44
+ // ───────────────────────────────────────────────────────────────────────────
45
+ // A diagnosis is only useful if it points at a SPECIFIC region. These are the
46
+ // levers; every rubric dimension is wired to the regions that control it.
47
+
48
+ export type RegionId =
49
+ | "ROLE"
50
+ | "TASK"
51
+ | "CONTEXT"
52
+ | "EVIDENCE_POLICY"
53
+ | "CONSTRAINTS"
54
+ | "DEPTH"
55
+ | "FORMAT"
56
+ | "EXAMPLES"
57
+ | "TONE"
58
+ | "STOP_CONDITION";
59
+
60
+ export interface RegionMeta {
61
+ id: RegionId;
62
+ label: string;
63
+ controls: string;
64
+ }
65
+
66
+ export const REGIONS: RegionMeta[] = [
67
+ { id: "ROLE", label: "Role / Persona", controls: "Expertise register, vocabulary, standard-of-care." },
68
+ { id: "TASK", label: "Task Statement", controls: "What is actually being asked; scope boundaries." },
69
+ { id: "CONTEXT", label: "Context Block", controls: "Background the model may assume." },
70
+ { id: "EVIDENCE_POLICY", label: "Evidence Policy", controls: "Citation requirements, source tiering, unknown-handling." },
71
+ { id: "CONSTRAINTS", label: "Hard Constraints", controls: "Must/must-not rules, exclusions, comparison targets." },
72
+ { id: "DEPTH", label: "Depth Directive", controls: "Length, granularity, how far to decompose." },
73
+ { id: "FORMAT", label: "Output Format", controls: "Structure, headings, tables, schema." },
74
+ { id: "EXAMPLES", label: "Few-shot Exemplars", controls: "Demonstrated quality bar." },
75
+ { id: "TONE", label: "Tone / Style", controls: "Hedging level, directness, audience." },
76
+ { id: "STOP_CONDITION", label: "Stop Condition", controls: "When the answer is done; anti-truncation." },
77
+ ];
78
+
79
+ // ───────────────────────────────────────────────────────────────────────────
80
+ // RUBRIC — anchored, multi-dimensional, weighted
81
+ // ───────────────────────────────────────────────────────────────────────────
82
+
83
+ export interface RubricDim {
84
+ id: string;
85
+ label: string;
86
+ weight: number;
87
+ /** Which prompt regions move this dimension. */
88
+ regions: RegionId[];
89
+ /** Explicit anchors — Prometheus-2 style. Vague rubrics produce vibe scores. */
90
+ anchor3: string;
91
+ anchor7: string;
92
+ anchor10: string;
93
+ }
94
+
95
+ export const RUBRIC: RubricDim[] = [
96
+ {
97
+ id: "grounding", label: "Evidence Grounding", weight: 1.6, regions: ["EVIDENCE_POLICY", "CONSTRAINTS"],
98
+ anchor3: "Assertions float free; no sources, no uncertainty marks.",
99
+ anchor7: "Some claims sourced; several load-bearing claims still unattributed.",
100
+ anchor10: "Every load-bearing claim carries a source or an explicit [UNVERIFIED]/[ASSUMPTION] tag.",
101
+ },
102
+ {
103
+ id: "specificity", label: "Specificity", weight: 1.5, regions: ["TASK", "DEPTH", "EXAMPLES"],
104
+ anchor3: "Generic advice that would apply to any question in the domain.",
105
+ anchor7: "Concrete in places, generic in others; named entities sparse.",
106
+ anchor10: "Named entities, exact figures with units, versions, and thresholds throughout.",
107
+ },
108
+ {
109
+ id: "structure", label: "Structure", weight: 1.0, regions: ["FORMAT", "DEPTH"],
110
+ anchor3: "Undifferentiated prose wall.",
111
+ anchor7: "Headings present but hierarchy inconsistent; no scannable summary.",
112
+ anchor10: "Clear hierarchy, tables where comparative, front-loaded answer.",
113
+ },
114
+ {
115
+ id: "directness", label: "Directness", weight: 1.3, regions: ["TONE", "ROLE", "STOP_CONDITION"],
116
+ anchor3: "Hedged into meaninglessness; refuses to commit.",
117
+ anchor7: "Commits, but padded with disclaimers and throat-clearing.",
118
+ anchor10: "Answer first, then support. Hedges only where genuinely uncertain.",
119
+ },
120
+ {
121
+ id: "completeness", label: "Completeness", weight: 1.4, regions: ["TASK", "CONSTRAINTS", "STOP_CONDITION"],
122
+ anchor3: "Ignores most of what was asked.",
123
+ anchor7: "Covers the main ask; misses sub-questions or edge cases.",
124
+ anchor10: "Every clause of the request addressed, including implicit sub-questions.",
125
+ },
126
+ {
127
+ id: "depth", label: "Analytical Depth", weight: 1.5, regions: ["DEPTH", "ROLE", "EXAMPLES"],
128
+ anchor3: "Restates the question with definitions.",
129
+ anchor7: "One level of causal reasoning; no mechanism, no second-order effects.",
130
+ anchor10: "Mechanism-level reasoning, trade-offs quantified, second-order effects named.",
131
+ },
132
+ {
133
+ id: "actionability", label: "Actionability", weight: 1.2, regions: ["TASK", "FORMAT"],
134
+ anchor3: "Nothing the reader can do next.",
135
+ anchor7: "Recommendations present but unprioritised and unowned.",
136
+ anchor10: "Prioritised next steps with thresholds, owners, and verification method.",
137
+ },
138
+ {
139
+ id: "calibration", label: "Calibration", weight: 1.2, regions: ["EVIDENCE_POLICY", "TONE"],
140
+ anchor3: "Uniform false confidence, or uniform hedging.",
141
+ anchor7: "Some uncertainty flagged, but confidence not differentiated by claim.",
142
+ anchor10: "Confidence varies per claim and matches actual evidence strength.",
143
+ },
144
+ {
145
+ id: "nonredundancy", label: "Non-Redundancy", weight: 0.9, regions: ["FORMAT", "STOP_CONDITION"],
146
+ anchor3: "Same point restated in three sections.",
147
+ anchor7: "Noticeable repetition in summary/conclusion.",
148
+ anchor10: "Every paragraph adds new information.",
149
+ },
150
+ {
151
+ id: "compliance", label: "Format Compliance", weight: 1.0, regions: ["FORMAT", "CONSTRAINTS"],
152
+ anchor3: "Ignores the requested shape entirely.",
153
+ anchor7: "Roughly the right shape; some required elements missing.",
154
+ anchor10: "Exactly the requested structure, nothing extra, nothing missing.",
155
+ },
156
+ ];
157
+
158
+ // ───────────────────────────────────────────────────────────────────────────
159
+ // DETERMINISTIC SCORER — no model, no network, fully reproducible
160
+ // ───────────────────────────────────────────────────────────────────────────
161
+
162
+ const HEDGES = [
163
+ "might", "may", "could", "perhaps", "possibly", "arguably", "somewhat", "generally",
164
+ "typically", "often", "sometimes", "it depends", "in some cases", "relatively",
165
+ "fairly", "quite", "rather", "tends to", "can be seen as", "to some extent",
166
+ ];
167
+ const FILLER = [
168
+ "it is important to note", "it's important to note", "it is worth noting",
169
+ "in today's world", "in conclusion", "as an ai", "i hope this helps",
170
+ "let's dive in", "delve into", "navigating the", "in the realm of",
171
+ "it's worth mentioning", "at the end of the day",
172
+ ];
173
+ const ACTION_MARKERS = [
174
+ "next step", "recommend", "should", "must", "action", "implement", "verify",
175
+ "measure", "threshold", "owner", "deadline", "checklist", "step 1", "priority",
176
+ ];
177
+ const UNCERTAINTY_TAGS = [
178
+ "[unverified]", "[assumption]", "[assumed]", "[estimate]", "[post-cutoff]",
179
+ "[unknown]", "unverified", "cannot verify", "no source",
180
+ ];
181
+
182
+ function words(t: string): string[] {
183
+ return t.toLowerCase().match(/[a-z0-9][a-z0-9'-]*/g) ?? [];
184
+ }
185
+ function countOccurrences(hay: string, needles: string[]): number {
186
+ const l = hay.toLowerCase();
187
+ let n = 0;
188
+ for (const nd of needles) {
189
+ let i = 0;
190
+ for (;;) {
191
+ const j = l.indexOf(nd, i);
192
+ if (j === -1) break;
193
+ n++;
194
+ i = j + nd.length;
195
+ }
196
+ }
197
+ return n;
198
+ }
199
+ /** Map an unbounded density to 0-10 with a target band. */
200
+ function band(v: number, lo: number, hi: number): number {
201
+ if (v <= 0) return 1;
202
+ if (v < lo) return 1 + 9 * (v / lo) * 0.55;
203
+ if (v > hi) return Math.max(3, 10 - 6 * Math.min(1, (v - hi) / (hi * 2)));
204
+ return 5.5 + 4.5 * ((v - lo) / Math.max(1e-9, hi - lo));
205
+ }
206
+
207
+ export interface DimScore {
208
+ id: string;
209
+ label: string;
210
+ score: number;
211
+ weight: number;
212
+ evidence: string;
213
+ }
214
+
215
+ export interface ScoreReport {
216
+ overall: number;
217
+ dims: DimScore[];
218
+ method: "deterministic" | "llm-judge";
219
+ raw?: string;
220
+ notes: string[];
221
+ }
222
+
223
+ export function scoreDeterministic(output: string, prompt: string): ScoreReport {
224
+ const w = words(output);
225
+ const wc = Math.max(1, w.length);
226
+ const per100 = (n: number) => (n / wc) * 100;
227
+ const notes: string[] = [];
228
+
229
+ // grounding: citation tags [S1], [1], (Author, 2024), bare URLs, uncertainty tags
230
+ const citeTags = (output.match(/\[[Ss]?\d{1,3}\]/g) ?? []).length;
231
+ const urls = (output.match(/https?:\/\/\S+/g) ?? []).length;
232
+ const authorYear = (output.match(/\([A-Z][A-Za-z.\s&]+,\s*(19|20)\d{2}\)/g) ?? []).length;
233
+ const uncTags = countOccurrences(output, UNCERTAINTY_TAGS);
234
+ const groundingDensity = per100(citeTags + urls + authorYear + uncTags);
235
+
236
+ // specificity: digits-with-units, proper nouns, versions, dates
237
+ const numbers = (output.match(/\b\d[\d,.]*\s?(%|ms|s\b|kb|mb|gb|tb|kg|km|mm|cm|°c|°f|usd|\$|€|x\b)/gi) ?? []).length;
238
+ const bareNums = (output.match(/\b\d[\d,.]{1,}\b/g) ?? []).length;
239
+ const versions = (output.match(/\bv?\d+\.\d+(\.\d+)?\b/g) ?? []).length;
240
+ const propers = (output.match(/\b[A-Z][a-zA-Z0-9]{2,}(?:[-.][A-Za-z0-9]+)*\b/g) ?? []).length;
241
+ const specificity = per100(numbers * 2 + versions * 2 + bareNums + propers * 0.4);
242
+
243
+ // structure
244
+ const headings = (output.match(/^#{1,6}\s+\S/gm) ?? []).length;
245
+ const bullets = (output.match(/^\s*[-*•]\s+\S/gm) ?? []).length;
246
+ const numbered = (output.match(/^\s*\d+[.)]\s+\S/gm) ?? []).length;
247
+ const tableRows = (output.match(/^\s*\|.*\|\s*$/gm) ?? []).length;
248
+ const structureSignal = per100(headings * 6 + tableRows * 3 + (bullets + numbered) * 1.2);
249
+
250
+ // directness (inverse hedging + filler)
251
+ const hedgeN = countOccurrences(output, HEDGES);
252
+ const fillerN = countOccurrences(output, FILLER);
253
+ const hedgeDensity = per100(hedgeN + fillerN * 3);
254
+ const directness = Math.max(1, 10 - hedgeDensity * 1.7);
255
+
256
+ // completeness: coverage of content terms from the prompt
257
+ const stop = new Set(["the", "and", "for", "with", "that", "this", "from", "your", "you", "are", "was", "have", "has", "will", "what", "how", "why", "please", "make", "sure", "into", "also", "each", "them", "then", "there", "which", "when", "can", "not", "all", "any", "our"]);
258
+ const promptTerms = [...new Set(words(prompt).filter((t) => t.length > 3 && !stop.has(t)))];
259
+ const outSet = new Set(w);
260
+ const covered = promptTerms.filter((t) => outSet.has(t)).length;
261
+ const coverage = promptTerms.length ? covered / promptTerms.length : 0.5;
262
+ if (promptTerms.length < 5) notes.push("Prompt too short for a reliable coverage signal — completeness is low-confidence.");
263
+
264
+ // depth: causal/mechanism connectives + clause complexity
265
+ const causal = countOccurrences(output, ["because", "therefore", "consequently", "which means", "as a result", "trade-off", "tradeoff", "mechanism", "root cause", "second-order", "downstream", "implies", "leads to", "driven by"]);
266
+ const sentences = Math.max(1, (output.match(/[.!?]+\s/g) ?? []).length);
267
+ const avgSentLen = wc / sentences;
268
+ const depth = Math.min(10, band(per100(causal), 0.6, 3.2) * 0.7 + Math.min(10, avgSentLen / 3.2) * 0.3);
269
+
270
+ // actionability
271
+ const actionability = band(per100(countOccurrences(output, ACTION_MARKERS)), 0.8, 4.0);
272
+
273
+ // calibration: uncertainty tags should exist, but be differentiated not uniform
274
+ const calibration = uncTags === 0
275
+ ? (groundingDensity > 2 ? 6.0 : 3.0)
276
+ : band(per100(uncTags), 0.15, 1.6);
277
+ if (uncTags === 0) notes.push("No explicit uncertainty markers found — calibration cannot exceed 6.");
278
+
279
+ // non-redundancy: repeated 6-gram ratio
280
+ const grams = new Map<string, number>();
281
+ for (let i = 0; i + 6 <= w.length; i++) {
282
+ const g = w.slice(i, i + 6).join(" ");
283
+ grams.set(g, (grams.get(g) ?? 0) + 1);
284
+ }
285
+ let repeated = 0;
286
+ for (const c of grams.values()) if (c > 1) repeated += c - 1;
287
+ const redundancyRatio = grams.size ? repeated / grams.size : 0;
288
+ const nonredundancy = Math.max(1, 10 - redundancyRatio * 120);
289
+
290
+ // format compliance: does output honour shapes named in the prompt?
291
+ const asks = {
292
+ table: /\btable\b/i.test(prompt),
293
+ bullets: /\bbullet|list\b/i.test(prompt),
294
+ heading: /\bsection|heading\b/i.test(prompt),
295
+ json: /\bjson\b/i.test(prompt),
296
+ code: /\bcode\b/i.test(prompt),
297
+ };
298
+ let hits = 0, asked = 0;
299
+ if (asks.table) { asked++; if (tableRows > 1) hits++; }
300
+ if (asks.bullets) { asked++; if (bullets + numbered > 2) hits++; }
301
+ if (asks.heading) { asked++; if (headings > 0) hits++; }
302
+ if (asks.json) { asked++; if (/[[{]/.test(output)) hits++; }
303
+ if (asks.code) { asked++; if (/```/.test(output)) hits++; }
304
+ const compliance = asked === 0 ? 7.0 : 2 + 8 * (hits / asked);
305
+ if (asked === 0) notes.push("Prompt declared no explicit format — compliance defaults to 7 (neutral).");
306
+
307
+ const scored: Record<string, { s: number; e: string }> = {
308
+ grounding: { s: band(groundingDensity, 0.5, 3.5), e: `${citeTags} tag(s), ${urls} url(s), ${authorYear} author-year, ${uncTags} uncertainty mark(s) → ${groundingDensity.toFixed(2)}/100w` },
309
+ specificity: { s: band(specificity, 3, 14), e: `${numbers} unit-bearing, ${versions} version(s), ${bareNums} numeral(s), ${propers} proper noun(s) → ${specificity.toFixed(1)}/100w` },
310
+ structure: { s: band(structureSignal, 1.5, 9), e: `${headings} heading(s), ${tableRows} table row(s), ${bullets + numbered} list item(s)` },
311
+ directness: { s: directness, e: `${hedgeN} hedge(s) + ${fillerN} filler phrase(s) → ${hedgeDensity.toFixed(2)}/100w` },
312
+ completeness: { s: 1 + 9 * coverage, e: `${covered}/${promptTerms.length} prompt content terms present (${(coverage * 100).toFixed(0)}%)` },
313
+ depth: { s: depth, e: `${causal} causal connective(s), avg sentence ${avgSentLen.toFixed(1)}w` },
314
+ actionability: { s: actionability, e: `${countOccurrences(output, ACTION_MARKERS)} action marker(s)` },
315
+ calibration: { s: calibration, e: `${uncTags} uncertainty marker(s) across ${wc} words` },
316
+ nonredundancy: { s: nonredundancy, e: `repeated 6-gram ratio ${(redundancyRatio * 100).toFixed(1)}%` },
317
+ compliance: { s: compliance, e: asked === 0 ? "no explicit format requested" : `${hits}/${asked} declared format element(s) honoured` },
318
+ };
319
+
320
+ const dims: DimScore[] = RUBRIC.map((r) => ({
321
+ id: r.id,
322
+ label: r.label,
323
+ weight: r.weight,
324
+ score: Math.max(1, Math.min(10, Number(scored[r.id].s.toFixed(2)))),
325
+ evidence: scored[r.id].e,
326
+ }));
327
+
328
+ const totalW = dims.reduce((a, d) => a + d.weight, 0);
329
+ const overall = Number((dims.reduce((a, d) => a + d.score * d.weight, 0) / totalW).toFixed(2));
330
+
331
+ return { overall, dims, method: "deterministic", notes };
332
+ }
333
+
334
+ // ───────────────────────────────────────────────────────────────────────────
335
+ // LLM JUDGE — anchored rubric, forced JSON contract
336
+ // ───────────────────────────────────────────────────────────────────────────
337
+
338
+ function buildJudgePrompt(prompt: string, output: string): string {
339
+ const rubricText = RUBRIC.map(
340
+ (r) => `- ${r.id} (${r.label}, weight ${r.weight})\n 3 = ${r.anchor3}\n 7 = ${r.anchor7}\n 10 = ${r.anchor10}`
341
+ ).join("\n");
342
+ return `You are a strict third-party evaluator. You did NOT write this output and have no stake in it. Score harshly; a 10 must be genuinely exceptional.
343
+
344
+ Score the RESPONSE against the anchored rubric. Use the anchors literally — do not invent your own standard.
345
+
346
+ RUBRIC
347
+ ${rubricText}
348
+
349
+ For EACH dimension return an integer or one-decimal score 1-10 and a one-sentence justification quoting or naming the specific textual evidence.
350
+
351
+ Then identify the SINGLE highest-leverage prompt defect: which region of the ORIGINAL PROMPT, if rewritten, would most raise the weakest dimensions. Choose the region id from exactly this set:
352
+ ROLE, TASK, CONTEXT, EVIDENCE_POLICY, CONSTRAINTS, DEPTH, FORMAT, EXAMPLES, TONE, STOP_CONDITION
353
+
354
+ Return ONLY JSON, no prose, no code fence:
355
+ {"dims":[{"id":"grounding","score":0,"why":""}],"weakest":["id","id"],"primaryRegion":"EVIDENCE_POLICY","gradient":"<one paragraph: exactly why the prompt — not the model — produced this ceiling>","patch":"<the literal replacement text to insert into that prompt region>"}
356
+
357
+ ORIGINAL PROMPT
358
+ <<<
359
+ ${prompt.slice(0, 6000)}
360
+ >>>
361
+
362
+ RESPONSE TO SCORE
363
+ <<<
364
+ ${output.slice(0, 14000)}
365
+ >>>`;
366
+ }
367
+
368
+ export interface JudgeResult {
369
+ report: ScoreReport;
370
+ weakest: string[];
371
+ primaryRegion: RegionId | null;
372
+ gradient: string;
373
+ patch: string;
374
+ model: string;
375
+ }
376
+
377
+ export async function judgeWithLLM(
378
+ prompt: string,
379
+ output: string,
380
+ model = "gemini-2.0-flash"
381
+ ): Promise<JudgeResult> {
382
+ const apiKey = getGeminiKey();
383
+ if (!apiKey) throw new Error("No Gemini API key configured. Set it in the V15 panel, or use the deterministic scorer.");
384
+
385
+ const res: any = await geminiGenerate({
386
+ apiKey,
387
+ model,
388
+ prompt: buildJudgePrompt(prompt, output),
389
+ maxOutputTokens: 2400,
390
+ });
391
+ const text: string = String(res?.text ?? res?.output ?? "");
392
+ if (!text) throw new Error(`Judge returned no text (model=${model}).`);
393
+
394
+ const m = text.match(/\{[\s\S]*\}/);
395
+ if (!m) throw new Error("Judge did not return parseable JSON. Raw output shown below.");
396
+ let parsed: any;
397
+ try {
398
+ parsed = JSON.parse(m[0]);
399
+ } catch (e) {
400
+ throw new Error(`Judge JSON parse failed: ${e instanceof Error ? e.message : String(e)}`);
401
+ }
402
+
403
+ const byId = new Map<string, any>((parsed.dims ?? []).map((d: any) => [String(d.id), d]));
404
+ const dims: DimScore[] = RUBRIC.map((r) => {
405
+ const d = byId.get(r.id);
406
+ const s = Number(d?.score);
407
+ return {
408
+ id: r.id,
409
+ label: r.label,
410
+ weight: r.weight,
411
+ score: Number.isFinite(s) ? Math.max(1, Math.min(10, s)) : 5,
412
+ evidence: String(d?.why ?? "(judge returned no justification for this dimension)"),
413
+ };
414
+ });
415
+ const totalW = dims.reduce((a, d) => a + d.weight, 0);
416
+ const overall = Number((dims.reduce((a, d) => a + d.score * d.weight, 0) / totalW).toFixed(2));
417
+
418
+ const region = String(parsed.primaryRegion ?? "").toUpperCase();
419
+ return {
420
+ report: { overall, dims, method: "llm-judge", raw: text, notes: [] },
421
+ weakest: Array.isArray(parsed.weakest) ? parsed.weakest.map(String) : [],
422
+ primaryRegion: (REGIONS.find((r) => r.id === region)?.id ?? null) as RegionId | null,
423
+ gradient: String(parsed.gradient ?? ""),
424
+ patch: String(parsed.patch ?? ""),
425
+ model,
426
+ };
427
+ }
428
+
429
+ // ───────────────────────────────────────────────────────────────────────────
430
+ // TEXTUAL GRADIENT → PROMPT PATCH (deterministic fallback, always available)
431
+ // ───────────────────────────────────────────────────────────────────────────
432
+
433
+ export interface PromptDiagnosis {
434
+ targetScore: number;
435
+ currentScore: number;
436
+ gap: number;
437
+ /** Ordered by leverage = weight × deficit. This is the "gradient magnitude". */
438
+ leverage: Array<{
439
+ dim: DimScore;
440
+ deficit: number;
441
+ leverage: number;
442
+ regions: RegionId[];
443
+ fix: string;
444
+ insert: string;
445
+ }>;
446
+ primaryRegion: RegionId | null;
447
+ /** Concrete text block to append/replace in the prompt. */
448
+ patchBlock: string;
449
+ caveats: string[];
450
+ }
451
+
452
+ /** Deterministic, dimension-specific prompt repairs. */
453
+ const FIXES: Record<string, { fix: string; insert: string }> = {
454
+ grounding: {
455
+ fix: "The prompt never made attribution mandatory, so the model treated sourcing as optional.",
456
+ insert: "EVIDENCE POLICY (hard): every load-bearing claim must carry an inline source marker in the form [S#] mapped to a source list at the end, OR an explicit tag from {[UNVERIFIED], [ASSUMPTION], [ESTIMATE], [POST-CUTOFF]}. An unmarked factual assertion is a defect. Do not fill gaps with plausible-sounding detail — say what is unknown.",
457
+ },
458
+ specificity: {
459
+ fix: "The prompt asked for a topic, not for resolvable particulars, so the model answered at category level.",
460
+ insert: "SPECIFICITY (hard): name concrete entities, exact figures WITH UNITS, version numbers, dates, and thresholds. Any sentence that would still be true if the subject were swapped for a different one in the same category must be deleted or made specific.",
461
+ },
462
+ structure: {
463
+ fix: "No output shape was specified, so the model defaulted to undifferentiated prose.",
464
+ insert: "FORMAT: open with a 2-3 sentence direct answer before any heading. Then use `##` sections. Use a markdown table for anything comparative (≥2 options × ≥2 attributes). No section shorter than 3 sentences.",
465
+ },
466
+ directness: {
467
+ fix: "Nothing in the prompt gave permission to commit, so the model hedged to stay safe.",
468
+ insert: "STANCE: you are permitted and required to commit to a position. State the conclusion first, then the support. Hedge ONLY where the evidence is genuinely split, and when you hedge, say precisely what evidence would resolve it. Ban: 'it depends', 'it is important to note', 'in conclusion', 'delve'.",
469
+ },
470
+ completeness: {
471
+ fix: "Multi-part requests were not enumerated, so later clauses were dropped.",
472
+ insert: "COVERAGE: before answering, silently enumerate every distinct question in the request, including implicit sub-questions. Address each one under its own heading. End with a coverage checklist mapping each enumerated question to the section that answers it.",
473
+ },
474
+ depth: {
475
+ fix: "The prompt requested an answer but not a mechanism, so the model stopped at the first causal layer.",
476
+ insert: "DEPTH: for each main claim, give the MECHANISM (why it happens, not just that it happens), quantify at least one trade-off, and name at least one second-order effect. Stop-condition: a domain expert must learn something they could not have guessed from the question alone.",
477
+ },
478
+ actionability: {
479
+ fix: "No consumer of the output was defined, so nothing was made operational.",
480
+ insert: "ACTIONABILITY: end with a prioritised action list. Each item: the action, the trigger threshold, who owns it, and how to verify it worked. Rank by (impact ÷ effort). No item may be a restatement of the analysis.",
481
+ },
482
+ calibration: {
483
+ fix: "Confidence was never asked for, so all claims were stated at one uniform level.",
484
+ insert: "CALIBRATION: attach a confidence to each major claim from {HIGH, MEDIUM, LOW} and justify the level with the evidence class behind it (measured / cited / derived / assumed). Uniform confidence across all claims is a defect.",
485
+ },
486
+ nonredundancy: {
487
+ fix: "A summary was implicitly invited, so content was restated instead of extended.",
488
+ insert: "ANTI-REDUNDANCY: no point may appear twice. Do not write a concluding summary that restates earlier sections — if a conclusion is included it must contain only new synthesis or the decision that follows.",
489
+ },
490
+ compliance: {
491
+ fix: "Format requirements were stated as preference, not as a contract, so they were partially ignored.",
492
+ insert: "FORMAT CONTRACT: the structure specified above is a hard contract. Before emitting, verify every required element is present. If any element cannot be produced, say so explicitly instead of silently omitting it.",
493
+ },
494
+ };
495
+
496
+ export function diagnose(report: ScoreReport, targetScore = 9.0): PromptDiagnosis {
497
+ const leverage = report.dims
498
+ .map((dim) => {
499
+ const deficit = Math.max(0, targetScore - dim.score);
500
+ const meta = RUBRIC.find((r) => r.id === dim.id)!;
501
+ const f = FIXES[dim.id];
502
+ return {
503
+ dim,
504
+ deficit: Number(deficit.toFixed(2)),
505
+ leverage: Number((deficit * dim.weight).toFixed(3)),
506
+ regions: meta.regions,
507
+ fix: f.fix,
508
+ insert: f.insert,
509
+ };
510
+ })
511
+ .filter((x) => x.deficit > 0.25)
512
+ .sort((a, b) => b.leverage - a.leverage);
513
+
514
+ // Primary region = region with the highest summed leverage across dimensions.
515
+ const regionScore = new Map<RegionId, number>();
516
+ for (const l of leverage) {
517
+ for (const r of l.regions) regionScore.set(r, (regionScore.get(r) ?? 0) + l.leverage);
518
+ }
519
+ const primaryRegion =
520
+ [...regionScore.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? null;
521
+
522
+ const top = leverage.slice(0, 4);
523
+ const patchBlock = top.length
524
+ ? [
525
+ "# ── PROMPT PATCH (generated from measured deficits) ──",
526
+ `# target=${targetScore.toFixed(1)} current=${report.overall.toFixed(2)} gap=${(targetScore - report.overall).toFixed(2)}`,
527
+ `# primary region: ${primaryRegion ?? "n/a"}`,
528
+ "",
529
+ ...top.map((l) => `## ${l.dim.label} — measured ${l.dim.score.toFixed(2)}/10 (leverage ${l.leverage})\n${l.insert}`),
530
+ ].join("\n")
531
+ : "# No dimension is below target. The prompt is not the bottleneck — investigate the pipeline trace instead.";
532
+
533
+ const caveats = [
534
+ "This diagnosis maximises a proxy signal. A prompt that games the scorer is not a better prompt — re-judge with a THIRD-PARTY model after patching.",
535
+ "Deterministic scores measure surface properties of text. They cannot detect a factually wrong but well-formatted answer. Grounding truth still requires the pipeline's citation audit.",
536
+ ...report.notes,
537
+ ];
538
+
539
+ return {
540
+ targetScore,
541
+ currentScore: report.overall,
542
+ gap: Number((targetScore - report.overall).toFixed(2)),
543
+ leverage,
544
+ primaryRegion,
545
+ patchBlock,
546
+ caveats,
547
+ };
548
+ }
549
+
550
+ // ───────────────────────────────────────────────────────────────────────────
551
+ // OPRO — score trajectory across prompt revisions
552
+ // ───────────────────────────────────────────────────────────────────────────
553
+
554
+ export interface TrajectoryPoint {
555
+ iteration: number;
556
+ ts: number;
557
+ label: string;
558
+ overall: number;
559
+ method: ScoreReport["method"];
560
+ dims: Record<string, number>;
561
+ }
562
+
563
+ const TRAJ_KEY = "veritas.promptforge.trajectory";
564
+
565
+ export function loadTrajectory(): TrajectoryPoint[] {
566
+ try {
567
+ const raw = localStorage.getItem(TRAJ_KEY);
568
+ return raw ? (JSON.parse(raw) as TrajectoryPoint[]) : [];
569
+ } catch {
570
+ return [];
571
+ }
572
+ }
573
+
574
+ export function recordTrajectory(label: string, report: ScoreReport): TrajectoryPoint[] {
575
+ const prev = loadTrajectory();
576
+ const pt: TrajectoryPoint = {
577
+ iteration: prev.length + 1,
578
+ ts: Date.now(),
579
+ label,
580
+ overall: report.overall,
581
+ method: report.method,
582
+ dims: Object.fromEntries(report.dims.map((d) => [d.id, d.score])),
583
+ };
584
+ const next = [...prev, pt].slice(-40);
585
+ try {
586
+ localStorage.setItem(TRAJ_KEY, JSON.stringify(next));
587
+ } catch {
588
+ /* storage full or unavailable — trajectory is best-effort */
589
+ }
590
+ return next;
591
+ }
592
+
593
+ export function clearTrajectory(): void {
594
+ try {
595
+ localStorage.removeItem(TRAJ_KEY);
596
+ } catch {
597
+ /* ignore */
598
+ }
599
+ }
600
+
601
+ /**
602
+ * OPRO meta-prompt: hand the optimizer the (prompt, score) history rather than
603
+ * a single critique. Copy this into any third-party LLM instance.
604
+ */
605
+ export function buildOproMetaPrompt(traj: TrajectoryPoint[], currentPrompt: string, target = 9.0): string {
606
+ const hist = traj
607
+ .slice(-12)
608
+ .map((p) => ` iter ${p.iteration} · ${p.label} · overall ${p.overall.toFixed(2)} · ${Object.entries(p.dims).map(([k, v]) => `${k}=${Number(v).toFixed(1)}`).join(" ")}`)
609
+ .join("\n");
610
+ return `You are a prompt optimizer. Below is the score TRAJECTORY of successive prompt revisions, evaluated against a fixed anchored rubric (1-10 per dimension, weighted overall).
611
+
612
+ TRAJECTORY (oldest → newest)
613
+ ${hist || " (no history yet — this is iteration 1)"}
614
+
615
+ TARGET: overall ≥ ${target.toFixed(1)} with NO single dimension below 8.
616
+
617
+ CURRENT PROMPT
618
+ <<<
619
+ ${currentPrompt}
620
+ >>>
621
+
622
+ Read the curve. Identify which edits moved which dimensions and which edits regressed others (dimension conflict is expected — textual gradients are not orthogonal). Then write ONE new prompt that beats the whole curve.
623
+
624
+ Constraints on your rewrite:
625
+ - Do not simply append more rules; consolidate and remove instructions that the trajectory shows had no effect.
626
+ - If two dimensions are in tension, state the trade-off explicitly and choose, do not hedge.
627
+ - Preserve every hard constraint from the current prompt.
628
+
629
+ Return: (1) a 5-line analysis of the curve, (2) the full rewritten prompt, (3) the single dimension you expect to move most and by how much.`;
630
+ }
631
+
632
+ /** ProTeGi-style handoff bundle for an external LLM instance. */
633
+ export function buildExternalAuditBundle(opts: {
634
+ prompt: string;
635
+ output: string;
636
+ deterministic: ScoreReport;
637
+ llm?: ScoreReport | null;
638
+ diagnosis: PromptDiagnosis;
639
+ }): string {
640
+ const { prompt, output, deterministic, llm, diagnosis } = opts;
641
+ const divergence = llm ? Math.abs(llm.overall - deterministic.overall) : null;
642
+ return `# EXTERNAL AUDIT BUNDLE — veritas.prompt-forge/1
643
+ Generated: ${new Date().toISOString()}
644
+
645
+ ## 1. SCORES
646
+ Deterministic (reproducible text analysis): ${deterministic.overall.toFixed(2)}/10
647
+ ${llm ? `LLM judge (${llm.method}): ${llm.overall.toFixed(2)}/10` : "LLM judge: not run"}
648
+ ${divergence !== null ? `Divergence: ${divergence.toFixed(2)}${divergence > 1.5 ? " ⚠ LARGE — one of the two scorers is wrong. Investigate before acting." : ""}` : ""}
649
+
650
+ ## 2. PER-DIMENSION (deterministic)
651
+ ${deterministic.dims.map((d) => `- ${d.label}: ${d.score.toFixed(2)}/10 (w=${d.weight}) — ${d.evidence}`).join("\n")}
652
+
653
+ ${llm ? `## 2b. PER-DIMENSION (LLM judge)\n${llm.dims.map((d) => `- ${d.label}: ${d.score.toFixed(2)}/10 — ${d.evidence}`).join("\n")}\n` : ""}
654
+ ## 3. GRADIENT (leverage = weight x deficit vs target ${diagnosis.targetScore})
655
+ ${diagnosis.leverage.map((l, i) => `${i + 1}. ${l.dim.label} — score ${l.dim.score.toFixed(2)}, deficit ${l.deficit}, leverage ${l.leverage}\n regions: ${l.regions.join(", ")}\n root cause: ${l.fix}`).join("\n")}
656
+
657
+ ## 4. PRIMARY PROMPT REGION TO EDIT
658
+ ${diagnosis.primaryRegion ?? "none — prompt is not the bottleneck"}
659
+
660
+ ## 5. PROPOSED PATCH
661
+ ${diagnosis.patchBlock}
662
+
663
+ ## 6. CAVEATS
664
+ ${diagnosis.caveats.map((c) => `- ${c}`).join("\n")}
665
+
666
+ ## 7. ORIGINAL PROMPT
667
+ <<<
668
+ ${prompt}
669
+ >>>
670
+
671
+ ## 8. OUTPUT UNDER TEST
672
+ <<<
673
+ ${output.slice(0, 20000)}
674
+ >>>
675
+
676
+ ## 9. TASK FOR YOU (the receiving LLM)
677
+ Independently re-score the OUTPUT against the same rubric WITHOUT looking at the scores above first. Then compare your scores to section 2. Where you disagree by more than 2 points, explain which scorer is wrong and why. Finally, either ratify the patch in section 5 or replace it with a better one, and state the specific dimension you expect it to move.`;
678
+ }