@heretek-ai/epistemic-swarm 0.7.24 → 1.0.2

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 (350) hide show
  1. package/index.ts +1 -0
  2. package/package.json +63 -139
  3. package/rpc.ts +1 -0
  4. package/server.ts +1 -0
  5. package/src/agents.ts +69 -0
  6. package/src/continue.ts +40 -0
  7. package/src/hooks.ts +283 -0
  8. package/src/panels.tsx +220 -0
  9. package/src/policy.ts +221 -0
  10. package/src/pr.ts +37 -0
  11. package/src/research.ts +63 -0
  12. package/src/rpc-def.ts +136 -0
  13. package/src/rpc.ts +331 -0
  14. package/src/runtime.ts +112 -0
  15. package/src/server.ts +311 -0
  16. package/src/session.ts +61 -0
  17. package/src/tools.ts +61 -0
  18. package/src/tui.tsx +206 -0
  19. package/tui.tsx +1 -0
  20. package/.agents/skills/brainstorming/SKILL.md +0 -19
  21. package/.agents/skills/code_audit/SKILL.md +0 -19
  22. package/.agents/skills/darkharvest/SKILL.md +0 -19
  23. package/.agents/skills/epistemic_search/SKILL.md +0 -19
  24. package/.agents/skills/factory/SKILL.md +0 -19
  25. package/.agents/skills/grilling/SKILL.md +0 -19
  26. package/.agents/skills/oss_scout/SKILL.md +0 -19
  27. package/.agents/skills/research_cache/SKILL.md +0 -19
  28. package/.agents/skills/swarm_config/SKILL.md +0 -19
  29. package/.claude-plugin/marketplace.json +0 -61
  30. package/.claude-plugin/plugin.json +0 -76
  31. package/.omp/README.md +0 -39
  32. package/.omp/SYSTEM.md +0 -17
  33. package/.omp/commands/audit.md +0 -10
  34. package/.omp/commands/brainstorming.md +0 -12
  35. package/.omp/commands/darkharvest.md +0 -11
  36. package/.omp/commands/domainexpansion.md +0 -9
  37. package/.omp/commands/factory.md +0 -9
  38. package/.omp/commands/grill.md +0 -9
  39. package/.omp/commands/scout.md +0 -10
  40. package/.omp/commands/swarm-config.md +0 -10
  41. package/.omp/commands/swarm.md +0 -9
  42. package/.omp/hooks/post/epistemic-audit.ts +0 -16
  43. package/.omp/hooks/pre/epistemic-redirect.ts +0 -21
  44. package/.omp/prompts/brainstorming.md +0 -8
  45. package/.omp/prompts/swarm.md +0 -8
  46. package/LICENSE +0 -126
  47. package/MARKETPLACE.md +0 -130
  48. package/README.md +0 -403
  49. package/bin/cli.js +0 -297
  50. package/config/claude-settings-patch.json +0 -10
  51. package/config/docker-compose.infra.yml +0 -23
  52. package/config/domain_packs/biopharma.json +0 -23
  53. package/config/domain_packs/legal.json +0 -19
  54. package/config/domain_packs/quant.json +0 -19
  55. package/config/mcp-research-servers.json +0 -33
  56. package/config/mcp_launcher.py +0 -153
  57. package/config/opencode-snippet.json +0 -156
  58. package/config/searxng_mcp.py +0 -92
  59. package/extensions/pi/index.js +0 -357
  60. package/hooks/hooks.json +0 -45
  61. package/install.sh +0 -473
  62. package/plugins/antigravity/README.md +0 -72
  63. package/plugins/antigravity/agents/alpha-thesis.md +0 -36
  64. package/plugins/antigravity/agents/beta-antithesis.md +0 -35
  65. package/plugins/antigravity/agents/brainstormer.md +0 -27
  66. package/plugins/antigravity/agents/code-auditor.md +0 -28
  67. package/plugins/antigravity/agents/darkharvester.md +0 -30
  68. package/plugins/antigravity/agents/epistemic-auditor.md +0 -28
  69. package/plugins/antigravity/agents/manager.md +0 -26
  70. package/plugins/antigravity/agents/oss-scout.md +0 -27
  71. package/plugins/antigravity/agents/programmer.md +0 -25
  72. package/plugins/antigravity/agents/qa-a.md +0 -22
  73. package/plugins/antigravity/agents/qa-b.md +0 -22
  74. package/plugins/antigravity/antigravity_hooks.py +0 -265
  75. package/plugins/antigravity/commands/audit.md +0 -11
  76. package/plugins/antigravity/commands/brainstorm.md +0 -9
  77. package/plugins/antigravity/commands/brainstorming.md +0 -10
  78. package/plugins/antigravity/commands/darkharvest.md +0 -12
  79. package/plugins/antigravity/commands/domainexpansion.md +0 -12
  80. package/plugins/antigravity/commands/factory.md +0 -14
  81. package/plugins/antigravity/commands/grill.md +0 -10
  82. package/plugins/antigravity/commands/scout.md +0 -11
  83. package/plugins/antigravity/commands/swarm-config.md +0 -9
  84. package/plugins/antigravity/commands/swarm.md +0 -12
  85. package/plugins/antigravity/hook_bus_bridge.js +0 -352
  86. package/plugins/antigravity/hooks.json +0 -44
  87. package/plugins/antigravity/mcp_config.json +0 -33
  88. package/plugins/antigravity/mcp_launcher.py +0 -58
  89. package/plugins/antigravity/plugin.json +0 -13
  90. package/plugins/antigravity/rules/AGENTS.md +0 -127
  91. package/plugins/antigravity/rules/epistemic-integrity.md +0 -16
  92. package/plugins/antigravity/skills/brainstorming/SKILL.md +0 -19
  93. package/plugins/antigravity/skills/code_audit/SKILL.md +0 -19
  94. package/plugins/antigravity/skills/darkharvest/SKILL.md +0 -19
  95. package/plugins/antigravity/skills/epistemic_search/SKILL.md +0 -19
  96. package/plugins/antigravity/skills/factory/SKILL.md +0 -19
  97. package/plugins/antigravity/skills/grilling/SKILL.md +0 -19
  98. package/plugins/antigravity/skills/oss_scout/SKILL.md +0 -19
  99. package/plugins/antigravity/skills/research_cache/SKILL.md +0 -19
  100. package/plugins/antigravity/skills/swarm_config/SKILL.md +0 -19
  101. package/plugins/codex/AGENTS.md.snippet +0 -10
  102. package/plugins/codex/README.md +0 -37
  103. package/plugins/codex/config.toml.snippet +0 -28
  104. package/plugins/codex/openai.yaml +0 -24
  105. package/plugins/codex/skills/brainstorming/SKILL.md +0 -19
  106. package/plugins/codex/skills/code_audit/SKILL.md +0 -19
  107. package/plugins/codex/skills/darkharvest/SKILL.md +0 -19
  108. package/plugins/codex/skills/epistemic_search/SKILL.md +0 -19
  109. package/plugins/codex/skills/factory/SKILL.md +0 -19
  110. package/plugins/codex/skills/grilling/SKILL.md +0 -19
  111. package/plugins/codex/skills/oss_scout/SKILL.md +0 -19
  112. package/plugins/codex/skills/research_cache/SKILL.md +0 -19
  113. package/plugins/codex/skills/swarm_config/SKILL.md +0 -19
  114. package/plugins/darkharvest/.claude-plugin/plugin.json +0 -15
  115. package/plugins/darkharvest/agents/harvest-proponent.md +0 -22
  116. package/plugins/darkharvest/agents/harvest-redteam.md +0 -20
  117. package/plugins/darkharvest/evals/teardown-verdict/graders/license-line.md +0 -6
  118. package/plugins/darkharvest/evals/teardown-verdict/graders/skill-fired.md +0 -5
  119. package/plugins/darkharvest/evals/teardown-verdict/prompt.md +0 -6
  120. package/plugins/darkharvest/skills/darkharvest/SKILL.md +0 -70
  121. package/plugins/darkharvest/skills/darkharvest/scripts/harvest.py +0 -289
  122. package/plugins/factory/.claude-plugin/plugin.json +0 -15
  123. package/plugins/factory/agents/factory-manager.md +0 -22
  124. package/plugins/factory/agents/programmer.md +0 -16
  125. package/plugins/factory/agents/qa-adversarial.md +0 -17
  126. package/plugins/factory/agents/qa-functional.md +0 -17
  127. package/plugins/factory/evals/gate-halt/graders/gates-first.md +0 -6
  128. package/plugins/factory/evals/gate-halt/graders/skill-fired.md +0 -5
  129. package/plugins/factory/evals/gate-halt/prompt.md +0 -6
  130. package/plugins/factory/skills/factory/SKILL.md +0 -61
  131. package/plugins/factory/skills/factory/scripts/factory.py +0 -300
  132. package/plugins/gemini/GEMINI.md +0 -16
  133. package/plugins/gemini/README.md +0 -20
  134. package/plugins/gemini/commands/audit.toml +0 -6
  135. package/plugins/gemini/commands/brainstorming.toml +0 -10
  136. package/plugins/gemini/commands/darkharvest.toml +0 -8
  137. package/plugins/gemini/commands/domainexpansion.toml +0 -7
  138. package/plugins/gemini/commands/factory.toml +0 -8
  139. package/plugins/gemini/commands/grill.toml +0 -6
  140. package/plugins/gemini/commands/scout.toml +0 -7
  141. package/plugins/gemini/commands/swarm-config.toml +0 -7
  142. package/plugins/gemini/commands/swarm.toml +0 -8
  143. package/plugins/gemini/gemini-extension.json +0 -38
  144. package/plugins/gemini/hooks/hooks.json +0 -11
  145. package/plugins/gemini/skills/brainstorming/SKILL.md +0 -19
  146. package/plugins/gemini/skills/code_audit/SKILL.md +0 -19
  147. package/plugins/gemini/skills/darkharvest/SKILL.md +0 -19
  148. package/plugins/gemini/skills/epistemic_search/SKILL.md +0 -19
  149. package/plugins/gemini/skills/factory/SKILL.md +0 -19
  150. package/plugins/gemini/skills/grilling/SKILL.md +0 -19
  151. package/plugins/gemini/skills/oss_scout/SKILL.md +0 -19
  152. package/plugins/gemini/skills/research_cache/SKILL.md +0 -19
  153. package/plugins/gemini/skills/swarm_config/SKILL.md +0 -19
  154. package/plugins/opencode/analysis-bridge.js +0 -620
  155. package/plugins/opencode/config-io.js +0 -1651
  156. package/plugins/opencode/dep-health.js +0 -1039
  157. package/plugins/opencode/hook-bus.js +0 -496
  158. package/plugins/opencode/index.js +0 -2992
  159. package/plugins/opencode/tui.js +0 -1551
  160. package/plugins/opencode/weight-baseline.json +0 -16
  161. package/plugins/opencode/weight-signals.js +0 -769
  162. package/plugins/research-cache/.claude-plugin/plugin.json +0 -15
  163. package/plugins/research-cache/skills/research_cache/SKILL.md +0 -36
  164. package/plugins/research-cache/skills/research_cache/__init__.py +0 -0
  165. package/plugins/research-cache/skills/research_cache/hasher.py +0 -302
  166. package/plugins/socratic-grilling/.claude-plugin/plugin.json +0 -15
  167. package/plugins/socratic-grilling/skills/grilling/SKILL.md +0 -61
  168. package/plugins/socratic-grilling/skills/grilling/__init__.py +0 -0
  169. package/plugins/socratic-grilling/skills/grilling/socratic_tree.py +0 -363
  170. package/prompts/agent_alpha_thesis.md +0 -70
  171. package/prompts/agent_beta_antithesis.md +0 -78
  172. package/prompts/agent_brainstormer.md +0 -143
  173. package/prompts/agent_code_auditor.md +0 -88
  174. package/prompts/agent_darkharvest.md +0 -140
  175. package/prompts/agent_oss_scout.md +0 -78
  176. package/prompts/antigravity_repo_factcheck.md +0 -143
  177. package/prompts/base_epistemic_system.md +0 -50
  178. package/prompts/epistemic_auditor.md +0 -74
  179. package/prompts/orchestrator.md +0 -70
  180. package/runner/__init__.py +0 -0
  181. package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
  182. package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
  183. package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
  184. package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
  185. package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
  186. package/runner/__pycache__/darkharvest_claims.cpython-311.pyc +0 -0
  187. package/runner/__pycache__/errors.cpython-311.pyc +0 -0
  188. package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
  189. package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
  190. package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
  191. package/runner/__pycache__/path_safety.cpython-311.pyc +0 -0
  192. package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
  193. package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
  194. package/runner/__pycache__/preflight.cpython-311.pyc +0 -0
  195. package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
  196. package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
  197. package/runner/__pycache__/retrieval_log.cpython-311.pyc +0 -0
  198. package/runner/__pycache__/schema_validate.cpython-311.pyc +0 -0
  199. package/runner/__pycache__/schemas.cpython-311.pyc +0 -0
  200. package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
  201. package/runner/antigravity_hooks.py +0 -265
  202. package/runner/auctioneer.py +0 -169
  203. package/runner/auditor_engine.py +0 -711
  204. package/runner/claim_store.py +0 -417
  205. package/runner/claim_witness.py +0 -412
  206. package/runner/darkharvest_claims.py +0 -358
  207. package/runner/errors.py +0 -51
  208. package/runner/living_dossiers.py +0 -395
  209. package/runner/mcp_protocol.py +0 -188
  210. package/runner/mcp_server.py +0 -1447
  211. package/runner/path_safety.py +0 -62
  212. package/runner/pcrb.py +0 -290
  213. package/runner/pcrb_verify.py +0 -267
  214. package/runner/preflight.py +0 -1011
  215. package/runner/refinement.py +0 -580
  216. package/runner/research_swarm.py +0 -1848
  217. package/runner/retrieval_log.py +0 -90
  218. package/runner/schema_validate.py +0 -193
  219. package/runner/schemas.py +0 -630
  220. package/runner/state_machine.py +0 -463
  221. package/runner/tests/__pycache__/test_analysis_bridge.cpython-311.pyc +0 -0
  222. package/runner/tests/__pycache__/test_antigravity_plugin.cpython-311.pyc +0 -0
  223. package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
  224. package/runner/tests/__pycache__/test_backends.cpython-311.pyc +0 -0
  225. package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
  226. package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
  227. package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
  228. package/runner/tests/__pycache__/test_claude_plugin.cpython-311.pyc +0 -0
  229. package/runner/tests/__pycache__/test_config_schema.cpython-311.pyc +0 -0
  230. package/runner/tests/__pycache__/test_contract_tooling.cpython-311.pyc +0 -0
  231. package/runner/tests/__pycache__/test_darkharvest_audit.cpython-311.pyc +0 -0
  232. package/runner/tests/__pycache__/test_dep_health.cpython-311.pyc +0 -0
  233. package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
  234. package/runner/tests/__pycache__/test_dossier_contract.cpython-311.pyc +0 -0
  235. package/runner/tests/__pycache__/test_factory.cpython-311.pyc +0 -0
  236. package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
  237. package/runner/tests/__pycache__/test_frontier_concurrency.cpython-311.pyc +0 -0
  238. package/runner/tests/__pycache__/test_frontier_mirror_standalone.cpython-311.pyc +0 -0
  239. package/runner/tests/__pycache__/test_grounding.cpython-311.pyc +0 -0
  240. package/runner/tests/__pycache__/test_hardening_contract.cpython-311.pyc +0 -0
  241. package/runner/tests/__pycache__/test_hook_bus.cpython-311.pyc +0 -0
  242. package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
  243. package/runner/tests/__pycache__/test_manifest_concurrency.cpython-311.pyc +0 -0
  244. package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
  245. package/runner/tests/__pycache__/test_nk_hardening.cpython-311.pyc +0 -0
  246. package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
  247. package/runner/tests/__pycache__/test_opencode_v2_registrars.cpython-311.pyc +0 -0
  248. package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
  249. package/runner/tests/__pycache__/test_phase08_waiver_reopens.cpython-311.pyc +0 -0
  250. package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
  251. package/runner/tests/__pycache__/test_search_anomaly.cpython-311.pyc +0 -0
  252. package/runner/tests/__pycache__/test_search_provider.cpython-311.pyc +0 -0
  253. package/runner/tests/__pycache__/test_search_provider_plugin.cpython-311.pyc +0 -0
  254. package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
  255. package/runner/tests/__pycache__/test_swarm_config.cpython-311.pyc +0 -0
  256. package/runner/tests/__pycache__/test_sweep_regressions.cpython-311.pyc +0 -0
  257. package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
  258. package/runner/tests/__pycache__/test_weight_signals.cpython-311.pyc +0 -0
  259. package/runner/tests/fixtures/auction_objective.json +0 -35
  260. package/runner/tests/fixtures/borderline_claims.json +0 -27
  261. package/runner/tests/fixtures/config_validation_cases.json +0 -276
  262. package/runner/tests/fixtures/ddg_anomaly_page.html +0 -176
  263. package/runner/tests/fixtures/ddg_results_page.html +0 -28
  264. package/runner/tests/fixtures/divergence_objectives.json +0 -31
  265. package/runner/tests/test_analysis_bridge.py +0 -450
  266. package/runner/tests/test_antigravity_plugin.py +0 -361
  267. package/runner/tests/test_auction_order.py +0 -173
  268. package/runner/tests/test_backends.py +0 -457
  269. package/runner/tests/test_bet1_spike.py +0 -95
  270. package/runner/tests/test_claim_store.py +0 -162
  271. package/runner/tests/test_claim_witness.py +0 -186
  272. package/runner/tests/test_claude_plugin.py +0 -170
  273. package/runner/tests/test_config_schema.py +0 -879
  274. package/runner/tests/test_contract_tooling.py +0 -312
  275. package/runner/tests/test_darkharvest_audit.py +0 -395
  276. package/runner/tests/test_dep_health.py +0 -595
  277. package/runner/tests/test_domain_packs.py +0 -217
  278. package/runner/tests/test_dossier_contract.py +0 -196
  279. package/runner/tests/test_factory.py +0 -258
  280. package/runner/tests/test_fleet_seam.py +0 -113
  281. package/runner/tests/test_frontier_concurrency.py +0 -288
  282. package/runner/tests/test_frontier_mirror_standalone.py +0 -156
  283. package/runner/tests/test_grounding.py +0 -183
  284. package/runner/tests/test_hardening_contract.py +0 -391
  285. package/runner/tests/test_hook_bus.py +0 -956
  286. package/runner/tests/test_living_dossiers.py +0 -204
  287. package/runner/tests/test_manifest_concurrency.py +0 -187
  288. package/runner/tests/test_mcp_server.py +0 -257
  289. package/runner/tests/test_nk_hardening.py +0 -1046
  290. package/runner/tests/test_opencode_ux.py +0 -2438
  291. package/runner/tests/test_opencode_v2_registrars.py +0 -2157
  292. package/runner/tests/test_pcrb.py +0 -240
  293. package/runner/tests/test_phase08_waiver_reopens.py +0 -539
  294. package/runner/tests/test_refinement.py +0 -255
  295. package/runner/tests/test_search_anomaly.py +0 -342
  296. package/runner/tests/test_search_provider.py +0 -1534
  297. package/runner/tests/test_search_provider_plugin.py +0 -401
  298. package/runner/tests/test_swarm.py +0 -444
  299. package/runner/tests/test_swarm_config.py +0 -520
  300. package/runner/tests/test_sweep_regressions.py +0 -453
  301. package/runner/tests/test_webcache.py +0 -271
  302. package/runner/tests/test_weight_signals.py +0 -401
  303. package/schemas/alpha_dossier.schema.json +0 -204
  304. package/schemas/audit_report.schema.json +0 -79
  305. package/schemas/beta_dossier.schema.json +0 -214
  306. package/schemas/config.schema.json +0 -311
  307. package/schemas/frontier.schema.json +0 -61
  308. package/schemas/manifest.schema.json +0 -49
  309. package/schemas/scope_manifest.schema.json +0 -47
  310. package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
  311. package/scripts/__pycache__/build_adapters.cpython-311.pyc +0 -0
  312. package/scripts/__pycache__/check_docs.cpython-311.pyc +0 -0
  313. package/scripts/__pycache__/divergence_experiment.cpython-311.pyc +0 -0
  314. package/scripts/__pycache__/gen_schemas.cpython-311.pyc +0 -0
  315. package/scripts/auction_experiment.py +0 -188
  316. package/scripts/bet1_advisory_spike.py +0 -442
  317. package/scripts/build_adapters.py +0 -417
  318. package/scripts/check_docs.py +0 -66
  319. package/scripts/divergence_experiment.py +0 -214
  320. package/scripts/gen_schemas.py +0 -69
  321. package/skills/brainstorming/SKILL.md +0 -106
  322. package/skills/brainstorming/__init__.py +0 -1
  323. package/skills/brainstorming/scripts/brainstorm.py +0 -201
  324. package/skills/code_audit/SKILL.md +0 -45
  325. package/skills/darkharvest/SKILL.md +0 -70
  326. package/skills/darkharvest/scripts/harvest.py +0 -289
  327. package/skills/epistemic_search/SKILL.md +0 -67
  328. package/skills/epistemic_search/__init__.py +0 -1
  329. package/skills/epistemic_search/scripts/__pycache__/search.cpython-311.pyc +0 -0
  330. package/skills/epistemic_search/scripts/fetch.py +0 -156
  331. package/skills/epistemic_search/scripts/search.py +0 -551
  332. package/skills/epistemic_search/scripts/webcache.py +0 -339
  333. package/skills/factory/SKILL.md +0 -61
  334. package/skills/factory/scripts/factory.py +0 -300
  335. package/skills/grilling/SKILL.md +0 -61
  336. package/skills/grilling/__init__.py +0 -0
  337. package/skills/grilling/__pycache__/__init__.cpython-311.pyc +0 -0
  338. package/skills/grilling/__pycache__/socratic_tree.cpython-311.pyc +0 -0
  339. package/skills/grilling/socratic_tree.py +0 -363
  340. package/skills/oss_scout/SKILL.md +0 -49
  341. package/skills/research_cache/SKILL.md +0 -36
  342. package/skills/research_cache/__init__.py +0 -0
  343. package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
  344. package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
  345. package/skills/research_cache/hasher.py +0 -302
  346. package/skills/swarm_config/SKILL.md +0 -178
  347. package/skills/swarm_config/__init__.py +0 -35
  348. package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
  349. package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
  350. package/skills/swarm_config/configure.py +0 -1002
@@ -1,463 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Filesystem IPC Protocol & State Machine for Epistemic Swarm.
4
- Manages .research/ hierarchy, session state, scope DAG, and dossier serialization.
5
- """
6
-
7
- import os
8
- import json
9
- import threading
10
- import tempfile
11
- from contextlib import contextmanager
12
- from enum import Enum
13
- from pathlib import Path
14
- from datetime import datetime, timezone
15
- from typing import Dict, Any, List, Optional
16
-
17
- try: # POSIX advisory locking; no-op where unavailable
18
- import fcntl
19
- except ImportError: # pragma: no cover - non-POSIX
20
- fcntl = None
21
-
22
-
23
- class SessionStatus(str, Enum):
24
- INITIALIZING = "INITIALIZING"
25
- FRONTIER_SETTLING = "FRONTIER_SETTLING"
26
- ORCHESTRATING = "ORCHESTRATING"
27
- SWARM_DISPATCHED = "SWARM_DISPATCHED"
28
- AUDITING = "AUDITING"
29
- COMPLETED = "COMPLETED"
30
- FAILED = "FAILED"
31
-
32
-
33
- class ScopeStatus(str, Enum):
34
- PENDING = "PENDING"
35
- ALPHA_RUNNING = "ALPHA_RUNNING"
36
- BETA_RUNNING = "BETA_RUNNING"
37
- RUNNING_PARALLEL = "RUNNING_PARALLEL"
38
- ALPHA_COMPLETE = "ALPHA_COMPLETE"
39
- BETA_COMPLETE = "BETA_COMPLETE"
40
- DOSSIERS_READY = "DOSSIERS_READY"
41
- AUDITING = "AUDITING"
42
- COMPLETE = "COMPLETE"
43
- FAILED = "FAILED"
44
-
45
-
46
- MANIFEST_FILENAME = "manifest.json"
47
- RUNS_DIRNAME = "runs"
48
- LATEST_POINTER = "latest.json"
49
-
50
-
51
- def run_scoped_enabled() -> bool:
52
- """Opt-in run-scoped layout (`.research/runs/<id>/`). Default: flat.
53
-
54
- The capability ships behind `IUMBTEMS_RUN_SCOPED=1` rather than flipped by
55
- default: it changes every artifact path and deserves a live end-to-end run
56
- before it becomes the default (see issue #6 item 3.9).
57
- """
58
- return os.environ.get("IUMBTEMS_RUN_SCOPED", "").strip().lower() in (
59
- "1",
60
- "true",
61
- "yes",
62
- "on",
63
- )
64
-
65
-
66
- def latest_run_dir(workspace: Path) -> Optional[Path]:
67
- """The run dir a `latest.json` pointer refers to, if any."""
68
- try:
69
- data = json.loads((workspace / LATEST_POINTER).read_text(encoding="utf-8"))
70
- run_id = data.get("run_id")
71
- except (OSError, ValueError):
72
- return None
73
- if not run_id:
74
- return None
75
- candidate = workspace / RUNS_DIRNAME / str(run_id)
76
- return candidate if candidate.is_dir() else None
77
-
78
-
79
- def manifest_name_for_mode(mode: Optional[str]) -> str:
80
- """Manifest filename for a run mode.
81
-
82
- The default research flow keeps the historical `manifest.json`; every other
83
- mode gets its own file so concurrently running tools (e.g. brainstorm and
84
- darkharvest) cannot clobber each other's scope DAG.
85
- """
86
- key = (mode or "").strip().lower()
87
- if key in ("", "research"):
88
- return MANIFEST_FILENAME
89
- return f"manifest.{key}.json"
90
-
91
-
92
- def resolve_manifest_path(base_dir, mode: Optional[str] = None) -> Path:
93
- """Absolute manifest path for a workspace + mode."""
94
- base = Path(os.path.realpath(str(base_dir)))
95
- return base / manifest_name_for_mode(mode)
96
-
97
-
98
- def find_any_manifest(base_dir) -> Optional[Path]:
99
- """Newest manifest in the workspace, preferring the canonical name.
100
-
101
- Understands both layouts: flat (`manifest.json`, `manifest.<mode>.json`) and
102
- run-scoped (`runs/<id>/manifest*.json`, resolved via `latest.json`).
103
- """
104
- base = Path(os.path.realpath(str(base_dir)))
105
- candidates = []
106
- canonical = base / MANIFEST_FILENAME
107
- if canonical.exists():
108
- return canonical
109
- candidates.extend(base.glob("manifest.*.json"))
110
-
111
- run_dir = latest_run_dir(base)
112
- if run_dir is not None:
113
- run_manifest = run_dir / MANIFEST_FILENAME
114
- if run_manifest.exists():
115
- return run_manifest
116
- candidates.extend(run_dir.glob("manifest.*.json"))
117
- if (base / RUNS_DIRNAME).is_dir():
118
- candidates.extend((base / RUNS_DIRNAME).glob("*/manifest*.json"))
119
-
120
- existing = [c for c in candidates if c.exists()]
121
- if not existing:
122
- return None
123
- return max(existing, key=lambda p: p.stat().st_mtime)
124
-
125
-
126
- @contextmanager
127
- def _file_lock(lock_path: Path):
128
- """Cross-process advisory lock over one workspace."""
129
- if fcntl is None:
130
- yield
131
- return
132
- lock_path.parent.mkdir(parents=True, exist_ok=True)
133
- with open(lock_path, "a+", encoding="utf-8") as fh:
134
- fcntl.flock(fh.fileno(), fcntl.LOCK_EX)
135
- try:
136
- yield
137
- finally:
138
- fcntl.flock(fh.fileno(), fcntl.LOCK_UN)
139
-
140
-
141
- def _atomic_write_json(path: Path, data: Any) -> None:
142
- """Write JSON atomically via a UNIQUE temp file + os.replace.
143
-
144
- A fixed `*.tmp` name let concurrent writers collide on the same temp path
145
- (reproduced: `FileNotFoundError: manifest.tmp -> manifest.json`, 758 times
146
- across 4 parallel writers).
147
- """
148
- path.parent.mkdir(parents=True, exist_ok=True)
149
- fd, tmp = tempfile.mkstemp(
150
- dir=str(path.parent), prefix=path.name + ".", suffix=".tmp"
151
- )
152
- try:
153
- with os.fdopen(fd, "w", encoding="utf-8") as f:
154
- json.dump(data, f, indent=2)
155
- os.replace(tmp, path)
156
- except BaseException:
157
- try:
158
- os.unlink(tmp)
159
- except OSError:
160
- pass
161
- raise
162
-
163
-
164
- class ResearchStateMachine:
165
- def __init__(
166
- self,
167
- base_dir: Optional[Path] = None,
168
- mode: Optional[str] = None,
169
- run_scoped: Optional[bool] = None,
170
- run_id: Optional[str] = None,
171
- ):
172
- workspace = Path(os.path.realpath(str(base_dir or ".research")))
173
- if run_scoped is None:
174
- run_scoped = run_scoped_enabled()
175
- self.workspace = workspace
176
- self.run_scoped = bool(run_scoped)
177
- if self.run_scoped:
178
- self.run_id = run_id or (
179
- f"{mode or 'run'}-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}"
180
- )
181
- self.base_dir = workspace / RUNS_DIRNAME / self.run_id
182
- else:
183
- self.run_id = None
184
- self.base_dir = workspace
185
- self.scratchpads_dir = self.base_dir / "scratchpads"
186
- self.sources_dir = self.base_dir / "sources"
187
- self.manifest_file = self.base_dir / manifest_name_for_mode(mode)
188
- self._lock_file = self.base_dir / ".manifest.lock"
189
- self._lock = threading.Lock()
190
-
191
- # Ensure directories exist
192
- self.scratchpads_dir.mkdir(parents=True, exist_ok=True)
193
- self.sources_dir.mkdir(parents=True, exist_ok=True)
194
- if self.run_scoped:
195
- self._write_latest_pointer(mode)
196
-
197
- def _write_latest_pointer(self, mode: Optional[str]) -> None:
198
- try:
199
- (self.workspace / LATEST_POINTER).write_text(
200
- json.dumps({"run_id": self.run_id, "mode": mode}), encoding="utf-8"
201
- )
202
- except OSError:
203
- pass
204
-
205
- def init_session(
206
- self, objective: str, session_id: Optional[str] = None
207
- ) -> Dict[str, Any]:
208
- """Initialize or reset a research session manifest."""
209
- sid = (
210
- session_id
211
- or f"session-{datetime.now(timezone.utc).strftime('%Y%m%d-%H%M%S')}"
212
- )
213
- manifest = {
214
- "session_id": sid,
215
- "objective": objective,
216
- "status": SessionStatus.INITIALIZING.value,
217
- "created_at": datetime.now(timezone.utc).isoformat(),
218
- "updated_at": datetime.now(timezone.utc).isoformat(),
219
- "scopes": [],
220
- "telemetry": {
221
- "total_scopes": 0,
222
- "completed_scopes": 0,
223
- "total_claims_audited": 0,
224
- "total_verified_claims": 0,
225
- "total_rejected_claims": 0,
226
- "mean_epistemic_score": 0.0,
227
- "mean_divergence_score": 0.0,
228
- },
229
- }
230
- self.save_global_manifest(manifest)
231
- return manifest
232
-
233
- def record_preflight(
234
- self,
235
- report: Dict[str, Any],
236
- backend: Optional[str] = None,
237
- divergence_threshold: Optional[float] = None,
238
- ) -> None:
239
- """Persist the preflight report + plugin version into the manifest.
240
-
241
- `divergence_threshold` is recorded for reference only (advisory — it
242
- never gates a verdict; see `runner/schemas.py` CONFIG).
243
- """
244
- with self._lock, _file_lock(self._lock_file):
245
- try:
246
- manifest = self._read_manifest_unlocked()
247
- except FileNotFoundError:
248
- # Dry runs / pre-orchestration: keep the report rather than fail.
249
- manifest = {"preflight": report}
250
- manifest["preflight"] = report
251
- version = report.get("plugin_version")
252
- if version:
253
- manifest["plugin_version"] = version
254
- if backend:
255
- manifest["backend"] = backend
256
- if divergence_threshold is not None:
257
- manifest["divergence_threshold"] = divergence_threshold
258
- self._write_manifest_unlocked(manifest)
259
-
260
- def _read_manifest_unlocked(self) -> Dict[str, Any]:
261
- if not self.manifest_file.exists():
262
- raise FileNotFoundError(
263
- f"Global manifest not found at {self.manifest_file}"
264
- )
265
- with open(self.manifest_file, "r", encoding="utf-8") as f:
266
- return json.load(f)
267
-
268
- def _write_manifest_unlocked(self, manifest: Dict[str, Any]) -> None:
269
- manifest["updated_at"] = datetime.now(timezone.utc).isoformat()
270
- _atomic_write_json(self.manifest_file, manifest)
271
-
272
- def load_global_manifest(self) -> Dict[str, Any]:
273
- with self._lock:
274
- return self._read_manifest_unlocked()
275
-
276
- def set_manifest_fields(self, **fields: Any) -> None:
277
- """Set runner-owned top-level manifest fields under the cross-process lock.
278
-
279
- Used for advisory bookkeeping (e.g. the recorded divergence threshold)
280
- that must survive `init_session` re-initialization. Never invents a
281
- manifest: when none exists yet, one is created with just these fields.
282
- """
283
- if not fields:
284
- return
285
- with self._lock, _file_lock(self._lock_file):
286
- try:
287
- manifest = self._read_manifest_unlocked()
288
- except FileNotFoundError:
289
- manifest = {}
290
- manifest.update(fields)
291
- self._write_manifest_unlocked(manifest)
292
-
293
- def save_global_manifest(self, manifest: Dict[str, Any]):
294
- with self._lock, _file_lock(self._lock_file):
295
- self._write_manifest_unlocked(manifest)
296
-
297
- def update_session_status(self, status: SessionStatus):
298
- # Read-modify-write under the cross-process lock so a concurrent writer
299
- # cannot lose this update.
300
- with self._lock, _file_lock(self._lock_file):
301
- manifest = self._read_manifest_unlocked()
302
- manifest["status"] = status.value
303
- self._write_manifest_unlocked(manifest)
304
-
305
- def set_scopes(self, scopes: List[Dict[str, Any]]):
306
- """Set scopes decomposed by orchestrator and prepare scratchpads."""
307
- with self._lock, _file_lock(self._lock_file):
308
- manifest = self._read_manifest_unlocked()
309
- manifest["scopes"] = scopes
310
- manifest.setdefault("telemetry", {})["total_scopes"] = len(scopes)
311
- self._write_manifest_unlocked(manifest)
312
-
313
- for scope in scopes:
314
- scope_id = scope["scope_id"]
315
- scope_dir = self.scratchpads_dir / scope_id
316
- scope_dir.mkdir(parents=True, exist_ok=True)
317
-
318
- scope_manifest = {
319
- "scope_id": scope_id,
320
- "title": scope.get("title", ""),
321
- "objective": scope.get("objective", ""),
322
- "dependencies": scope.get("dependencies", []),
323
- "status": ScopeStatus.PENDING.value,
324
- "alpha_completed": False,
325
- "beta_completed": False,
326
- "audit_completed": False,
327
- "created_at": datetime.now(timezone.utc).isoformat(),
328
- }
329
- _atomic_write_json(scope_dir / MANIFEST_FILENAME, scope_manifest)
330
-
331
- def get_scope_dir(self, scope_id: str) -> Path:
332
- return self.scratchpads_dir / scope_id
333
-
334
- def find_orphan_scopes(self) -> List[Dict[str, Any]]:
335
- """Scope dirs not referenced by any manifest — marked, never deleted.
336
-
337
- A dir may belong to a concurrently running session, so this reports
338
- rather than prunes (issue #5 layer 6: 14 manifest-only leftovers).
339
- """
340
- referenced: set = set()
341
- manifests = [self.manifest_file, *self.base_dir.glob("manifest.*.json")]
342
- for manifest_path in manifests:
343
- if not manifest_path.exists():
344
- continue
345
- try:
346
- data = json.loads(manifest_path.read_text(encoding="utf-8"))
347
- except (OSError, ValueError):
348
- continue
349
- for scope in data.get("scopes") or []:
350
- if isinstance(scope, dict) and scope.get("scope_id"):
351
- referenced.add(scope["scope_id"])
352
-
353
- orphans: List[Dict[str, Any]] = []
354
- if not self.scratchpads_dir.is_dir():
355
- return orphans
356
- for scope_dir in sorted(self.scratchpads_dir.iterdir()):
357
- if not scope_dir.is_dir() or scope_dir.name in referenced:
358
- continue
359
- orphans.append(
360
- {
361
- "scope_id": scope_dir.name,
362
- "path": str(scope_dir),
363
- "alpha_dossier": (scope_dir / "alpha_dossier.json").exists(),
364
- "beta_dossier": (scope_dir / "beta_dossier.json").exists(),
365
- }
366
- )
367
- return orphans
368
-
369
- def _read_scope_unlocked(self, scope_id: str) -> Dict[str, Any]:
370
- scope_manifest_file = self.get_scope_dir(scope_id) / MANIFEST_FILENAME
371
- if not scope_manifest_file.exists():
372
- raise FileNotFoundError(f"Scope manifest not found for {scope_id}")
373
- with open(scope_manifest_file, "r", encoding="utf-8") as f:
374
- return json.load(f)
375
-
376
- def _write_scope_unlocked(self, scope_id: str, manifest: Dict[str, Any]) -> None:
377
- _atomic_write_json(self.get_scope_dir(scope_id) / MANIFEST_FILENAME, manifest)
378
-
379
- def load_scope_manifest(self, scope_id: str) -> Dict[str, Any]:
380
- with self._lock:
381
- return self._read_scope_unlocked(scope_id)
382
-
383
- def save_scope_manifest(self, scope_id: str, manifest: Dict[str, Any]):
384
- with self._lock, _file_lock(self._lock_file):
385
- self._write_scope_unlocked(scope_id, manifest)
386
-
387
- def update_scope_status(self, scope_id: str, status: ScopeStatus):
388
- with self._lock, _file_lock(self._lock_file):
389
- sm = self._read_scope_unlocked(scope_id)
390
- sm["status"] = status.value
391
- self._write_scope_unlocked(scope_id, sm)
392
-
393
- def record_agent_completion(
394
- self, scope_id: str, agent_type: str, dossier_data: Dict[str, Any]
395
- ):
396
- """Records dossier from Alpha or Beta and advances scope state machine."""
397
- scope_dir = self.get_scope_dir(scope_id)
398
-
399
- if agent_type.lower() in ["alpha", "thesis", "proponent"]:
400
- filename = "alpha_dossier.json"
401
- elif agent_type.lower() in ["beta", "antithesis", "adversary", "red_team"]:
402
- filename = "beta_dossier.json"
403
- else:
404
- raise ValueError(f"Unknown agent type: {agent_type}")
405
-
406
- _atomic_write_json(scope_dir / filename, dossier_data)
407
- self.reconcile_scope_status(scope_id)
408
-
409
- def _artifacts_complete(self, scope_id: str) -> tuple:
410
- """(alpha, beta) dossier presence, derived from disk — never from stored flags."""
411
- scope_dir = self.get_scope_dir(scope_id)
412
- return (
413
- (scope_dir / "alpha_dossier.json").exists(),
414
- (scope_dir / "beta_dossier.json").exists(),
415
- )
416
-
417
- def reconcile_scope_status(self, scope_id: str) -> Dict[str, Any]:
418
- """Recompute completion flags + status from dossier artifacts on disk.
419
-
420
- The scope manifest is runner-owned, but agents can write to the workspace
421
- and have forged `beta_completed: true` / `DOSSIERS_READY` without emitting
422
- the dossier. Deriving from files means stored booleans can never disagree
423
- with reality.
424
- """
425
- alpha, beta = self._artifacts_complete(scope_id)
426
- with self._lock, _file_lock(self._lock_file):
427
- sm = self._read_scope_unlocked(scope_id)
428
- sm["alpha_completed"] = alpha
429
- sm["beta_completed"] = beta
430
- if sm.get("audit_completed"):
431
- sm["status"] = ScopeStatus.COMPLETE.value
432
- elif alpha and beta:
433
- sm["status"] = ScopeStatus.DOSSIERS_READY.value
434
- elif alpha:
435
- sm["status"] = ScopeStatus.ALPHA_COMPLETE.value
436
- elif beta:
437
- sm["status"] = ScopeStatus.BETA_COMPLETE.value
438
- elif sm.get("status") not in (
439
- ScopeStatus.RUNNING_PARALLEL.value,
440
- ScopeStatus.AUDITING.value,
441
- ):
442
- sm["status"] = ScopeStatus.PENDING.value
443
- self._write_scope_unlocked(scope_id, sm)
444
- return sm
445
-
446
- def get_ready_scopes(self) -> List[Dict[str, Any]]:
447
- """Return scopes whose dependencies are completed and status is PENDING."""
448
- manifest = self.load_global_manifest()
449
- ready = []
450
- completed_scope_ids = {
451
- s["scope_id"]
452
- for s in manifest["scopes"]
453
- if self.load_scope_manifest(s["scope_id"]).get("status")
454
- == ScopeStatus.COMPLETE.value
455
- }
456
-
457
- for scope in manifest["scopes"]:
458
- sm = self.load_scope_manifest(scope["scope_id"])
459
- if sm["status"] == ScopeStatus.PENDING.value:
460
- deps = set(scope.get("dependencies", []))
461
- if deps.issubset(completed_scope_ids):
462
- ready.append(scope)
463
- return ready
@@ -1,35 +0,0 @@
1
- {
2
- "objective_set": "auction-f-v1",
3
- "note": "Fixed 4-scope objective for the Stream F auction-vs-DAG probe. Stable set: do not edit between runs, or wall-clock and claims/token are not comparable.",
4
- "objective": "Evaluate the operational envelope of content-addressed research caches for long-lived engineering briefs",
5
- "scopes": [
6
- {
7
- "scope_id": "scope_01_integrity",
8
- "title": "Tamper evidence in content-addressed caches",
9
- "objective": "Assess mechanisms for detecting tampering in SHA-256 addressed document caches",
10
- "dependencies": [],
11
- "bid": 4.0
12
- },
13
- {
14
- "scope_id": "scope_02_staleness",
15
- "title": "Claim staleness and source retraction",
16
- "objective": "Determine how retraction and revision events should degrade previously verified claims",
17
- "dependencies": ["scope_01_integrity"],
18
- "bid": 3.0
19
- },
20
- {
21
- "scope_id": "scope_03_portability",
22
- "title": "Portable proof-carrying briefs",
23
- "objective": "Evaluate self-contained signed brief bundles for third-party re-verification",
24
- "dependencies": [],
25
- "bid": 2.0
26
- },
27
- {
28
- "scope_id": "scope_04_allocation",
29
- "title": "Research resource allocation policies",
30
- "objective": "Compare static DAG ordering versus bid-based allocation of dialectic research scopes",
31
- "dependencies": [],
32
- "bid": 1.0
33
- }
34
- ]
35
- }
@@ -1,27 +0,0 @@
1
- {
2
- "fixture_id": "borderline-g-v1",
3
- "note": "20 borderline claims for the Domain Packs probe. Mechanisms: 6 banned-domain, 2 missing-tag, 2 retracted-source (see retracted_hashes), 10 clean preprint-tier. Default constitution should ACCEPT all 20; biopharma should REJECT >= 25%.",
4
- "retracted_hashes": ["RETRACTED_SRC_A", "RETRACTED_SRC_B"],
5
- "claims": [
6
- {"claim_id": "BB-01", "tag": "VERIFIED", "statement": "Cohort endpoint met primary efficacy bar", "source_hash": "PREPRINT_01", "source_url": "https://banned-preprint-mirror.example/p1", "verbatim_quote": "primary efficacy bar met", "tier": "PREPRINT"},
7
- {"claim_id": "BB-02", "tag": "VERIFIED", "statement": "Adverse event rate within expected band", "source_hash": "PREPRINT_02", "source_url": "https://banned-preprint-mirror.example/p2", "verbatim_quote": "within expected band", "tier": "PREPRINT"},
8
- {"claim_id": "BB-03", "tag": "VERIFIED", "statement": "Secondary endpoint shows dose response", "source_hash": "PREPRINT_03", "source_url": "https://banned-preprint-mirror.example/p3", "verbatim_quote": "dose response observed", "tier": "PREPRINT"},
9
- {"claim_id": "BB-04", "tag": "VERIFIED", "statement": "Biomarker subgroup analysis favorable", "source_hash": "PREPRINT_04", "source_url": "https://predatory-journal.example/p4", "verbatim_quote": "subgroup analysis favorable", "tier": "PREPRINT"},
10
- {"claim_id": "BB-05", "tag": "VERIFIED", "statement": "Pharmacokinetics consistent with model", "source_hash": "PREPRINT_05", "source_url": "https://predatory-journal.example/p5", "verbatim_quote": "consistent with model", "tier": "PREPRINT"},
11
- {"claim_id": "BB-06", "tag": "VERIFIED", "statement": "Manufacturing yield acceptable at scale", "source_hash": "PREPRINT_06", "source_url": "https://banned-preprint-mirror.example/p6", "verbatim_quote": "yield acceptable at scale", "tier": "PREPRINT"},
12
- {"claim_id": "BB-07", "tag": "", "statement": "Untagged assertion lacking epistemic classification", "source_hash": "CLEAN_01", "source_url": "https://journal.example/c1", "verbatim_quote": "assertion recorded without tag", "tier": "PREPRINT"},
13
- {"claim_id": "BB-08", "tag": "", "statement": "Second untagged assertion in the borderline set", "source_hash": "CLEAN_02", "source_url": "https://journal.example/c2", "verbatim_quote": "second assertion without tag", "tier": "PREPRINT"},
14
- {"claim_id": "BB-09", "tag": "VERIFIED", "statement": "Claim resting on a retracted source", "source_hash": "RETRACTED_SRC_A", "source_url": "https://journal.example/r1", "verbatim_quote": "finding later retracted", "tier": "PREPRINT"},
15
- {"claim_id": "BB-10", "tag": "VERIFIED", "statement": "Second claim resting on a retracted source", "source_hash": "RETRACTED_SRC_B", "source_url": "https://journal.example/r2", "verbatim_quote": "second retracted finding", "tier": "PREPRINT"},
16
- {"claim_id": "BB-11", "tag": "VERIFIED", "statement": "Preprint claim near acceptance boundary", "source_hash": "CLEAN_03", "source_url": "https://journal.example/c3", "verbatim_quote": "near acceptance boundary", "tier": "PREPRINT"},
17
- {"claim_id": "BB-12", "tag": "VERIFIED", "statement": "Preprint claim with modest evidence", "source_hash": "CLEAN_04", "source_url": "https://journal.example/c4", "verbatim_quote": "modest evidence presented", "tier": "PREPRINT"},
18
- {"claim_id": "BB-13", "tag": "VERIFIED", "statement": "Preprint claim with weak statistical power", "source_hash": "CLEAN_05", "source_url": "https://journal.example/c5", "verbatim_quote": "weak statistical power", "tier": "PREPRINT"},
19
- {"claim_id": "BB-14", "tag": "VERIFIED", "statement": "Preprint claim awaiting replication", "source_hash": "CLEAN_06", "source_url": "https://journal.example/c6", "verbatim_quote": "awaiting replication", "tier": "PREPRINT"},
20
- {"claim_id": "BB-15", "tag": "VERIFIED", "statement": "Preprint claim with narrow applicability", "source_hash": "CLEAN_07", "source_url": "https://journal.example/c7", "verbatim_quote": "narrow applicability", "tier": "PREPRINT"},
21
- {"claim_id": "BB-16", "tag": "VERIFIED", "statement": "Preprint claim with exploratory endpoint", "source_hash": "CLEAN_08", "source_url": "https://journal.example/c8", "verbatim_quote": "exploratory endpoint", "tier": "PREPRINT"},
22
- {"claim_id": "BB-17", "tag": "VERIFIED", "statement": "Preprint claim with post-hoc analysis", "source_hash": "CLEAN_09", "source_url": "https://journal.example/c9", "verbatim_quote": "post-hoc analysis", "tier": "PREPRINT"},
23
- {"claim_id": "BB-18", "tag": "VERIFIED", "statement": "Preprint claim with surrogate endpoint", "source_hash": "CLEAN_10", "source_url": "https://journal.example/c10", "verbatim_quote": "surrogate endpoint", "tier": "PREPRINT"},
24
- {"claim_id": "BB-19", "tag": "VERIFIED", "statement": "Preprint claim with single-site data", "source_hash": "CLEAN_11", "source_url": "https://journal.example/c11", "verbatim_quote": "single-site data", "tier": "PREPRINT"},
25
- {"claim_id": "BB-20", "tag": "VERIFIED", "statement": "Preprint claim with interim readout", "source_hash": "CLEAN_12", "source_url": "https://journal.example/c12", "verbatim_quote": "interim readout", "tier": "PREPRINT"}
26
- ]
27
- }