@trac3er/oh-my-god 2.1.0 → 2.1.4

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 (371) hide show
  1. package/.agents/skills/omg/AGENTS.fragment.md +2 -2
  2. package/.agents/skills/omg/algorithms/SKILL.md +1 -1
  3. package/.agents/skills/omg/algorithms/openai.yaml +1 -1
  4. package/.agents/skills/omg/api-twin/SKILL.md +1 -1
  5. package/.agents/skills/omg/api-twin/openai.yaml +1 -1
  6. package/.agents/skills/omg/claim-judge/SKILL.md +1 -1
  7. package/.agents/skills/omg/claim-judge/openai.yaml +1 -1
  8. package/.agents/skills/omg/codex-rules.md +1 -1
  9. package/.agents/skills/omg/control-plane/SKILL.md +1 -1
  10. package/.agents/skills/omg/control-plane/openai.yaml +1 -1
  11. package/.agents/skills/omg/data-lineage/SKILL.md +1 -1
  12. package/.agents/skills/omg/data-lineage/openai.yaml +1 -1
  13. package/.agents/skills/omg/delta-classifier/SKILL.md +1 -1
  14. package/.agents/skills/omg/delta-classifier/openai.yaml +1 -1
  15. package/.agents/skills/omg/eval-gate/SKILL.md +1 -1
  16. package/.agents/skills/omg/eval-gate/openai.yaml +1 -1
  17. package/.agents/skills/omg/health/SKILL.md +1 -1
  18. package/.agents/skills/omg/health/openai.yaml +1 -1
  19. package/.agents/skills/omg/hook-governor/SKILL.md +1 -1
  20. package/.agents/skills/omg/hook-governor/openai.yaml +1 -1
  21. package/.agents/skills/omg/incident-replay/SKILL.md +1 -1
  22. package/.agents/skills/omg/incident-replay/openai.yaml +1 -1
  23. package/.agents/skills/omg/lsp-pack/SKILL.md +1 -1
  24. package/.agents/skills/omg/lsp-pack/openai.yaml +1 -1
  25. package/.agents/skills/omg/mcp-fabric/SKILL.md +1 -1
  26. package/.agents/skills/omg/mcp-fabric/openai.yaml +1 -1
  27. package/.agents/skills/omg/plan-council/SKILL.md +1 -1
  28. package/.agents/skills/omg/plan-council/openai.yaml +1 -1
  29. package/.agents/skills/omg/preflight/SKILL.md +1 -1
  30. package/.agents/skills/omg/preflight/openai.yaml +1 -1
  31. package/.agents/skills/omg/proof-gate/SKILL.md +1 -1
  32. package/.agents/skills/omg/proof-gate/openai.yaml +1 -1
  33. package/.agents/skills/omg/remote-supervisor/SKILL.md +1 -1
  34. package/.agents/skills/omg/remote-supervisor/openai.yaml +1 -1
  35. package/.agents/skills/omg/robotics/SKILL.md +1 -1
  36. package/.agents/skills/omg/robotics/openai.yaml +1 -1
  37. package/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +1 -1
  38. package/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +1 -1
  39. package/.agents/skills/omg/security-check/SKILL.md +1 -1
  40. package/.agents/skills/omg/security-check/openai.yaml +1 -1
  41. package/.agents/skills/omg/test-intent-lock/SKILL.md +1 -1
  42. package/.agents/skills/omg/test-intent-lock/openai.yaml +1 -1
  43. package/.agents/skills/omg/tracebank/SKILL.md +1 -1
  44. package/.agents/skills/omg/tracebank/openai.yaml +1 -1
  45. package/.agents/skills/omg/vision/SKILL.md +1 -1
  46. package/.agents/skills/omg/vision/openai.yaml +1 -1
  47. package/.claude-plugin/marketplace.json +3 -3
  48. package/.claude-plugin/plugin.json +1 -1
  49. package/CHANGELOG.md +16 -0
  50. package/CLI-ADAPTER-MAP.md +3 -3
  51. package/OMG-setup.sh +114 -1
  52. package/OMG_COMPAT_CONTRACT.md +1 -1
  53. package/README.md +2 -1
  54. package/artifacts/release/.claude-plugin/marketplace.json +3 -3
  55. package/artifacts/release/.claude-plugin/plugin.json +1 -1
  56. package/artifacts/release/OMG_COMPAT_CONTRACT.md +1 -1
  57. package/artifacts/release/dist/enterprise/bundle/.claude-plugin/marketplace.json +3 -3
  58. package/artifacts/release/dist/enterprise/bundle/.claude-plugin/plugin.json +1 -1
  59. package/artifacts/release/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +1 -1
  60. package/artifacts/release/dist/enterprise/bundle/plugins/advanced/plugin.json +26 -9
  61. package/artifacts/release/dist/enterprise/bundle/registry/bundles/algorithms.yaml +1 -1
  62. package/artifacts/release/dist/enterprise/bundle/registry/bundles/api-twin.yaml +1 -1
  63. package/artifacts/release/dist/enterprise/bundle/registry/bundles/claim-judge.yaml +1 -1
  64. package/artifacts/release/dist/enterprise/bundle/registry/bundles/control-plane.yaml +1 -1
  65. package/artifacts/release/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +1 -1
  66. package/artifacts/release/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +1 -1
  67. package/artifacts/release/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +1 -1
  68. package/artifacts/release/dist/enterprise/bundle/registry/bundles/health.yaml +1 -1
  69. package/artifacts/release/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +1 -1
  70. package/artifacts/release/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +1 -1
  71. package/artifacts/release/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +1 -1
  72. package/artifacts/release/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +1 -1
  73. package/artifacts/release/dist/enterprise/bundle/registry/bundles/plan-council.yaml +1 -1
  74. package/artifacts/release/dist/enterprise/bundle/registry/bundles/preflight.yaml +1 -1
  75. package/artifacts/release/dist/enterprise/bundle/registry/bundles/proof-gate.yaml +1 -1
  76. package/artifacts/release/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +1 -1
  77. package/artifacts/release/dist/enterprise/bundle/registry/bundles/robotics.yaml +1 -1
  78. package/artifacts/release/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  79. package/artifacts/release/dist/enterprise/bundle/registry/bundles/security-check.yaml +1 -1
  80. package/artifacts/release/dist/enterprise/bundle/registry/bundles/test-intent-lock.yaml +1 -1
  81. package/artifacts/release/dist/enterprise/bundle/registry/bundles/tracebank.yaml +1 -1
  82. package/artifacts/release/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
  83. package/artifacts/release/dist/enterprise/bundle/registry/omg-capability.schema.json +1 -1
  84. package/artifacts/release/dist/enterprise/bundle/settings.json +3 -3
  85. package/artifacts/release/dist/enterprise/manifest.json +30 -40
  86. package/artifacts/release/dist/public/bundle/.claude-plugin/marketplace.json +3 -3
  87. package/artifacts/release/dist/public/bundle/.claude-plugin/plugin.json +1 -1
  88. package/artifacts/release/dist/public/bundle/OMG_COMPAT_CONTRACT.md +1 -1
  89. package/artifacts/release/dist/public/bundle/plugins/advanced/plugin.json +26 -9
  90. package/artifacts/release/dist/public/bundle/registry/bundles/algorithms.yaml +1 -1
  91. package/artifacts/release/dist/public/bundle/registry/bundles/api-twin.yaml +1 -1
  92. package/artifacts/release/dist/public/bundle/registry/bundles/claim-judge.yaml +1 -1
  93. package/artifacts/release/dist/public/bundle/registry/bundles/control-plane.yaml +1 -1
  94. package/artifacts/release/dist/public/bundle/registry/bundles/data-lineage.yaml +1 -1
  95. package/artifacts/release/dist/public/bundle/registry/bundles/delta-classifier.yaml +1 -1
  96. package/artifacts/release/dist/public/bundle/registry/bundles/eval-gate.yaml +1 -1
  97. package/artifacts/release/dist/public/bundle/registry/bundles/health.yaml +1 -1
  98. package/artifacts/release/dist/public/bundle/registry/bundles/hook-governor.yaml +1 -1
  99. package/artifacts/release/dist/public/bundle/registry/bundles/incident-replay.yaml +1 -1
  100. package/artifacts/release/dist/public/bundle/registry/bundles/lsp-pack.yaml +1 -1
  101. package/artifacts/release/dist/public/bundle/registry/bundles/mcp-fabric.yaml +1 -1
  102. package/artifacts/release/dist/public/bundle/registry/bundles/plan-council.yaml +1 -1
  103. package/artifacts/release/dist/public/bundle/registry/bundles/preflight.yaml +1 -1
  104. package/artifacts/release/dist/public/bundle/registry/bundles/proof-gate.yaml +1 -1
  105. package/artifacts/release/dist/public/bundle/registry/bundles/remote-supervisor.yaml +1 -1
  106. package/artifacts/release/dist/public/bundle/registry/bundles/robotics.yaml +1 -1
  107. package/artifacts/release/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  108. package/artifacts/release/dist/public/bundle/registry/bundles/security-check.yaml +1 -1
  109. package/artifacts/release/dist/public/bundle/registry/bundles/test-intent-lock.yaml +1 -1
  110. package/artifacts/release/dist/public/bundle/registry/bundles/tracebank.yaml +1 -1
  111. package/artifacts/release/dist/public/bundle/registry/bundles/vision.yaml +1 -1
  112. package/artifacts/release/dist/public/bundle/registry/omg-capability.schema.json +1 -1
  113. package/artifacts/release/dist/public/bundle/settings.json +3 -3
  114. package/artifacts/release/dist/public/manifest.json +30 -40
  115. package/artifacts/release/plugins/advanced/plugin.json +26 -9
  116. package/artifacts/release/registry/bundles/algorithms.yaml +1 -1
  117. package/artifacts/release/registry/bundles/api-twin.yaml +1 -1
  118. package/artifacts/release/registry/bundles/claim-judge.yaml +1 -1
  119. package/artifacts/release/registry/bundles/control-plane.yaml +1 -1
  120. package/artifacts/release/registry/bundles/data-lineage.yaml +1 -1
  121. package/artifacts/release/registry/bundles/delta-classifier.yaml +1 -1
  122. package/artifacts/release/registry/bundles/eval-gate.yaml +1 -1
  123. package/artifacts/release/registry/bundles/health.yaml +1 -1
  124. package/artifacts/release/registry/bundles/hook-governor.yaml +1 -1
  125. package/artifacts/release/registry/bundles/incident-replay.yaml +1 -1
  126. package/artifacts/release/registry/bundles/lsp-pack.yaml +1 -1
  127. package/artifacts/release/registry/bundles/mcp-fabric.yaml +1 -1
  128. package/artifacts/release/registry/bundles/plan-council.yaml +1 -1
  129. package/artifacts/release/registry/bundles/preflight.yaml +1 -1
  130. package/artifacts/release/registry/bundles/proof-gate.yaml +1 -1
  131. package/artifacts/release/registry/bundles/remote-supervisor.yaml +1 -1
  132. package/artifacts/release/registry/bundles/robotics.yaml +1 -1
  133. package/artifacts/release/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  134. package/artifacts/release/registry/bundles/security-check.yaml +1 -1
  135. package/artifacts/release/registry/bundles/test-intent-lock.yaml +1 -1
  136. package/artifacts/release/registry/bundles/tracebank.yaml +1 -1
  137. package/artifacts/release/registry/bundles/vision.yaml +1 -1
  138. package/artifacts/release/registry/omg-capability.schema.json +1 -1
  139. package/artifacts/release/settings.json +3 -3
  140. package/build/lib/commands/OMG:profile-review.md +43 -0
  141. package/build/lib/commands/OMG:validate.md +59 -0
  142. package/build/lib/control_plane/service.py +40 -1
  143. package/build/lib/hooks/_agent_registry.py +2 -0
  144. package/build/lib/hooks/firewall.py +263 -4
  145. package/build/lib/hooks/intentgate-keyword-detector.py +15 -3
  146. package/build/lib/hooks/policy_engine.py +77 -0
  147. package/build/lib/hooks/prompt-enhancer.py +146 -0
  148. package/build/lib/hooks/session-end-capture.py +374 -6
  149. package/build/lib/hooks/session-start.py +13 -35
  150. package/build/lib/hooks/setup_wizard.py +333 -1
  151. package/build/lib/hooks/shadow_manager.py +111 -2
  152. package/build/lib/hooks/stop_dispatcher.py +108 -4
  153. package/build/lib/plugins/advanced/plugin.json +26 -9
  154. package/build/lib/plugins/core/plugin.json +44 -11
  155. package/build/lib/registry/bundles/algorithms.yaml +1 -1
  156. package/build/lib/registry/bundles/api-twin.yaml +1 -1
  157. package/build/lib/registry/bundles/claim-judge.yaml +1 -1
  158. package/build/lib/registry/bundles/control-plane.yaml +1 -1
  159. package/build/lib/registry/bundles/data-lineage.yaml +1 -1
  160. package/build/lib/registry/bundles/delta-classifier.yaml +1 -1
  161. package/build/lib/registry/bundles/eval-gate.yaml +1 -1
  162. package/build/lib/registry/bundles/health.yaml +1 -1
  163. package/build/lib/registry/bundles/hook-governor.yaml +1 -1
  164. package/build/lib/registry/bundles/incident-replay.yaml +1 -1
  165. package/build/lib/registry/bundles/lsp-pack.yaml +1 -1
  166. package/build/lib/registry/bundles/mcp-fabric.yaml +1 -1
  167. package/build/lib/registry/bundles/plan-council.yaml +1 -1
  168. package/build/lib/registry/bundles/preflight.yaml +1 -1
  169. package/build/lib/registry/bundles/proof-gate.yaml +1 -1
  170. package/build/lib/registry/bundles/remote-supervisor.yaml +1 -1
  171. package/build/lib/registry/bundles/robotics.yaml +1 -1
  172. package/build/lib/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  173. package/build/lib/registry/bundles/security-check.yaml +1 -1
  174. package/build/lib/registry/bundles/test-intent-lock.yaml +1 -1
  175. package/build/lib/registry/bundles/tracebank.yaml +1 -1
  176. package/build/lib/registry/bundles/vision.yaml +1 -1
  177. package/build/lib/registry/omg-capability.schema.json +1 -1
  178. package/build/lib/runtime/adoption.py +1 -1
  179. package/build/lib/runtime/background_verification.py +62 -0
  180. package/build/lib/runtime/claim_judge.py +165 -5
  181. package/build/lib/runtime/compat.py +15 -1
  182. package/build/lib/runtime/context_engine.py +261 -4
  183. package/build/lib/runtime/contract_compiler.py +370 -93
  184. package/build/lib/runtime/defense_state.py +79 -8
  185. package/build/lib/runtime/delta_classifier.py +80 -2
  186. package/build/lib/runtime/evidence_query.py +56 -4
  187. package/build/lib/runtime/evidence_registry.py +16 -0
  188. package/build/lib/runtime/evidence_requirements.py +47 -0
  189. package/build/lib/runtime/forge_agents.py +179 -9
  190. package/build/lib/runtime/forge_contracts.py +208 -2
  191. package/build/lib/runtime/interaction_journal.py +318 -42
  192. package/build/lib/runtime/memory_store.py +134 -1
  193. package/build/lib/runtime/mutation_gate.py +57 -11
  194. package/build/lib/runtime/omg_compat_contract_snapshot.json +2 -2
  195. package/build/lib/runtime/omg_mcp_server.py +14 -4
  196. package/build/lib/runtime/preflight.py +14 -0
  197. package/build/lib/runtime/profile_io.py +294 -0
  198. package/build/lib/runtime/proof_gate.py +122 -7
  199. package/build/lib/runtime/release_run_coordinator.py +339 -0
  200. package/build/lib/runtime/release_surfaces.py +243 -0
  201. package/build/lib/runtime/rollback_manifest.py +136 -0
  202. package/build/lib/runtime/router_critics.py +50 -0
  203. package/build/lib/runtime/runtime_contracts.py +137 -0
  204. package/build/lib/runtime/security_check.py +16 -0
  205. package/build/lib/runtime/session_health.py +60 -16
  206. package/build/lib/runtime/team_router.py +156 -13
  207. package/build/lib/runtime/test_intent_lock.py +102 -0
  208. package/build/lib/runtime/tool_plan_gate.py +249 -24
  209. package/build/lib/runtime/validate.py +194 -0
  210. package/build/lib/runtime/verification_controller.py +52 -2
  211. package/commands/OMG:diagnose-plugins.md +33 -0
  212. package/commands/OMG:profile-review.md +43 -0
  213. package/commands/OMG:setup.md +4 -1
  214. package/commands/OMG:validate.md +59 -0
  215. package/control_plane/service.py +40 -1
  216. package/dist/enterprise/bundle/.claude-plugin/marketplace.json +3 -3
  217. package/dist/enterprise/bundle/.claude-plugin/plugin.json +1 -1
  218. package/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +1 -1
  219. package/dist/enterprise/bundle/plugins/advanced/plugin.json +26 -9
  220. package/dist/enterprise/bundle/registry/bundles/algorithms.yaml +1 -1
  221. package/dist/enterprise/bundle/registry/bundles/api-twin.yaml +1 -1
  222. package/dist/enterprise/bundle/registry/bundles/claim-judge.yaml +1 -1
  223. package/dist/enterprise/bundle/registry/bundles/control-plane.yaml +1 -1
  224. package/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +1 -1
  225. package/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +1 -1
  226. package/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +1 -1
  227. package/dist/enterprise/bundle/registry/bundles/health.yaml +1 -1
  228. package/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +1 -1
  229. package/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +1 -1
  230. package/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +1 -1
  231. package/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +1 -1
  232. package/dist/enterprise/bundle/registry/bundles/plan-council.yaml +1 -1
  233. package/dist/enterprise/bundle/registry/bundles/preflight.yaml +1 -1
  234. package/dist/enterprise/bundle/registry/bundles/proof-gate.yaml +1 -1
  235. package/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +1 -1
  236. package/dist/enterprise/bundle/registry/bundles/robotics.yaml +1 -1
  237. package/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  238. package/dist/enterprise/bundle/registry/bundles/security-check.yaml +1 -1
  239. package/dist/enterprise/bundle/registry/bundles/test-intent-lock.yaml +1 -1
  240. package/dist/enterprise/bundle/registry/bundles/tracebank.yaml +1 -1
  241. package/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
  242. package/dist/enterprise/bundle/registry/omg-capability.schema.json +1 -1
  243. package/dist/enterprise/bundle/settings.json +3 -3
  244. package/dist/enterprise/manifest.json +30 -40
  245. package/dist/oh_my_god-2.1.4-py3-none-any.whl +0 -0
  246. package/dist/oh_my_god-2.1.4.tar.gz +0 -0
  247. package/dist/public/bundle/.claude-plugin/marketplace.json +3 -3
  248. package/dist/public/bundle/.claude-plugin/plugin.json +1 -1
  249. package/dist/public/bundle/OMG_COMPAT_CONTRACT.md +1 -1
  250. package/dist/public/bundle/plugins/advanced/plugin.json +26 -9
  251. package/dist/public/bundle/registry/bundles/algorithms.yaml +1 -1
  252. package/dist/public/bundle/registry/bundles/api-twin.yaml +1 -1
  253. package/dist/public/bundle/registry/bundles/claim-judge.yaml +1 -1
  254. package/dist/public/bundle/registry/bundles/control-plane.yaml +1 -1
  255. package/dist/public/bundle/registry/bundles/data-lineage.yaml +1 -1
  256. package/dist/public/bundle/registry/bundles/delta-classifier.yaml +1 -1
  257. package/dist/public/bundle/registry/bundles/eval-gate.yaml +1 -1
  258. package/dist/public/bundle/registry/bundles/health.yaml +1 -1
  259. package/dist/public/bundle/registry/bundles/hook-governor.yaml +1 -1
  260. package/dist/public/bundle/registry/bundles/incident-replay.yaml +1 -1
  261. package/dist/public/bundle/registry/bundles/lsp-pack.yaml +1 -1
  262. package/dist/public/bundle/registry/bundles/mcp-fabric.yaml +1 -1
  263. package/dist/public/bundle/registry/bundles/plan-council.yaml +1 -1
  264. package/dist/public/bundle/registry/bundles/preflight.yaml +1 -1
  265. package/dist/public/bundle/registry/bundles/proof-gate.yaml +1 -1
  266. package/dist/public/bundle/registry/bundles/remote-supervisor.yaml +1 -1
  267. package/dist/public/bundle/registry/bundles/robotics.yaml +1 -1
  268. package/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  269. package/dist/public/bundle/registry/bundles/security-check.yaml +1 -1
  270. package/dist/public/bundle/registry/bundles/test-intent-lock.yaml +1 -1
  271. package/dist/public/bundle/registry/bundles/tracebank.yaml +1 -1
  272. package/dist/public/bundle/registry/bundles/vision.yaml +1 -1
  273. package/dist/public/bundle/registry/omg-capability.schema.json +1 -1
  274. package/dist/public/bundle/settings.json +3 -3
  275. package/dist/public/manifest.json +30 -40
  276. package/docs/install/opencode.md +30 -0
  277. package/docs/proof.md +11 -0
  278. package/docs/release-checklist.md +14 -1
  279. package/hooks/_agent_registry.py +2 -0
  280. package/hooks/firewall.py +263 -4
  281. package/hooks/intentgate-keyword-detector.py +15 -3
  282. package/hooks/policy_engine.py +77 -0
  283. package/hooks/prompt-enhancer.py +146 -0
  284. package/hooks/session-end-capture.py +374 -6
  285. package/hooks/session-start.py +13 -35
  286. package/hooks/setup_wizard.py +342 -2
  287. package/hooks/shadow_manager.py +111 -2
  288. package/hooks/stop_dispatcher.py +108 -4
  289. package/hud/omg-hud.mjs +30 -6
  290. package/lab/pipeline.py +197 -26
  291. package/package.json +1 -1
  292. package/plugins/advanced/plugin.json +26 -9
  293. package/plugins/core/plugin.json +51 -12
  294. package/pyproject.toml +10 -2
  295. package/registry/bundles/algorithms.yaml +1 -1
  296. package/registry/bundles/api-twin.yaml +1 -1
  297. package/registry/bundles/claim-judge.yaml +1 -1
  298. package/registry/bundles/control-plane.yaml +1 -1
  299. package/registry/bundles/data-lineage.yaml +1 -1
  300. package/registry/bundles/delta-classifier.yaml +1 -1
  301. package/registry/bundles/eval-gate.yaml +1 -1
  302. package/registry/bundles/health.yaml +1 -1
  303. package/registry/bundles/hook-governor.yaml +1 -1
  304. package/registry/bundles/incident-replay.yaml +1 -1
  305. package/registry/bundles/lsp-pack.yaml +1 -1
  306. package/registry/bundles/mcp-fabric.yaml +1 -1
  307. package/registry/bundles/plan-council.yaml +1 -1
  308. package/registry/bundles/preflight.yaml +1 -1
  309. package/registry/bundles/proof-gate.yaml +1 -1
  310. package/registry/bundles/remote-supervisor.yaml +1 -1
  311. package/registry/bundles/robotics.yaml +1 -1
  312. package/registry/bundles/secure-worktree-pipeline.yaml +1 -1
  313. package/registry/bundles/security-check.yaml +1 -1
  314. package/registry/bundles/test-intent-lock.yaml +1 -1
  315. package/registry/bundles/tracebank.yaml +1 -1
  316. package/registry/bundles/vision.yaml +1 -1
  317. package/registry/omg-capability.schema.json +1 -1
  318. package/runtime/adoption.py +7 -5
  319. package/runtime/background_verification.py +62 -0
  320. package/runtime/claim_judge.py +165 -5
  321. package/runtime/compat.py +48 -1
  322. package/runtime/context_engine.py +261 -4
  323. package/runtime/contract_compiler.py +370 -93
  324. package/runtime/defense_state.py +79 -8
  325. package/runtime/delta_classifier.py +80 -2
  326. package/runtime/evidence_query.py +56 -4
  327. package/runtime/evidence_registry.py +16 -0
  328. package/runtime/evidence_requirements.py +47 -0
  329. package/runtime/forge_agents.py +179 -9
  330. package/runtime/forge_contracts.py +208 -2
  331. package/runtime/hook_governor.py +19 -1
  332. package/runtime/interaction_journal.py +318 -42
  333. package/runtime/memory_store.py +134 -1
  334. package/runtime/mutation_gate.py +57 -11
  335. package/runtime/omg_compat_contract_snapshot.json +2 -2
  336. package/runtime/omg_mcp_server.py +14 -4
  337. package/runtime/plugin_diagnostics.py +248 -0
  338. package/runtime/plugin_interop.py +1007 -0
  339. package/runtime/preflight.py +14 -0
  340. package/runtime/profile_io.py +294 -0
  341. package/runtime/proof_gate.py +122 -7
  342. package/runtime/providers/opencode_provider.py +94 -0
  343. package/runtime/release_run_coordinator.py +339 -0
  344. package/runtime/release_surfaces.py +243 -0
  345. package/runtime/rollback_manifest.py +136 -0
  346. package/runtime/router_critics.py +50 -0
  347. package/runtime/runtime_contracts.py +137 -0
  348. package/runtime/security_check.py +16 -0
  349. package/runtime/session_health.py +60 -16
  350. package/runtime/team_router.py +156 -13
  351. package/runtime/test_intent_lock.py +102 -0
  352. package/runtime/tool_plan_gate.py +218 -19
  353. package/runtime/validate.py +289 -0
  354. package/runtime/verification_controller.py +52 -2
  355. package/scripts/omg.py +306 -3
  356. package/scripts/prepare-release-proof-fixtures.py +191 -7
  357. package/scripts/print-canonical-version.py +80 -0
  358. package/scripts/sync-release-identity.py +476 -0
  359. package/scripts/validate-release-identity.py +246 -0
  360. package/scripts/verify-standalone.sh +3 -0
  361. package/settings.json +3 -3
  362. package/templates/plugins-allowlist.yaml +19 -0
  363. package/artifacts/release/dist/enterprise/bundle/.gemini/settings.json +0 -11
  364. package/artifacts/release/dist/enterprise/bundle/.kimi/mcp.json +0 -11
  365. package/artifacts/release/dist/public/bundle/.gemini/settings.json +0 -11
  366. package/artifacts/release/dist/public/bundle/.kimi/mcp.json +0 -11
  367. package/build/lib/yaml.py +0 -321
  368. package/dist/enterprise/bundle/.gemini/settings.json +0 -11
  369. package/dist/enterprise/bundle/.kimi/mcp.json +0 -11
  370. package/dist/public/bundle/.gemini/settings.json +0 -11
  371. package/dist/public/bundle/.kimi/mcp.json +0 -11
@@ -1,7 +1,6 @@
1
1
  """Repo-aware change classification for routing and policy attachment."""
2
2
  from __future__ import annotations
3
3
 
4
- import json
5
4
  from pathlib import Path
6
5
  import subprocess
7
6
  from typing import Any
@@ -21,6 +20,51 @@ _CATEGORY_RULES: dict[str, tuple[str, ...]] = {
21
20
  "algorithms": ("algorithm", "benchmark", "determinism", "complexity"),
22
21
  }
23
22
 
23
+ _DOCS_SUFFIXES: tuple[str, ...] = (
24
+ ".md",
25
+ ".mdx",
26
+ ".rst",
27
+ ".txt",
28
+ )
29
+
30
+ _DOCS_PATH_HINTS: tuple[str, ...] = (
31
+ "docs/",
32
+ "readme",
33
+ "changelog",
34
+ )
35
+
36
+ _SECURITY_CATEGORY_HINTS: tuple[str, ...] = (
37
+ "auth",
38
+ "payment",
39
+ "db",
40
+ "infra",
41
+ "compliance",
42
+ "health",
43
+ )
44
+
45
+ _SECURITY_TOKENS: tuple[str, ...] = (
46
+ "security",
47
+ "secret",
48
+ "vulnerability",
49
+ "audit",
50
+ "hardening",
51
+ )
52
+
53
+ _RELEASE_TOKENS: tuple[str, ...] = (
54
+ "release",
55
+ "publish",
56
+ "ship",
57
+ "cut tag",
58
+ "version bump",
59
+ )
60
+
61
+ _FORGE_TOKENS: tuple[str, ...] = (
62
+ "forge",
63
+ "prototype",
64
+ "evaluation run",
65
+ "lab job",
66
+ )
67
+
24
68
 
25
69
  def classify_project_changes(
26
70
  project_dir: str,
@@ -40,17 +84,51 @@ def classify_project_changes(
40
84
  if not categories:
41
85
  categories.add("implementation")
42
86
 
87
+ sorted_categories = sorted(categories)
43
88
  result = {
44
89
  "schema": "DeltaClassification",
45
90
  "project_dir": project_dir,
46
91
  "goal": goal,
47
- "categories": sorted(categories),
92
+ "categories": sorted_categories,
93
+ "evidence_profile": _classify_evidence_profile(goal=goal, touched_files=files, categories=sorted_categories),
48
94
  "touched_files": files,
49
95
  "manifests": manifest_names,
50
96
  }
51
97
  return result
52
98
 
53
99
 
100
+ def _classify_evidence_profile(*, goal: str, touched_files: list[str], categories: list[str]) -> str:
101
+ lowered_goal = goal.lower()
102
+ lowered_files = [path.lower() for path in touched_files]
103
+
104
+ if _contains_any(lowered_goal, _RELEASE_TOKENS) or any(_contains_any(path, _RELEASE_TOKENS) for path in lowered_files):
105
+ return "release"
106
+
107
+ if _contains_any(lowered_goal, _FORGE_TOKENS) or any(_contains_any(path, _FORGE_TOKENS) for path in lowered_files):
108
+ return "forge-run"
109
+
110
+ if set(categories) & set(_SECURITY_CATEGORY_HINTS):
111
+ return "security-audit"
112
+ if _contains_any(lowered_goal, _SECURITY_TOKENS) or any(_contains_any(path, _SECURITY_TOKENS) for path in lowered_files):
113
+ return "security-audit"
114
+
115
+ if lowered_files and all(_is_docs_file(path) for path in lowered_files):
116
+ return "docs-only"
117
+
118
+ return "code-change"
119
+
120
+
121
+ def _is_docs_file(path: str) -> bool:
122
+ lowered = path.lower()
123
+ if lowered.endswith(_DOCS_SUFFIXES):
124
+ return True
125
+ return any(hint in lowered for hint in _DOCS_PATH_HINTS)
126
+
127
+
128
+ def _contains_any(haystack: str, needles: tuple[str, ...]) -> bool:
129
+ return any(token in haystack for token in needles)
130
+
131
+
54
132
  def _discover_files(project_dir: str) -> list[str]:
55
133
  root = Path(project_dir)
56
134
  git_dir = root / ".git"
@@ -1,9 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import hashlib
4
5
  from pathlib import Path
5
6
  from typing import cast
6
7
 
8
+ from runtime.context_engine import load_profile_digest
9
+ from runtime.evidence_requirements import requirements_for_profile
10
+
7
11
  JsonPrimitive = str | int | float | bool | None
8
12
  JsonValue = JsonPrimitive | dict[str, "JsonValue"] | list["JsonValue"]
9
13
  JsonObject = dict[str, JsonValue]
@@ -35,6 +39,54 @@ def _load_json(path: Path) -> JsonObject | None:
35
39
  return cast(JsonObject, payload)
36
40
 
37
41
 
42
+ def _json_checksum(payload: JsonObject) -> str:
43
+ encoded = json.dumps(payload, sort_keys=True, ensure_ascii=True, separators=(",", ":"))
44
+ return hashlib.sha256(encoded.encode("utf-8", errors="ignore")).hexdigest()
45
+
46
+
47
+ def _record_copy_with_context_metadata(root: Path, record: JsonObject) -> JsonObject:
48
+ run_id = _record_string(record, "run_id")
49
+ if not run_id:
50
+ return record
51
+
52
+ profile_digest = load_profile_digest(root)
53
+ existing_profile_version = _record_string(record, "profile_version")
54
+ profile_version = existing_profile_version or str(profile_digest.get("profile_version", "")).strip()
55
+ evidence_profile = _record_string(record, "evidence_profile").strip()
56
+ evidence_requirements = requirements_for_profile(evidence_profile)
57
+
58
+ intent_gate_payload = _load_json(root / ".omg" / "state" / "intent_gate" / f"{run_id}.json") or {}
59
+ existing_intent_gate_version = _record_string(record, "intent_gate_version")
60
+ intent_gate_version = existing_intent_gate_version or (
61
+ _record_string(intent_gate_payload, "intent_gate_version")
62
+ or _record_string(intent_gate_payload, "schema_version")
63
+ or _record_string(intent_gate_payload, "version")
64
+ )
65
+
66
+ packet_payload = _load_json(root / ".omg" / "state" / "context_engine_packet.json") or {}
67
+ packet_run_id = _record_string(packet_payload, "run_id")
68
+ scoped_packet = packet_payload if packet_run_id == run_id else {}
69
+ context_material: JsonObject = {
70
+ "run_id": run_id,
71
+ "profile_version": profile_version,
72
+ "intent_gate_version": intent_gate_version,
73
+ }
74
+ if scoped_packet:
75
+ context_material["context_packet"] = scoped_packet
76
+ if intent_gate_payload:
77
+ context_material["intent_gate"] = intent_gate_payload
78
+
79
+ existing_context_checksum = _record_string(record, "context_checksum")
80
+ context_checksum = existing_context_checksum or _json_checksum(context_material)
81
+ enriched = dict(record)
82
+ enriched["context_checksum"] = context_checksum
83
+ enriched["profile_version"] = profile_version
84
+ enriched["intent_gate_version"] = intent_gate_version
85
+ enriched["evidence_profile"] = evidence_profile
86
+ enriched["evidence_requirements"] = cast(JsonValue, [str(item) for item in evidence_requirements])
87
+ return enriched
88
+
89
+
38
90
  def _read_jsonl(path: Path) -> list[JsonObject]:
39
91
  if not path.exists():
40
92
  return []
@@ -109,7 +161,7 @@ def get_evidence_pack(project_dir: str, run_id: str) -> JsonObject | None:
109
161
  if payload.get("schema") != "EvidencePack":
110
162
  continue
111
163
  if _record_string(payload, "run_id") == run_id:
112
- return payload
164
+ return _record_copy_with_context_metadata(root, payload)
113
165
  return None
114
166
 
115
167
 
@@ -136,7 +188,7 @@ def query_evidence(
136
188
  schema=schema,
137
189
  kind=kind,
138
190
  ):
139
- records.append(payload)
191
+ records.append(_record_copy_with_context_metadata(root, payload))
140
192
 
141
193
  for row in _read_jsonl(root / rel_dir / "events.jsonl"):
142
194
  if _record_matches(
@@ -146,7 +198,7 @@ def query_evidence(
146
198
  schema=schema,
147
199
  kind=kind,
148
200
  ):
149
- records.append(row)
201
+ records.append(_record_copy_with_context_metadata(root, row))
150
202
 
151
203
  return records
152
204
 
@@ -164,7 +216,7 @@ def list_evidence_packs(project_dir: str) -> list[JsonObject]:
164
216
  mtime = path.stat().st_mtime
165
217
  except OSError:
166
218
  mtime = 0.0
167
- payloads.append((mtime, payload))
219
+ payloads.append((mtime, _record_copy_with_context_metadata(root, payload)))
168
220
 
169
221
  payloads.sort(key=lambda item: item[0], reverse=True)
170
222
  return [payload for _, payload in payloads]
@@ -0,0 +1,16 @@
1
+ """Backward-compatible alias for evidence requirements registry."""
2
+ from __future__ import annotations
3
+
4
+ from importlib import import_module
5
+
6
+ _registry = import_module("runtime.evidence_requirements")
7
+
8
+ EVIDENCE_REQUIREMENTS_BY_PROFILE = getattr(_registry, "EVIDENCE_REQUIREMENTS_BY_PROFILE", {})
9
+ FULL_REQUIREMENTS = getattr(_registry, "FULL_REQUIREMENTS", [])
10
+ requirements_for_profile = getattr(_registry, "requirements_for_profile")
11
+
12
+ __all__ = [
13
+ "EVIDENCE_REQUIREMENTS_BY_PROFILE",
14
+ "FULL_REQUIREMENTS",
15
+ "requirements_for_profile",
16
+ ]
@@ -0,0 +1,47 @@
1
+ """Single-source evidence profile requirements registry."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Final
5
+
6
+ FULL_REQUIREMENTS: Final[list[str]] = [
7
+ "tests",
8
+ "lsp_clean",
9
+ "build",
10
+ "provenance",
11
+ "trust_scores",
12
+ "security_scan",
13
+ "license_scan",
14
+ "sbom",
15
+ "trace_link",
16
+ ]
17
+
18
+ EVIDENCE_REQUIREMENTS_BY_PROFILE: Final[dict[str, list[str]]] = {
19
+ "code-change": [
20
+ "tests",
21
+ "lsp_clean",
22
+ "build",
23
+ "provenance",
24
+ "trace_link",
25
+ ],
26
+ "docs-only": [
27
+ "lsp_clean",
28
+ "trace_link",
29
+ ],
30
+ "forge-run": [
31
+ "tests",
32
+ "lsp_clean",
33
+ "provenance",
34
+ "trace_link",
35
+ ],
36
+ "security-audit": list(FULL_REQUIREMENTS),
37
+ "release": list(FULL_REQUIREMENTS),
38
+ }
39
+
40
+
41
+ def requirements_for_profile(evidence_profile: str | None) -> list[str]:
42
+ if not evidence_profile:
43
+ return list(FULL_REQUIREMENTS)
44
+ requirements = EVIDENCE_REQUIREMENTS_BY_PROFILE.get(evidence_profile)
45
+ if not requirements:
46
+ return list(FULL_REQUIREMENTS)
47
+ return list(requirements)
@@ -1,12 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import importlib
4
+ import importlib.util
3
5
  import json
4
6
  import os
5
7
  from datetime import datetime, timezone
6
8
  from pathlib import Path
7
9
  from typing import Any
8
10
 
9
- from runtime.forge_contracts import load_forge_mvp, validate_forge_job
11
+ from runtime.forge_contracts import ADAPTER_REGISTRY, load_forge_mvp, validate_forge_job
12
+ from runtime.runtime_contracts import read_defense_state, read_session_health
13
+ from runtime.security_check import run_security_check
10
14
 
11
15
 
12
16
  _SPECIALIST_REGISTRY: dict[str, dict[str, object]] = {
@@ -22,6 +26,10 @@ _SPECIALIST_REGISTRY: dict[str, dict[str, object]] = {
22
26
  "description": "Builds simulator-backed evaluations through the PyBullet hook contract.",
23
27
  "capabilities": ["simulator-scenarios", "pybullet-hook-contract", "regression-replay"],
24
28
  },
29
+ "forge-cybersecurity": {
30
+ "description": "Runs labs-bounded cybersecurity hardening and threat-evidence checks.",
31
+ "capabilities": ["threat-modeling", "security-regression", "proof-linked-security-evidence"],
32
+ },
25
33
  }
26
34
 
27
35
  _DOMAIN_SPECIALISTS: dict[str, list[str]] = {
@@ -30,6 +38,7 @@ _DOMAIN_SPECIALISTS: dict[str, list[str]] = {
30
38
  "robotics": ["training-architect", "simulator-engineer"],
31
39
  "algorithms": ["training-architect"],
32
40
  "health": ["data-curator", "training-architect"],
41
+ "cybersecurity": ["forge-cybersecurity"],
33
42
  }
34
43
 
35
44
 
@@ -42,7 +51,33 @@ def get_specialist_registry() -> dict[str, dict[str, object]]:
42
51
  return {name: dict(metadata) for name, metadata in _SPECIALIST_REGISTRY.items()}
43
52
 
44
53
 
45
- def dispatch_specialists(job: dict[str, Any], project_dir: str) -> dict[str, Any]:
54
+
55
+ def _execute_cybersecurity_scan(project_dir: str) -> dict[str, Any]:
56
+ """Run canonical security_check scan for forge-cybersecurity specialist.
57
+
58
+ Reuses runtime/security_check.py engine. Degrades gracefully
59
+ when Semgrep or other external tools are unavailable.
60
+ """
61
+ try:
62
+ return run_security_check(
63
+ project_dir=project_dir,
64
+ scope=".",
65
+ include_live_enrichment=False,
66
+ )
67
+ except Exception:
68
+ return {
69
+ "schema": "SecurityCheckResult",
70
+ "status": "error",
71
+ "scope": ".",
72
+ "findings": [],
73
+ "security_scans": [],
74
+ "unresolved_risks": [],
75
+ "evidence": {},
76
+ "summary": {"scan_status": "failed", "finding_count": 0},
77
+ }
78
+
79
+
80
+ def dispatch_specialists(job: dict[str, Any], project_dir: str, run_id: str | None = None) -> dict[str, Any]:
46
81
  ok, reason = validate_forge_job(job)
47
82
  if not ok:
48
83
  return {
@@ -61,7 +96,7 @@ def dispatch_specialists(job: dict[str, Any], project_dir: str) -> dict[str, Any
61
96
  "status": "blocked",
62
97
  "specialists_dispatched": [],
63
98
  "evidence_path": "",
64
- "reason": f"domain '{domain}' has no specialist contract",
99
+ "reason": "invalid_specialist_domain_combination",
65
100
  }
66
101
 
67
102
  if requested_specialists:
@@ -79,7 +114,7 @@ def dispatch_specialists(job: dict[str, Any], project_dir: str) -> dict[str, Any
79
114
  "status": "blocked",
80
115
  "specialists_dispatched": [],
81
116
  "evidence_path": "",
82
- "reason": f"specialists not allowed for domain '{domain}': {', '.join(invalid_for_domain)}",
117
+ "reason": "invalid_specialist_domain_combination",
83
118
  }
84
119
  missing_required = [name for name in expected_specialists if name not in requested_specialists]
85
120
  if missing_required:
@@ -87,27 +122,66 @@ def dispatch_specialists(job: dict[str, Any], project_dir: str) -> dict[str, Any
87
122
  "status": "blocked",
88
123
  "specialists_dispatched": [],
89
124
  "evidence_path": "",
90
- "reason": f"missing required specialists for domain '{domain}': {', '.join(missing_required)}",
125
+ "reason": "invalid_specialist_domain_combination",
91
126
  }
92
127
 
93
128
  specialists_dispatched = requested_specialists if requested_specialists else expected_specialists
94
129
  status = "ok" if specialists_dispatched else "noop"
95
- run_id = _now_run_id()
130
+ active_run_id = run_id or _now_run_id()
131
+
132
+ job_with_specialists = dict(job)
133
+ job_with_specialists["specialists"] = specialists_dispatched
134
+ adapter_evidence = resolve_adapters(job_with_specialists)
135
+
136
+ backends_ok, backends_reason = check_required_backends_satisfied(adapter_evidence)
137
+ if not backends_ok:
138
+ return {
139
+ "status": "blocked",
140
+ "specialists_dispatched": specialists_dispatched,
141
+ "evidence_path": "",
142
+ "reason": backends_reason,
143
+ "adapter_evidence": adapter_evidence,
144
+ }
145
+
146
+ security_scan: dict[str, Any] | None = None
147
+ if "forge-cybersecurity" in specialists_dispatched:
148
+ security_scan = _execute_cybersecurity_scan(project_dir)
149
+
96
150
  evidence_path = _write_dispatch_evidence(
97
151
  project_dir=project_dir,
98
- run_id=run_id,
152
+ run_id=active_run_id,
153
+ snapshot_run_id=run_id,
99
154
  status=status,
100
155
  domain=domain,
101
156
  expected_specialists=expected_specialists,
102
157
  requested_specialists=requested_specialists,
103
158
  specialists_dispatched=specialists_dispatched,
104
159
  job=job,
160
+ security_scan=security_scan,
105
161
  )
106
- return {
162
+ result_payload: dict[str, Any] = {
107
163
  "status": status,
108
164
  "specialists_dispatched": specialists_dispatched,
165
+ "run_id": active_run_id,
109
166
  "evidence_path": evidence_path,
167
+ "adapter_evidence": adapter_evidence,
110
168
  }
169
+ if security_scan is not None:
170
+ result_payload["security_scan"] = security_scan
171
+ return result_payload
172
+
173
+
174
+ def _resolve_specialist_contracts(contract: dict[str, object], specialists: list[str]) -> dict[str, dict[str, object]]:
175
+ raw_contracts = contract.get("specialist_contracts")
176
+ if not isinstance(raw_contracts, dict):
177
+ return {}
178
+
179
+ selected: dict[str, dict[str, object]] = {}
180
+ for name in specialists:
181
+ entry = raw_contracts.get(name)
182
+ if isinstance(entry, dict):
183
+ selected[name] = dict(entry)
184
+ return selected
111
185
 
112
186
 
113
187
  def _normalize_specialist_list(value: object) -> list[str]:
@@ -125,27 +199,106 @@ def _now_run_id() -> str:
125
199
  return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ")
126
200
 
127
201
 
202
+ def _check_backend_available(backend_name: str) -> bool:
203
+ entry = ADAPTER_REGISTRY.get(backend_name)
204
+ if entry is None:
205
+ return False
206
+ module_name = str(entry.get("module", ""))
207
+ if not module_name:
208
+ return False
209
+ try:
210
+ return importlib.util.find_spec(module_name) is not None
211
+ except Exception:
212
+ return False
213
+
214
+
215
+ def _check_axolotl_available() -> bool:
216
+ return _check_backend_available("axolotl")
217
+
218
+
219
+ def _check_simulator_available(name: str) -> bool:
220
+ return _check_backend_available(name)
221
+
222
+
223
+ def resolve_adapters(job: dict[str, Any]) -> list[dict[str, object]]:
224
+ results: list[dict[str, object]] = []
225
+ dispatched_specialists = job.get("specialists", [])
226
+ if not isinstance(dispatched_specialists, list):
227
+ dispatched_specialists = []
228
+
229
+ requested_backend = str(job.get("simulator_backend", "")).strip().lower()
230
+ require_backend = bool(job.get("require_backend", False))
231
+
232
+ if "training-architect" in dispatched_specialists:
233
+ available = _check_axolotl_available()
234
+ results.append({
235
+ "adapter": "axolotl",
236
+ "kind": "training",
237
+ "status": "invoked" if available else "skipped_unavailable_backend",
238
+ "required": require_backend and requested_backend == "axolotl",
239
+ "reason": "" if available else "axolotl not installed",
240
+ "available": available,
241
+ })
242
+
243
+ if "simulator-engineer" in dispatched_specialists:
244
+ simulator_backends = _resolve_simulator_backends(requested_backend)
245
+ for backend in simulator_backends:
246
+ available = _check_simulator_available(backend)
247
+ is_required = require_backend and requested_backend == backend
248
+ results.append({
249
+ "adapter": backend,
250
+ "kind": "simulator",
251
+ "status": "invoked" if available else "skipped_unavailable_backend",
252
+ "required": is_required,
253
+ "reason": "" if available else f"{backend} not installed",
254
+ "available": available,
255
+ })
256
+
257
+ return results
258
+
259
+
260
+ def _resolve_simulator_backends(requested: str) -> list[str]:
261
+ if requested and requested in ADAPTER_REGISTRY:
262
+ entry = ADAPTER_REGISTRY[requested]
263
+ if str(entry.get("kind", "")) == "simulator":
264
+ return [requested]
265
+ return ["pybullet"]
266
+
267
+
268
+ def check_required_backends_satisfied(adapter_evidence: list[dict[str, object]]) -> tuple[bool, str]:
269
+ for ev in adapter_evidence:
270
+ if ev.get("required") is True and ev.get("status") == "skipped_unavailable_backend":
271
+ adapter_name = str(ev.get("adapter", "unknown"))
272
+ return False, f"required backend unavailable: {adapter_name}"
273
+ return True, "ok"
274
+
275
+
128
276
  def _write_dispatch_evidence(
129
277
  *,
130
278
  project_dir: str,
131
279
  run_id: str,
280
+ snapshot_run_id: str | None,
132
281
  status: str,
133
282
  domain: str,
134
283
  expected_specialists: list[str],
135
284
  requested_specialists: list[str],
136
285
  specialists_dispatched: list[str],
137
286
  job: dict[str, Any],
287
+ security_scan: dict[str, Any] | None = None,
138
288
  ) -> str:
139
289
  evidence_dir = Path(project_dir) / ".omg" / "evidence"
140
290
  evidence_dir.mkdir(parents=True, exist_ok=True)
141
291
  evidence_path = evidence_dir / f"forge-specialists-{run_id}.json"
142
292
  contract = load_forge_mvp()
143
- payload = {
293
+ payload: dict[str, Any] = {
144
294
  "schema": "ForgeSpecialistDispatchEvidence",
145
295
  "schema_version": "1.0.0",
146
296
  "run_id": run_id,
147
297
  "generated_at": datetime.now(timezone.utc).isoformat(),
148
298
  "status": status,
299
+ "labs_only": True,
300
+ "proof_backed": True,
301
+ "specialist": ",".join(specialists_dispatched),
149
302
  "domain": domain,
150
303
  "requested_specialists": requested_specialists,
151
304
  "expected_specialists": expected_specialists,
@@ -155,9 +308,26 @@ def _write_dispatch_evidence(
155
308
  "axolotl_hook": contract.get("axolotl_hook", ""),
156
309
  "pybullet_hook": contract.get("pybullet_hook", ""),
157
310
  },
311
+ "specialist_contracts": _resolve_specialist_contracts(contract, specialists_dispatched),
312
+ "causal_chain": {
313
+ "lock_id": "",
314
+ "waiver_artifact_path": f".omg/evidence/forge-specialists-{run_id}.json",
315
+ "delta_summary": {"forge_dispatch": domain, "specialists": specialists_dispatched},
316
+ "verification_status": status,
317
+ },
158
318
  "job": job,
159
319
  }
160
320
 
321
+ if security_scan is not None:
322
+ payload["security_scan"] = security_scan
323
+
324
+ defense_state = read_defense_state(project_dir, run_id=snapshot_run_id, compat=True)
325
+ session_health = read_session_health(project_dir, run_id=snapshot_run_id, compat=True)
326
+ if isinstance(defense_state, dict):
327
+ payload["defense_state"] = defense_state
328
+ if isinstance(session_health, dict):
329
+ payload["session_health"] = session_health
330
+
161
331
  tmp_path = evidence_path.with_name(f"{evidence_path.name}.tmp")
162
332
  _ = tmp_path.write_text(json.dumps(payload, indent=2, ensure_ascii=True), encoding="utf-8")
163
333
  _ = os.replace(tmp_path, evidence_path)