@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
@@ -7,7 +7,9 @@ from __future__ import annotations
7
7
  import json
8
8
  import logging
9
9
  import os
10
+ import re
10
11
  import sys
12
+ from pathlib import Path
11
13
  from typing import Any, cast
12
14
 
13
15
  import yaml
@@ -35,6 +37,7 @@ from runtime.mcp_config_writers import ( # noqa: E402
35
37
  import runtime.providers.codex_provider # noqa: E402, F401
36
38
  import runtime.providers.gemini_provider # noqa: E402, F401
37
39
  import runtime.providers.kimi_provider # noqa: E402, F401
40
+ from runtime.validate import run_validate as _run_post_install_validate # noqa: E402
38
41
  from runtime.adoption import ( # noqa: E402
39
42
  CANONICAL_MODE_NAMES,
40
43
  CANONICAL_VERSION,
@@ -191,6 +194,28 @@ MCP_CATALOG: list[dict[str, Any]] = [
191
194
  "default": False,
192
195
  "category": "memory",
193
196
  },
197
+ {
198
+ "id": "notebooklm",
199
+ "name": "NotebookLM",
200
+ "description": "NotebookLM MCP server for AI-powered research and note-taking",
201
+ "command": "npx",
202
+ "args": ["-y", "notebooklm-mcp@latest"],
203
+ "default": False,
204
+ "category": "productivity",
205
+ "warning": (
206
+ "NOTEBOOKLM MCP WARNING\n\n"
207
+ "NotebookLM requires browser automation and has several important considerations:\n\n"
208
+ "BROWSER AUTOMATION: NotebookLM uses Puppeteer for browser automation. "
209
+ "This requires a Chromium/Chrome installation and may consume significant system resources.\n\n"
210
+ "FIRST-RUN DOWNLOAD: On first run, NotebookLM will download a full browser instance "
211
+ "(typically 100-300 MB). This is a one-time operation but may take several minutes.\n\n"
212
+ "DEDICATED ACCOUNT: It is strongly recommended to use a dedicated Google account "
213
+ "for NotebookLM MCP. Do NOT use your primary account, as the MCP will store credentials locally.\n\n"
214
+ "AUTH EXPIRY: Google authentication tokens expire periodically. "
215
+ "You may need to re-authenticate if the MCP fails with auth errors.\n\n"
216
+ "Enable NotebookLM only if you understand these requirements and accept the risks."
217
+ ),
218
+ },
194
219
  ]
195
220
 
196
221
  _MCP_ID_ALIASES: dict[str, str] = {
@@ -451,6 +476,12 @@ def check_auth() -> dict[str, Any]:
451
476
 
452
477
  _HTTP_MEMORY_MIN_LEVEL: int = _PRESET_LEVEL["interop"]
453
478
 
479
+ _PROFILE_ARCH_REQUEST_MAX = 8
480
+ _PROFILE_TAG_MAX = 12
481
+ _PROFILE_SUMMARY_MAX_CHARS = 240
482
+ _PROFILE_RECENT_UPDATES_MAX = 5
483
+ _PROFILE_GOVERNED_MAX = 24
484
+
454
485
 
455
486
  def get_mode_choices() -> list[str]:
456
487
  return list(CANONICAL_MODE_NAMES)
@@ -660,6 +691,8 @@ def set_preferences(project_dir: str, preferences: dict[str, Any]) -> dict[str,
660
691
  state_dir = os.path.join(project_dir, ".omg", "state")
661
692
  os.makedirs(state_dir, exist_ok=True)
662
693
 
694
+ _write_profile_learning_sections(state_dir, preferences)
695
+
663
696
  # Write config to YAML file
664
697
  config_path = os.path.join(state_dir, "cli-config.yaml")
665
698
  with open(config_path, "w") as f:
@@ -674,6 +707,260 @@ def set_preferences(project_dir: str, preferences: dict[str, Any]) -> dict[str,
674
707
  }
675
708
 
676
709
 
710
+ def _write_profile_learning_sections(state_dir: str, preferences: dict[str, Any]) -> None:
711
+ profile_path = os.path.join(state_dir, "profile.yaml")
712
+ profile_data = _load_profile_yaml(profile_path)
713
+ _ensure_profile_baseline(profile_data)
714
+
715
+ profile_data["preferences"] = _normalize_preferences_block(preferences.get("preferences"))
716
+ profile_data["user_vector"] = _normalize_user_vector_block(preferences.get("user_vector"))
717
+ profile_data["profile_provenance"] = _normalize_provenance_block(preferences.get("profile_provenance"))
718
+ profile_data["governed_preferences"] = _normalize_governed_preferences_block(preferences.get("governed_preferences"))
719
+
720
+ from runtime.profile_io import save_profile
721
+ save_profile(profile_path, profile_data)
722
+
723
+
724
+ def _render_explicit_empty_collections(dumped: str) -> str:
725
+ lines = dumped.splitlines()
726
+ output: list[str] = []
727
+
728
+ def _next_line(start: int) -> str:
729
+ if start + 1 < len(lines):
730
+ return lines[start + 1]
731
+ return ""
732
+
733
+ for idx, line in enumerate(lines):
734
+ next_line = _next_line(idx)
735
+ stripped = line.strip()
736
+
737
+ if stripped == "stack:" and (not next_line or not next_line.startswith("- ")):
738
+ output.append("stack: []")
739
+ continue
740
+ if stripped == "conventions:" and (not next_line or not next_line.startswith(" ")):
741
+ output.append("conventions: {}")
742
+ continue
743
+ if stripped == "ai_behavior:" and (not next_line or not next_line.startswith(" ")):
744
+ output.append("ai_behavior: {}")
745
+ continue
746
+ if stripped == "architecture_requests:" and (not next_line or not next_line.startswith(" - ")):
747
+ output.append(" architecture_requests: []")
748
+ continue
749
+ if stripped == "constraints:" and (not next_line or not next_line.startswith(" ")):
750
+ output.append(" constraints: {}")
751
+ continue
752
+ if stripped == "tags:" and (not next_line or not next_line.startswith(" - ")):
753
+ output.append(" tags: []")
754
+ continue
755
+ if stripped == "recent_updates:" and (not next_line or not next_line.startswith(" - ")):
756
+ output.append(" recent_updates: []")
757
+ continue
758
+
759
+ output.append(line)
760
+
761
+ return "\n".join(output) + "\n"
762
+
763
+
764
+ def _load_profile_yaml(profile_path: str) -> dict[str, Any]:
765
+ from runtime.profile_io import load_profile
766
+ return load_profile(profile_path)
767
+
768
+
769
+ def _ensure_profile_baseline(profile_data: dict[str, Any]) -> None:
770
+ profile_data.setdefault("name", "omg-project")
771
+ profile_data.setdefault("description", "initialized by OMG standalone compat bootstrap")
772
+ profile_data.setdefault("language", "unknown")
773
+ profile_data.setdefault("framework", "unknown")
774
+ profile_data.setdefault("stack", [])
775
+ profile_data.setdefault("conventions", {})
776
+ profile_data.setdefault("ai_behavior", {})
777
+ profile_data.setdefault("governed_preferences", {"style": [], "safety": []})
778
+
779
+
780
+ def _normalize_preferences_block(raw: Any) -> dict[str, Any]:
781
+ block = raw if isinstance(raw, dict) else {}
782
+
783
+ requests_obj = block.get("architecture_requests")
784
+ architecture_requests: list[str] = []
785
+ if isinstance(requests_obj, list):
786
+ for value in requests_obj:
787
+ text = str(value).strip()
788
+ if text:
789
+ architecture_requests.append(text)
790
+ if len(architecture_requests) >= _PROFILE_ARCH_REQUEST_MAX:
791
+ break
792
+
793
+ constraints_obj = block.get("constraints")
794
+ constraints: dict[str, Any] = {}
795
+ if isinstance(constraints_obj, dict):
796
+ for key, value in constraints_obj.items():
797
+ normalized_key = _normalize_constraint_key(str(key))
798
+ normalized_value = _normalize_constraint_value(value)
799
+ if normalized_key and normalized_value is not None:
800
+ constraints[normalized_key] = normalized_value
801
+
802
+ routing_obj = block.get("routing")
803
+ routing_map = routing_obj if isinstance(routing_obj, dict) else {}
804
+ routing = {
805
+ "prefer_clarification": bool(routing_map.get("prefer_clarification", False)),
806
+ }
807
+
808
+ return {
809
+ "architecture_requests": architecture_requests,
810
+ "constraints": constraints,
811
+ "routing": routing,
812
+ }
813
+
814
+
815
+ def _normalize_constraint_key(value: str) -> str:
816
+ normalized = value.strip().lower()
817
+ normalized = re.sub(r"\s+", "_", normalized)
818
+ normalized = re.sub(r"[^a-z0-9_]+", "", normalized)
819
+ return normalized
820
+
821
+
822
+ def _normalize_constraint_value(value: Any) -> str | int | float | bool | None:
823
+ if isinstance(value, bool):
824
+ return value
825
+ if isinstance(value, int):
826
+ return value
827
+ if isinstance(value, float):
828
+ return value
829
+ if value is None:
830
+ return None
831
+ text = str(value).strip().lower()
832
+ return text if text else None
833
+
834
+
835
+ def _normalize_user_vector_block(raw: Any) -> dict[str, Any]:
836
+ block = raw if isinstance(raw, dict) else {}
837
+
838
+ tags_obj = block.get("tags")
839
+ tags: list[str] = []
840
+ if isinstance(tags_obj, list):
841
+ for value in tags_obj:
842
+ token = _normalize_tag_token(str(value))
843
+ if token:
844
+ tags.append(token)
845
+ if len(tags) >= _PROFILE_TAG_MAX:
846
+ break
847
+
848
+ summary = ""
849
+ summary_obj = block.get("summary")
850
+ if isinstance(summary_obj, str):
851
+ summary = " ".join(summary_obj.strip().split())[:_PROFILE_SUMMARY_MAX_CHARS]
852
+
853
+ confidence = 0.0
854
+ confidence_obj = block.get("confidence")
855
+ if isinstance(confidence_obj, (int, float, str)):
856
+ try:
857
+ confidence = float(confidence_obj)
858
+ except (TypeError, ValueError):
859
+ confidence = 0.0
860
+ confidence = max(0.0, min(1.0, confidence))
861
+
862
+ return {
863
+ "tags": tags,
864
+ "summary": summary,
865
+ "confidence": confidence,
866
+ }
867
+
868
+
869
+ def _normalize_tag_token(value: str) -> str:
870
+ normalized = value.strip().lower()
871
+ normalized = re.sub(r"\s+", "_", normalized)
872
+ normalized = re.sub(r"[^a-z0-9_\-]+", "", normalized)
873
+ return normalized
874
+
875
+
876
+ def _normalize_provenance_block(raw: Any) -> dict[str, Any]:
877
+ block = raw if isinstance(raw, dict) else {}
878
+ updates_obj = block.get("recent_updates")
879
+ updates: list[dict[str, str]] = []
880
+ if isinstance(updates_obj, list):
881
+ for entry in updates_obj:
882
+ if not isinstance(entry, dict):
883
+ continue
884
+ run_id = str(entry.get("run_id", "")).strip()
885
+ source = str(entry.get("source", "")).strip()
886
+ field = str(entry.get("field", "")).strip()
887
+ updated_at = str(entry.get("updated_at", "")).strip()
888
+ if not (run_id and source and field and updated_at):
889
+ continue
890
+ updates.append(
891
+ {
892
+ "run_id": run_id,
893
+ "source": source,
894
+ "field": field,
895
+ "updated_at": updated_at,
896
+ }
897
+ )
898
+ if len(updates) >= _PROFILE_RECENT_UPDATES_MAX:
899
+ break
900
+ return {"recent_updates": updates}
901
+
902
+
903
+ def _normalize_governed_preferences_block(raw: Any) -> dict[str, list[dict[str, Any]]]:
904
+ block = raw if isinstance(raw, dict) else {}
905
+ style_raw = block.get("style")
906
+ safety_raw = block.get("safety")
907
+ return {
908
+ "style": _normalize_governed_section_entries(style_raw, section="style"),
909
+ "safety": _normalize_governed_section_entries(safety_raw, section="safety"),
910
+ }
911
+
912
+
913
+ def _normalize_governed_section_entries(raw: Any, *, section: str) -> list[dict[str, Any]]:
914
+ if not isinstance(raw, list):
915
+ return []
916
+ entries: list[dict[str, Any]] = []
917
+ for item in raw:
918
+ if not isinstance(item, dict):
919
+ continue
920
+ field = str(item.get("field", "")).strip()
921
+ value = " ".join(str(item.get("value", "")).strip().split())
922
+ source = str(item.get("source", "")).strip()
923
+ learned_at = str(item.get("learned_at", "")).strip()
924
+ updated_at = str(item.get("updated_at", "")).strip()
925
+ candidate_section = str(item.get("section", section)).strip().lower()
926
+ confirmation_state = str(item.get("confirmation_state", "")).strip().lower()
927
+
928
+ if not (field and value and source and learned_at and updated_at):
929
+ continue
930
+ if candidate_section != section:
931
+ continue
932
+ if confirmation_state not in ("confirmed", "pending_confirmation", "inferred"):
933
+ continue
934
+
935
+ entry: dict[str, Any] = {
936
+ "field": field,
937
+ "value": value,
938
+ "source": source,
939
+ "learned_at": learned_at,
940
+ "updated_at": updated_at,
941
+ "section": section,
942
+ "confirmation_state": confirmation_state,
943
+ }
944
+
945
+ if section == "style" and confirmation_state == "inferred":
946
+ decay_raw = item.get("decay_metadata")
947
+ decay = decay_raw if isinstance(decay_raw, dict) else {}
948
+ try:
949
+ score = float(decay.get("decay_score", 0.0))
950
+ except (TypeError, ValueError):
951
+ score = 0.0
952
+ entry["decay_metadata"] = {
953
+ "decay_score": max(0.0, min(1.0, score)),
954
+ "last_seen_at": str(decay.get("last_seen_at", updated_at)).strip() or updated_at,
955
+ "decay_reason": str(decay.get("decay_reason", "inferred_signal")).strip() or "inferred_signal",
956
+ }
957
+
958
+ entries.append(entry)
959
+ if len(entries) >= _PROFILE_GOVERNED_MAX:
960
+ break
961
+ return entries
962
+
963
+
677
964
  def _write_project_settings_preset(project_dir: str, preset: str) -> None:
678
965
  """Persist preset metadata into project settings when settings.json exists."""
679
966
  settings_path = os.path.join(project_dir, "settings.json")
@@ -760,7 +1047,7 @@ def run_setup_wizard(
760
1047
  report_path = write_adoption_report(project_dir, adoption)
761
1048
  adoption["report_path"] = report_path
762
1049
 
763
- return {
1050
+ result: dict[str, Any] = {
764
1051
  "status": "complete",
765
1052
  "setup_mode": {
766
1053
  "choices": get_mode_choices(),
@@ -773,3 +1060,48 @@ def run_setup_wizard(
773
1060
  "preferences": prefs,
774
1061
  "adoption": adoption,
775
1062
  }
1063
+
1064
+ # --- Post-install validation (runs AFTER all setup writes are complete) ---
1065
+ try:
1066
+ validation_result = _run_post_install_validate(root_dir=Path(_PROJECT_ROOT))
1067
+ except Exception as exc:
1068
+ validation_result = {
1069
+ "schema": "ValidateResult",
1070
+ "status": "fail",
1071
+ "checks": [
1072
+ {
1073
+ "name": "validation_error",
1074
+ "status": "blocker",
1075
+ "message": str(exc),
1076
+ "required": True,
1077
+ },
1078
+ ],
1079
+ "version": "",
1080
+ }
1081
+
1082
+ # Persist machine-readable validation artifact
1083
+ artifact_dir = os.path.join(project_dir, ".omg", "state")
1084
+ os.makedirs(artifact_dir, exist_ok=True)
1085
+ artifact_path = os.path.join(artifact_dir, "post-install-validation.json")
1086
+ try:
1087
+ with open(artifact_path, "w", encoding="utf-8") as f:
1088
+ json.dump(validation_result, f, indent=2, ensure_ascii=True)
1089
+ f.write("\n")
1090
+ except OSError:
1091
+ artifact_path = ""
1092
+
1093
+ blockers = [
1094
+ c for c in validation_result.get("checks", [])
1095
+ if c.get("status") == "blocker"
1096
+ ]
1097
+
1098
+ result["post_install_validation"] = {
1099
+ "status": validation_result.get("status", "fail"),
1100
+ "artifact_path": artifact_path,
1101
+ "blockers": [{"name": c["name"], "message": c["message"]} for c in blockers],
1102
+ }
1103
+
1104
+ if blockers:
1105
+ result["status"] = "validation_failed"
1106
+
1107
+ return result
@@ -146,7 +146,13 @@ def map_shadow_path(project_dir: str, run_id: str, file_path: str) -> str:
146
146
  return os.path.join(_shadow_root(project_dir), run_id, "overlay", rel)
147
147
 
148
148
 
149
- def record_shadow_write(project_dir: str, run_id: str, file_path: str, source: str = "tool") -> dict[str, Any]:
149
+ def record_shadow_write(
150
+ project_dir: str,
151
+ run_id: str,
152
+ file_path: str,
153
+ source: str = "tool",
154
+ step_id: str | None = None,
155
+ ) -> dict[str, Any]:
150
156
  run_id = _validated_run_id(run_id)
151
157
  run_dir = os.path.join(_shadow_root(project_dir), run_id)
152
158
  os.makedirs(run_dir, exist_ok=True)
@@ -155,7 +161,8 @@ def record_shadow_write(project_dir: str, run_id: str, file_path: str, source: s
155
161
  os.makedirs(os.path.dirname(shadow_path), exist_ok=True)
156
162
 
157
163
  abs_file = file_path if os.path.isabs(file_path) else os.path.join(project_dir, file_path)
158
- if os.path.exists(abs_file):
164
+ file_existed_before = os.path.exists(abs_file)
165
+ if file_existed_before:
159
166
  shutil.copy2(abs_file, shadow_path)
160
167
  file_hash = _hash_file(abs_file)
161
168
  else:
@@ -169,7 +176,10 @@ def record_shadow_write(project_dir: str, run_id: str, file_path: str, source: s
169
176
  "recorded_at": _utc_now(),
170
177
  "source": source,
171
178
  "sha256": file_hash,
179
+ "file_existed_before": file_existed_before,
172
180
  }
181
+ if step_id:
182
+ entry["step_id"] = step_id
173
183
 
174
184
  files = manifest.get("files", [])
175
185
  # Replace existing entry for same file.
@@ -181,6 +191,72 @@ def record_shadow_write(project_dir: str, run_id: str, file_path: str, source: s
181
191
  return entry
182
192
 
183
193
 
194
+ def restore_shadow_entry(project_dir: str, run_id: str, step_id: str) -> dict[str, Any]:
195
+ run_id = _validated_run_id(run_id)
196
+ run_dir = os.path.join(_shadow_root(project_dir), run_id)
197
+ manifest = _load_manifest(run_dir)
198
+ entries = manifest.get("files", [])
199
+
200
+ restored: list[str] = []
201
+ failed: list[dict[str, str]] = []
202
+
203
+ selected_entries: list[dict[str, Any]] = []
204
+ for item in entries:
205
+ if not isinstance(item, dict):
206
+ continue
207
+ item_step_id = str(item.get("step_id", "")).strip()
208
+ if item_step_id == step_id:
209
+ selected_entries.append(item)
210
+
211
+ if not selected_entries and isinstance(entries, list) and len(entries) == 1:
212
+ single = entries[0]
213
+ if isinstance(single, dict):
214
+ selected_entries = [single]
215
+
216
+ if not selected_entries:
217
+ return {"restored": restored, "failed": failed, "reason": "step not found"}
218
+
219
+ for item in selected_entries:
220
+ rel = str(item.get("file", "")).strip()
221
+ shadow_rel = str(item.get("shadow_file", "")).strip()
222
+ file_existed_before = bool(item.get("file_existed_before", True))
223
+ if not rel:
224
+ failed.append({"file": "", "reason": "missing file path"})
225
+ continue
226
+
227
+ dst = os.path.join(project_dir, rel)
228
+ src = os.path.join(run_dir, shadow_rel) if shadow_rel else ""
229
+
230
+ if src and os.path.exists(src):
231
+ try:
232
+ os.makedirs(os.path.dirname(dst), exist_ok=True)
233
+ shutil.copy2(src, dst)
234
+ restored.append(rel)
235
+ except Exception as exc:
236
+ failed.append({"file": rel, "reason": f"copy failed: {exc}"})
237
+ continue
238
+
239
+ if not file_existed_before:
240
+ try:
241
+ if os.path.exists(dst):
242
+ os.remove(dst)
243
+ restored.append(rel)
244
+ except Exception as exc:
245
+ failed.append({"file": rel, "reason": f"delete failed: {exc}"})
246
+ continue
247
+
248
+ failed.append({"file": rel, "reason": "shadow snapshot missing"})
249
+
250
+ manifest["status"] = "restored"
251
+ manifest["restored_at"] = _utc_now()
252
+ _save_manifest(run_dir, manifest)
253
+
254
+ reason = "shadow restore applied" if restored and not failed else "shadow restore partial"
255
+ if not restored and failed:
256
+ reason = "shadow restore failed"
257
+ return {"restored": restored, "failed": failed, "reason": reason}
258
+
259
+
184
260
  def create_evidence_pack(
185
261
  project_dir: str,
186
262
  run_id: str,
@@ -321,6 +397,34 @@ def drop_shadow(project_dir: str, run_id: str) -> dict[str, Any]:
321
397
  return {"run_id": run_id, "dropped": True}
322
398
 
323
399
 
400
+ def auto_journal_mutation(
401
+ project_dir: str,
402
+ tool: str,
403
+ file_path: str,
404
+ run_id: str,
405
+ ) -> dict[str, Any] | None:
406
+ try:
407
+ from runtime.interaction_journal import InteractionJournal
408
+ from runtime.release_run_coordinator import resolve_current_run_id
409
+ except ImportError:
410
+ return None
411
+
412
+ canonical_run_id = resolve_current_run_id(project_dir) or run_id
413
+ shadow_manifest = os.path.join(
414
+ _shadow_root(project_dir), run_id, "manifest.json"
415
+ )
416
+
417
+ journal = InteractionJournal(project_dir)
418
+ return journal.record_step(
419
+ tool.lower(),
420
+ {
421
+ "file_path": file_path,
422
+ "run_id": canonical_run_id,
423
+ "shadow_manifest": shadow_manifest,
424
+ },
425
+ )
426
+
427
+
324
428
  def _handle_post_tool_use(payload: dict[str, Any]) -> None:
325
429
  tool = payload.get("tool_name", "")
326
430
  if tool not in ("Write", "Edit", "MultiEdit"):
@@ -343,6 +447,11 @@ def _handle_post_tool_use(payload: dict[str, Any]) -> None:
343
447
  run_id = begin_shadow_run(project_dir, metadata={"source": "post-tool-use"})
344
448
  record_shadow_write(project_dir, run_id, file_path)
345
449
 
450
+ try:
451
+ auto_journal_mutation(project_dir, tool, file_path, run_id)
452
+ except Exception:
453
+ pass
454
+
346
455
 
347
456
  def _main() -> int:
348
457
  # Early-exit: skip all work if shadow/evidence mode is not enabled
@@ -9,10 +9,12 @@ import subprocess
9
9
  import sys
10
10
  import time
11
11
  from datetime import datetime, timedelta, timezone
12
+ import warnings
12
13
 
13
14
  sys.path.insert(0, os.path.dirname(__file__))
15
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
14
16
 
15
- from _common import ( # noqa: E402
17
+ from hooks._common import ( # noqa: E402
16
18
  atomic_json_write,
17
19
  block_decision,
18
20
  check_performance_budget,
@@ -27,7 +29,10 @@ from _common import ( # noqa: E402
27
29
  should_skip_stop_hooks,
28
30
  STOP_CHECK_MAX_MS,
29
31
  )
30
- from state_migration import resolve_state_file # noqa: E402
32
+ from hooks.state_migration import resolve_state_file # noqa: E402
33
+
34
+ from runtime.release_run_coordinator import resolve_current_run_id # noqa: E402
35
+ from runtime import test_intent_lock # noqa: E402
31
36
 
32
37
 
33
38
  setup_crash_handler("stop_dispatcher")
@@ -132,7 +137,7 @@ def _is_internal_control_path(file_path: str) -> bool:
132
137
 
133
138
 
134
139
  try:
135
- from shadow_manager import has_recent_evidence # type: ignore
140
+ from hooks.shadow_manager import has_recent_evidence # type: ignore
136
141
  except Exception: # intentional: optional feature — shadow_manager may not exist
137
142
  has_recent_evidence = None
138
143
 
@@ -621,6 +626,104 @@ def check_bare_done(data, project_dir):
621
626
 
622
627
  return []
623
628
 
629
+
630
+ def _proof_chain_strict_enabled() -> bool:
631
+ return os.environ.get("OMG_PROOF_CHAIN_STRICT", "0").strip() == "1"
632
+
633
+
634
+ def _load_test_delta_from_evidence(project_dir: str, run_id: str | None) -> dict[str, object]:
635
+ evidence_dir = os.path.join(project_dir, ".omg", "evidence")
636
+ if not os.path.isdir(evidence_dir):
637
+ return {}
638
+
639
+ candidates = sorted(
640
+ [
641
+ os.path.join(evidence_dir, name)
642
+ for name in os.listdir(evidence_dir)
643
+ if name.endswith(".json")
644
+ ],
645
+ key=os.path.getmtime,
646
+ reverse=True,
647
+ )
648
+ for path in candidates:
649
+ try:
650
+ with open(path, "r", encoding="utf-8", errors="ignore") as handle:
651
+ payload = json.load(handle)
652
+ except (OSError, json.JSONDecodeError):
653
+ continue
654
+ if not isinstance(payload, dict):
655
+ continue
656
+ if payload.get("schema") != "EvidencePack":
657
+ continue
658
+ payload_run_id = str(payload.get("run_id", "")).strip()
659
+ if run_id and payload_run_id and payload_run_id != run_id:
660
+ continue
661
+ test_delta = payload.get("test_delta")
662
+ if isinstance(test_delta, dict):
663
+ return test_delta
664
+ return {}
665
+
666
+
667
+ def _has_waiver_artifact(delta_summary: dict[str, object]) -> bool:
668
+ waiver = delta_summary.get("waiver_artifact")
669
+ if isinstance(waiver, dict):
670
+ for field in ("artifact_path", "path", "id", "reason"):
671
+ if str(waiver.get(field, "")).strip():
672
+ return True
673
+ return False
674
+
675
+
676
+ def _has_weakened_or_drift(delta_summary: dict[str, object]) -> bool:
677
+ flags = delta_summary.get("flags")
678
+ if not isinstance(flags, list):
679
+ return False
680
+ risk_flags = {
681
+ "weakened_assertions",
682
+ "tests_mismatch",
683
+ "selector_drift",
684
+ "removed_touched_area_coverage",
685
+ "integration_to_mock_downgrade",
686
+ "snapshot_only_refresh",
687
+ }
688
+ normalized = {str(item).strip().lower() for item in flags if str(item).strip()}
689
+ return bool(normalized & risk_flags)
690
+
691
+
692
+ def check_tdd_proof_chain(data, project_dir):
693
+ if not get_feature_flag("tdd_proof_chain", True):
694
+ return []
695
+
696
+ context = data["_stop_ctx"]
697
+ if not context.get("has_source_writes", False):
698
+ return []
699
+
700
+ run_id = resolve_current_run_id(project_dir=project_dir)
701
+ lock_verdict = test_intent_lock.verify_lock(project_dir, run_id=run_id)
702
+ delta_summary = data.get("_test_delta") if isinstance(data.get("_test_delta"), dict) else {}
703
+ if not delta_summary:
704
+ delta_summary = _load_test_delta_from_evidence(project_dir, run_id)
705
+
706
+ lock_missing = str(lock_verdict.get("status", "")).strip() != "ok"
707
+ weakened_without_waiver = _has_weakened_or_drift(delta_summary) and not _has_waiver_artifact(delta_summary)
708
+ if not lock_missing and not weakened_without_waiver:
709
+ return []
710
+
711
+ strict_mode = _proof_chain_strict_enabled()
712
+ if strict_mode:
713
+ return [json.dumps({"status": "blocked", "reason": "tdd_proof_chain_incomplete"}, sort_keys=True)]
714
+
715
+ warnings.warn(
716
+ "tdd_proof_chain_incomplete_permissive",
717
+ RuntimeWarning,
718
+ stacklevel=2,
719
+ )
720
+ advisories = data.setdefault("_stop_advisories", [])
721
+ advisories.append(
722
+ "[OMG advisory] tdd proof chain incomplete: active lock evidence or waiver artifact is missing. "
723
+ "Set OMG_PROOF_CHAIN_STRICT=1 to hard-block completion."
724
+ )
725
+ return []
726
+
624
727
  def check_simplifier(data, project_dir):
625
728
  """CHECK 7: Code simplifier — advisory only, never blocks."""
626
729
  if not get_feature_flag("simplifier", True):
@@ -832,7 +935,7 @@ def check_scope_drift(project_dir):
832
935
 
833
936
 
834
937
 
835
- def check_todo_continuation(data: dict) -> dict | None:
938
+ def check_todo_continuation(data: dict[str, object]) -> dict[str, str] | None:
836
939
  """Check if agent should continue due to incomplete todos.
837
940
  Returns a dict with continuation response if idle, None otherwise.
838
941
  Budget: STOP_CHECK_MAX_MS (15s)
@@ -911,6 +1014,7 @@ def main():
911
1014
  check_diff_budget,
912
1015
  check_recent_failures,
913
1016
  check_test_execution,
1017
+ check_tdd_proof_chain,
914
1018
  check_test_validator_coverage,
915
1019
  check_false_fix,
916
1020
  check_write_failures,