@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,6 +1,7 @@
1
1
  """Structured preflight routing for OMG."""
2
2
  from __future__ import annotations
3
3
 
4
+ import importlib
4
5
  from runtime.delta_classifier import classify_project_changes
5
6
  from runtime.tracebank import record_trace
6
7
  from typing import Any
@@ -45,6 +46,7 @@ def run_preflight(project_dir: str, *, goal: str) -> dict[str, Any]:
45
46
  categories = set(delta["categories"])
46
47
  requires_security_check = _requires_security_check(delta)
47
48
  domain_packs = [category for category in delta["categories"] if category in {"robotics", "vision", "algorithms", "health"}]
49
+ evidence_requirements = _requirements_for_profile(delta.get("evidence_profile"))
48
50
 
49
51
  if requires_security_check:
50
52
  task_class = "security"
@@ -83,6 +85,7 @@ def run_preflight(project_dir: str, *, goal: str) -> dict[str, Any]:
83
85
  "required_mcps": ["omg-control"] if route in {"security-check", "api-twin", "crazy"} else [],
84
86
  "missing_constraints": [],
85
87
  "evidence_plan": _evidence_plan(route),
88
+ "evidence_requirements": evidence_requirements,
86
89
  "delta_classification": delta,
87
90
  "domain_packs": domain_packs,
88
91
  "trace": {"trace_id": trace["trace_id"], "path": trace["path"]},
@@ -101,6 +104,17 @@ def _requires_security_check(delta: dict[str, Any]) -> bool:
101
104
  return False
102
105
 
103
106
 
107
+ def _requirements_for_profile(evidence_profile: str | None) -> list[str]:
108
+ module = importlib.import_module("runtime.evidence_requirements")
109
+ resolver = getattr(module, "requirements_for_profile", None)
110
+ if callable(resolver):
111
+ resolved = resolver(evidence_profile)
112
+ if isinstance(resolved, (list, tuple, set)):
113
+ return [str(item) for item in resolved]
114
+ full = getattr(module, "FULL_REQUIREMENTS", [])
115
+ return [str(item) for item in full]
116
+
117
+
104
118
  def _required_tools(route: str) -> list[str]:
105
119
  return {
106
120
  "security-check": ["security"],
@@ -0,0 +1,294 @@
1
+ """Canonical profile I/O — single owner of profile.yaml read/write/version.
2
+
3
+ All profile consumers should use this module to load and persist profile data.
4
+ ``profile_version`` is derived from a canonical key-sorted JSON hash of the
5
+ parsed dict, never from raw file text.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ import json
12
+ import os
13
+ from typing import Any
14
+
15
+ import yaml
16
+
17
+
18
+ def load_profile(path: str) -> dict[str, Any]:
19
+ """Load a profile from *path*, returning a dict.
20
+
21
+ Handles both YAML and JSON-shaped content transparently (backward compat).
22
+ Returns ``{}`` when the file is missing or unreadable.
23
+ """
24
+ if not os.path.exists(path):
25
+ return {}
26
+ try:
27
+ with open(path, "r", encoding="utf-8", errors="replace") as fh:
28
+ payload = yaml.safe_load(fh)
29
+ except Exception:
30
+ return {}
31
+ if isinstance(payload, dict):
32
+ return payload
33
+ return {}
34
+
35
+
36
+ def save_profile(path: str, data: dict[str, Any]) -> None:
37
+ """Persist *data* as canonical YAML to *path*.
38
+
39
+ Creates parent directories when needed. Output is always YAML (never JSON)
40
+ so that ``profile_version_from_map`` produces a deterministic hash
41
+ regardless of how the file was previously written.
42
+
43
+ Uses an internal serializer that correctly round-trips empty collections
44
+ as ``[]`` / ``{}`` instead of bare ``key:`` (which the project yaml shim
45
+ parses back as ``None``).
46
+ """
47
+ parent = os.path.dirname(path)
48
+ if parent:
49
+ os.makedirs(parent, exist_ok=True)
50
+ dumped = "\n".join(_dump_lines(data, 0)) + "\n"
51
+ with open(path, "w", encoding="utf-8") as fh:
52
+ fh.write(dumped)
53
+
54
+
55
+ def profile_version_from_map(data: dict[str, Any]) -> str:
56
+ """Derive a deterministic version string from a parsed profile dict.
57
+
58
+ The version is the full SHA-256 hex digest of the canonical key-sorted
59
+ JSON representation. This is independent of on-disk formatting (JSON
60
+ vs YAML, whitespace, key ordering).
61
+ """
62
+ canonical = json.dumps(data, sort_keys=True, ensure_ascii=True)
63
+ return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Internal YAML serializer — mirrors the project yaml shim's ``_dump_lines``
68
+ # but renders empty collections as ``[]`` / ``{}`` so that ``yaml.safe_load``
69
+ # round-trips them correctly.
70
+ # ---------------------------------------------------------------------------
71
+
72
+ _YAML_SPECIAL_WORDS = frozenset(
73
+ ("true", "false", "null", "yes", "no", "on", "off")
74
+ )
75
+ _YAML_SPECIAL_CHARS = set(":#{}[],&*?|>!%@`\"'")
76
+
77
+
78
+ def _dump_scalar(value: object) -> str:
79
+ """Serialize a scalar to a YAML-safe string."""
80
+ if value is None:
81
+ return "null"
82
+ if isinstance(value, bool):
83
+ return "true" if value else "false"
84
+ if isinstance(value, (int, float)):
85
+ return str(value)
86
+ text = str(value)
87
+ if (
88
+ text.lower() in _YAML_SPECIAL_WORDS
89
+ or text != text.strip()
90
+ or any(ch in _YAML_SPECIAL_CHARS for ch in text)
91
+ or not text
92
+ or _looks_numeric(text)
93
+ ):
94
+ return json.dumps(text, ensure_ascii=False)
95
+ return text
96
+
97
+
98
+ def _looks_numeric(text: str) -> bool:
99
+ """Return True if *text* would be parsed as a number by yaml.safe_load."""
100
+ try:
101
+ float(text)
102
+ return True
103
+ except (TypeError, ValueError):
104
+ return False
105
+
106
+
107
+ def _dump_lines(value: object, indent: int) -> list[str]:
108
+ """Recursively serialize *value* to a list of YAML lines."""
109
+ prefix = " " * indent
110
+ if isinstance(value, dict):
111
+ if not value:
112
+ return [f"{prefix}{{}}"]
113
+ lines: list[str] = []
114
+ for key, item in value.items():
115
+ if isinstance(item, dict):
116
+ if not item:
117
+ lines.append(f"{prefix}{key}: {{}}")
118
+ else:
119
+ lines.append(f"{prefix}{key}:")
120
+ lines.extend(_dump_lines(item, indent + 2))
121
+ elif isinstance(item, list):
122
+ if not item:
123
+ lines.append(f"{prefix}{key}: []")
124
+ else:
125
+ lines.append(f"{prefix}{key}:")
126
+ lines.extend(_dump_lines(item, indent + 2))
127
+ else:
128
+ lines.append(f"{prefix}{key}: {_dump_scalar(item)}")
129
+ return lines
130
+ if isinstance(value, list):
131
+ if not value:
132
+ return [f"{prefix}[]"]
133
+ lines = []
134
+ for item in value:
135
+ if isinstance(item, dict):
136
+ nested = _dump_lines(item, indent + 2)
137
+ if nested:
138
+ first = nested[0].strip()
139
+ lines.append(f"{prefix}- {first}")
140
+ lines.extend(nested[1:])
141
+ else:
142
+ lines.append(f"{prefix}- {{}}")
143
+ elif isinstance(item, list):
144
+ lines.append(f"{prefix}-")
145
+ lines.extend(_dump_lines(item, indent + 2))
146
+ else:
147
+ lines.append(f"{prefix}- {_dump_scalar(item)}")
148
+ return lines
149
+ return [f"{prefix}{_dump_scalar(value)}"]
150
+
151
+
152
+ _GOVERNED_SECTIONS = ("style", "safety")
153
+ _GOVERNED_CONFIRMATION_STATES = ("confirmed", "pending_confirmation", "inferred")
154
+
155
+
156
+ def classify_preference_section(field: str, value: str) -> str:
157
+ token = f"{field} {value}".lower()
158
+ if "safety" in token or "guardrail" in token or "override" in token:
159
+ return "safety"
160
+ return "style"
161
+
162
+
163
+ def is_destructive_preference(field: str, value: str) -> bool:
164
+ token = f"{field} {value}".lower()
165
+ destructive_tokens = (
166
+ "disable",
167
+ "off",
168
+ "bypass",
169
+ "ignore",
170
+ "override",
171
+ "unsafe",
172
+ "no_guard",
173
+ "no guard",
174
+ )
175
+ return any(piece in token for piece in destructive_tokens)
176
+
177
+
178
+ def ensure_governed_preferences(profile: dict[str, Any]) -> None:
179
+ governed_obj = profile.get("governed_preferences")
180
+ governed = governed_obj if isinstance(governed_obj, dict) else {}
181
+ for section in _GOVERNED_SECTIONS:
182
+ raw_entries = governed.get(section)
183
+ if not isinstance(raw_entries, list):
184
+ governed[section] = []
185
+ continue
186
+ normalized: list[dict[str, Any]] = []
187
+ for raw in raw_entries:
188
+ if not isinstance(raw, dict):
189
+ continue
190
+ entry = _normalize_governed_entry(raw, section)
191
+ if entry is not None:
192
+ normalized.append(entry)
193
+ governed[section] = normalized
194
+ profile["governed_preferences"] = governed
195
+
196
+
197
+ def upsert_governed_preference(
198
+ profile: dict[str, Any],
199
+ *,
200
+ field: str,
201
+ value: str,
202
+ source: str,
203
+ learned_at: str,
204
+ updated_at: str,
205
+ section: str,
206
+ confirmation_state: str,
207
+ decay_metadata: dict[str, Any] | None,
208
+ ) -> None:
209
+ ensure_governed_preferences(profile)
210
+ governed = profile["governed_preferences"]
211
+ if not isinstance(governed, dict):
212
+ return
213
+ target = governed.get(section)
214
+ if not isinstance(target, list):
215
+ target = []
216
+
217
+ match_index = -1
218
+ for idx, raw_entry in enumerate(target):
219
+ if not isinstance(raw_entry, dict):
220
+ continue
221
+ if str(raw_entry.get("field", "")).strip() == field and str(raw_entry.get("value", "")).strip() == value:
222
+ match_index = idx
223
+ break
224
+
225
+ baseline: dict[str, Any] = {
226
+ "field": field,
227
+ "value": value,
228
+ "source": source,
229
+ "learned_at": learned_at,
230
+ "updated_at": updated_at,
231
+ "section": section,
232
+ "confirmation_state": confirmation_state,
233
+ }
234
+ if section == "style" and decay_metadata is not None:
235
+ baseline["decay_metadata"] = decay_metadata
236
+
237
+ if match_index == -1:
238
+ target.append(baseline)
239
+ else:
240
+ existing = target[match_index]
241
+ if isinstance(existing, dict):
242
+ baseline["learned_at"] = str(existing.get("learned_at", learned_at)).strip() or learned_at
243
+ target[match_index] = baseline
244
+
245
+ governed[section] = target
246
+
247
+
248
+ def _normalize_governed_entry(raw: dict[str, Any], section: str) -> dict[str, Any] | None:
249
+ field = str(raw.get("field", "")).strip()
250
+ value = " ".join(str(raw.get("value", "")).strip().split())
251
+ source = str(raw.get("source", "")).strip()
252
+ learned_at = str(raw.get("learned_at", "")).strip()
253
+ updated_at = str(raw.get("updated_at", "")).strip()
254
+ section_raw = str(raw.get("section", section)).strip().lower()
255
+ confirmation_state = str(raw.get("confirmation_state", "")).strip().lower()
256
+
257
+ if not (field and value and source and learned_at and updated_at):
258
+ return None
259
+ if section_raw not in _GOVERNED_SECTIONS:
260
+ return None
261
+ if confirmation_state not in _GOVERNED_CONFIRMATION_STATES:
262
+ return None
263
+
264
+ out: dict[str, Any] = {
265
+ "field": field,
266
+ "value": value,
267
+ "source": source,
268
+ "learned_at": learned_at,
269
+ "updated_at": updated_at,
270
+ "section": section_raw,
271
+ "confirmation_state": confirmation_state,
272
+ }
273
+
274
+ if section_raw == "style" and confirmation_state == "inferred":
275
+ decay_raw = raw.get("decay_metadata")
276
+ decay = decay_raw if isinstance(decay_raw, dict) else {}
277
+ out["decay_metadata"] = {
278
+ "decay_score": _coerce_decay_score(decay.get("decay_score", 0.0)),
279
+ "last_seen_at": str(decay.get("last_seen_at", updated_at)).strip() or updated_at,
280
+ "decay_reason": str(decay.get("decay_reason", "inferred_signal")).strip() or "inferred_signal",
281
+ }
282
+ return out
283
+
284
+
285
+ def _coerce_decay_score(raw: Any) -> float:
286
+ try:
287
+ score = float(raw)
288
+ except (TypeError, ValueError):
289
+ score = 0.0
290
+ if score < 0.0:
291
+ return 0.0
292
+ if score > 1.0:
293
+ return 1.0
294
+ return round(score, 3)
@@ -1,14 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import hashlib
4
+ import os
4
5
  from pathlib import Path
5
6
  from typing import Any
6
7
 
7
8
  from runtime import artifact_parsers
9
+ from runtime.evidence_requirements import FULL_REQUIREMENTS, requirements_for_profile
8
10
 
9
11
 
10
12
  _REQUIRED_ARTIFACT_FIELDS = ("kind", "path", "sha256", "parser", "summary", "trace_id")
11
13
 
14
+ _REQUIRED_ARTIFACT_TOKENS: dict[str, tuple[str, ...]] = {
15
+ "junit": ("junit", "junit.xml", "surefire"),
16
+ "coverage": ("coverage", "lcov", "coverage.xml"),
17
+ "sarif": ("sarif", ".sarif"),
18
+ "browser_trace": ("trace.zip", "browser_trace", "playwright", "browser-evidence"),
19
+ }
20
+
12
21
 
13
22
  def evaluate_proof_gate(input: dict[str, Any]) -> dict[str, Any]:
14
23
  claims = _as_claims(input.get("claims"))
@@ -17,6 +26,10 @@ def evaluate_proof_gate(input: dict[str, Any]) -> dict[str, Any]:
17
26
  security_evidence = _as_dict(input.get("security_evidence"))
18
27
  browser_evidence = _as_dict(input.get("browser_evidence"))
19
28
  evidence_pack = _as_dict(input.get("evidence_pack"))
29
+ evidence_profile = _resolve_evidence_profile(input=input, evidence_pack=evidence_pack)
30
+ evidence_requirements = requirements_for_profile(evidence_profile)
31
+ test_intent_lock = _as_dict(input.get("test_intent_lock"))
32
+ test_delta = _as_dict(input.get("test_delta"))
20
33
 
21
34
  blockers: list[str] = []
22
35
  if not claims:
@@ -32,21 +45,37 @@ def evaluate_proof_gate(input: dict[str, Any]) -> dict[str, Any]:
32
45
  blockers.append("proof_gate_proof_chain_blockers_invalid")
33
46
 
34
47
  trace_id = str(proof_chain.get("trace_id", "")).strip()
35
- blockers.extend(_validate_claim_artifacts(claims))
48
+ blockers.extend(_validate_claim_artifacts(claims, evidence_requirements=evidence_requirements))
36
49
  blockers.extend(_validate_trace_linkage(claims=claims, trace_id=trace_id, eval_output=eval_output, browser_evidence=browser_evidence))
37
50
  blockers.extend(_validate_security_and_browser_artifacts(claims=claims, security_evidence=security_evidence, browser_evidence=browser_evidence))
38
51
  blockers.extend(_validate_evidence_pack(evidence_pack))
39
52
 
53
+ strict_mode = os.environ.get("OMG_PROOF_CHAIN_STRICT", "0").strip() == "1"
54
+ causal_chain_blockers = _validate_lock_delta_chain(
55
+ claims=claims,
56
+ test_intent_lock=test_intent_lock,
57
+ test_delta=test_delta,
58
+ evidence_pack=evidence_pack,
59
+ )
60
+ if strict_mode:
61
+ blockers.extend(causal_chain_blockers)
62
+
40
63
  unique_blockers = list(dict.fromkeys(item for item in blockers if str(item).strip()))
64
+ advisories = [] if strict_mode else causal_chain_blockers
41
65
  evidence_summary = {
42
66
  "claim_count": len(claims),
43
67
  "proof_chain_status": proof_status,
44
68
  "proof_chain_blocker_count": len(proof_blockers) if isinstance(proof_blockers, list) else 0,
45
- "required_artifacts": ["junit", "coverage", "sarif", "browser_trace"],
69
+ "required_artifacts": _required_artifact_keys(evidence_requirements),
70
+ "evidence_profile": evidence_profile,
71
+ "evidence_requirements": list(evidence_requirements),
46
72
  "trace_id": trace_id,
47
73
  "eval_trace_id": str(eval_output.get("trace_id", "")).strip(),
48
74
  "has_security_evidence": bool(security_evidence),
49
75
  "has_browser_evidence": bool(browser_evidence),
76
+ "has_lock_evidence": _has_lock_evidence(claims, test_intent_lock, evidence_pack),
77
+ "has_waiver_artifact": _has_waiver_artifact(test_delta or _as_dict(evidence_pack.get("test_delta"))),
78
+ "advisories": advisories,
50
79
  }
51
80
  return {
52
81
  "schema": "ProofGateResult",
@@ -100,7 +129,11 @@ def _collect_trace_ids(claim: dict[str, Any]) -> set[str]:
100
129
  return {str(item).strip() for item in raw_trace_ids if str(item).strip()}
101
130
 
102
131
 
103
- def _validate_claim_artifacts(claims: list[dict[str, Any]]) -> list[str]:
132
+ def _validate_claim_artifacts(
133
+ claims: list[dict[str, Any]],
134
+ *,
135
+ evidence_requirements: list[str],
136
+ ) -> list[str]:
104
137
  all_artifacts: list[str] = []
105
138
  artifact_records: list[dict[str, Any]] = []
106
139
  for claim in claims:
@@ -109,10 +142,9 @@ def _validate_claim_artifacts(claims: list[dict[str, Any]]) -> list[str]:
109
142
 
110
143
  blockers: list[str] = []
111
144
  required_tokens = {
112
- "junit": ("junit", "junit.xml", "surefire"),
113
- "coverage": ("coverage", "lcov", "coverage.xml"),
114
- "sarif": ("sarif", ".sarif"),
115
- "browser_trace": ("trace.zip", "browser_trace", "playwright", "browser-evidence"),
145
+ key: _REQUIRED_ARTIFACT_TOKENS[key]
146
+ for key in _required_artifact_keys(evidence_requirements)
147
+ if key in _REQUIRED_ARTIFACT_TOKENS
116
148
  }
117
149
  for key, tokens in required_tokens.items():
118
150
  if not any(any(token in artifact for token in tokens) for artifact in all_artifacts):
@@ -256,6 +288,89 @@ def _validate_artifact_hash(artifact: dict[str, Any]) -> str | None:
256
288
  return None
257
289
 
258
290
 
291
+ def _has_lock_evidence(claims: list[dict[str, Any]], test_intent_lock: dict[str, Any], evidence_pack: dict[str, Any]) -> bool:
292
+ lock_status = str(test_intent_lock.get("status", "")).strip().lower()
293
+ if lock_status == "ok":
294
+ return True
295
+ if str(test_intent_lock.get("lock_id", "")).strip():
296
+ return True
297
+
298
+ test_delta = _as_dict(evidence_pack.get("test_delta"))
299
+ if str(test_delta.get("lock_id", "")).strip():
300
+ return True
301
+
302
+ for claim in claims:
303
+ if str(claim.get("lock_id", "")).strip():
304
+ return True
305
+ lock_verification = _as_dict(claim.get("lock_verification"))
306
+ if str(lock_verification.get("status", "")).strip().lower() == "ok":
307
+ return True
308
+ return False
309
+
310
+
311
+ def _has_waiver_artifact(delta_summary: dict[str, Any]) -> bool:
312
+ waiver = delta_summary.get("waiver_artifact")
313
+ if isinstance(waiver, dict):
314
+ for field in ("artifact_path", "path", "id", "reason"):
315
+ if str(waiver.get(field, "")).strip():
316
+ return True
317
+ return bool(str(delta_summary.get("waiver_artifact_path", "")).strip())
318
+
319
+
320
+ def _is_weakened_or_drift_delta(delta_summary: dict[str, Any]) -> bool:
321
+ flags = delta_summary.get("flags")
322
+ if not isinstance(flags, list):
323
+ return False
324
+ risk_flags = {
325
+ "weakened_assertions",
326
+ "tests_mismatch",
327
+ "selector_drift",
328
+ "removed_touched_area_coverage",
329
+ "integration_to_mock_downgrade",
330
+ "snapshot_only_refresh",
331
+ }
332
+ normalized_flags = {str(item).strip().lower() for item in flags if str(item).strip()}
333
+ return bool(normalized_flags & risk_flags)
334
+
335
+
336
+ def _validate_lock_delta_chain(
337
+ *,
338
+ claims: list[dict[str, Any]],
339
+ test_intent_lock: dict[str, Any],
340
+ test_delta: dict[str, Any],
341
+ evidence_pack: dict[str, Any],
342
+ ) -> list[str]:
343
+ blockers: list[str] = []
344
+ if not _has_lock_evidence(claims, test_intent_lock, evidence_pack):
345
+ blockers.append("proof_gate_missing_lock_evidence")
346
+
347
+ delta_summary = test_delta if test_delta else _as_dict(evidence_pack.get("test_delta"))
348
+ if _is_weakened_or_drift_delta(delta_summary) and not _has_waiver_artifact(delta_summary):
349
+ blockers.append("proof_gate_missing_waiver_artifact")
350
+ return blockers
351
+
352
+
353
+ def _resolve_evidence_profile(*, input: dict[str, Any], evidence_pack: dict[str, Any]) -> str:
354
+ profile = str(input.get("evidence_profile", "")).strip()
355
+ if profile:
356
+ return profile
357
+ return str(evidence_pack.get("evidence_profile", "")).strip()
358
+
359
+
360
+ def _required_artifact_keys(evidence_requirements: list[str]) -> list[str]:
361
+ required: list[str] = []
362
+ requirement_set = {str(item).strip() for item in evidence_requirements if str(item).strip()}
363
+ if "tests" in requirement_set:
364
+ required.append("junit")
365
+ if "build" in requirement_set:
366
+ required.append("coverage")
367
+ if "security_scan" in requirement_set:
368
+ required.append("sarif")
369
+ if requirement_set == set(FULL_REQUIREMENTS):
370
+ required.append("browser_trace")
371
+ return required
372
+
373
+
259
374
  _PARSERS: dict[str, Any] = {
260
375
  "junit": artifact_parsers.parse_junit,
261
376
  "sarif": artifact_parsers.parse_sarif,
@@ -0,0 +1,94 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import shutil
6
+ import subprocess
7
+ from pathlib import Path
8
+ from typing import cast
9
+ from typing import Any
10
+
11
+ from runtime.cli_provider import CLIProvider, register_provider
12
+ from runtime.mcp_config_writers import _atomic_write_text # pyright: ignore[reportPrivateUsage]
13
+
14
+ HOST_RULES = {
15
+ "compilation_targets": ["opencode.json"],
16
+ "mcp": ["omg-control"],
17
+ "mcp_key": "mcp",
18
+ }
19
+
20
+
21
+ class OpenCodeProvider(CLIProvider):
22
+ def get_name(self) -> str: # pyright: ignore[reportImplicitOverride]
23
+ return "opencode"
24
+
25
+ def detect(self) -> bool: # pyright: ignore[reportImplicitOverride]
26
+ return shutil.which("opencode") is not None
27
+
28
+ def check_auth(self) -> tuple[bool | None, str]: # pyright: ignore[reportImplicitOverride]
29
+ auth_path = Path(os.path.expanduser("~/.local/share/opencode/auth.json"))
30
+ if not auth_path.exists():
31
+ return False, f"auth not found: missing {auth_path}"
32
+ try:
33
+ parsed = cast(object, json.loads(auth_path.read_text()))
34
+ except (json.JSONDecodeError, ValueError) as exc:
35
+ return False, f"auth not found: invalid json: {exc}"
36
+ except OSError as exc:
37
+ return False, f"auth not found: unreadable file: {exc}"
38
+
39
+ if not parsed:
40
+ return False, "auth not found: empty auth content"
41
+ return True, "auth found"
42
+
43
+ def invoke(self, prompt: str, project_dir: str, timeout: int = 120) -> dict[str, Any]: # pyright: ignore[reportExplicitAny, reportImplicitOverride]
44
+ try:
45
+ result = self.run_tool(["opencode", prompt], timeout=timeout)
46
+ return {
47
+ "model": "opencode-cli",
48
+ "output": result.stdout,
49
+ "exit_code": result.returncode,
50
+ }
51
+ except subprocess.TimeoutExpired:
52
+ return {"error": "opencode-cli timeout", "fallback": "claude"}
53
+ except FileNotFoundError:
54
+ return {"error": "opencode-cli not found", "fallback": "claude"}
55
+ except Exception as exc:
56
+ return {"error": str(exc), "fallback": "claude"}
57
+
58
+ def invoke_tmux(self, prompt: str, project_dir: str, timeout: int = 120) -> dict[str, Any]: # pyright: ignore[reportExplicitAny, reportImplicitOverride]
59
+ return self.invoke(prompt, project_dir, timeout=timeout)
60
+
61
+ def get_non_interactive_cmd(self, prompt: str) -> list[str]: # pyright: ignore[reportImplicitOverride]
62
+ return ["opencode", prompt]
63
+
64
+ def get_config_path(self) -> str: # pyright: ignore[reportImplicitOverride]
65
+ return os.path.expanduser("~/.config/opencode/opencode.json")
66
+
67
+ def get_project_config_path(self, root: str = ".") -> str:
68
+ return str(Path(root) / "opencode.json")
69
+
70
+ def get_plugin_dir(self, root: str = ".") -> str:
71
+ return str(Path(root) / ".opencode" / "plugins")
72
+
73
+ def write_mcp_config(self, server_url: str, server_name: str = "memory-server") -> None: # pyright: ignore[reportImplicitOverride]
74
+ config_path = Path(self.get_config_path())
75
+ config: dict[str, object]
76
+ if config_path.exists():
77
+ try:
78
+ loaded = cast(object, json.loads(config_path.read_text()))
79
+ config = cast(dict[str, object], loaded) if isinstance(loaded, dict) else {}
80
+ except (json.JSONDecodeError, ValueError):
81
+ config = {}
82
+ else:
83
+ config = {}
84
+
85
+ mcp = config.get("mcp")
86
+ if not isinstance(mcp, dict):
87
+ mcp = {}
88
+ config["mcp"] = mcp
89
+
90
+ mcp[server_name] = {"type": "http", "url": server_url}
91
+ _atomic_write_text(config_path, json.dumps(config, indent=2) + "\n")
92
+
93
+
94
+ register_provider(OpenCodeProvider())