@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
@@ -2,13 +2,25 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
+ import re
6
+ import warnings
5
7
  from datetime import datetime, timezone
6
8
  from hashlib import sha256
7
9
  from pathlib import Path
8
10
 
11
+ from runtime.release_run_coordinator import resolve_current_run_id
12
+ from runtime.test_intent_lock import verify_lock
13
+
9
14
 
10
15
  _MUTATING_TOOLS = frozenset({"Write", "Edit", "MultiEdit"})
11
16
  _EXEMPTIONS = frozenset({"docs", "config", "generated", "test"})
17
+ _MUTATION_BASH_PATTERNS = (
18
+ r"\b(git\s+(add|commit|push|rebase|cherry-pick|merge|tag))\b",
19
+ r"\b(rm|mv|cp|tee|touch|mkdir|rmdir|ln)\b",
20
+ r"\b(sed\s+-i|perl\s+-pi)\b",
21
+ r"\b(chmod|chown)\b",
22
+ r">\s*[^\s]",
23
+ )
12
24
 
13
25
 
14
26
  def check_mutation_allowed(
@@ -18,11 +30,25 @@ def check_mutation_allowed(
18
30
  lock_id: str | None,
19
31
  *,
20
32
  exemption: str | None = None,
33
+ command: str | None = None,
34
+ run_id: str | None = None,
35
+ metadata: dict[str, object] | None = None,
21
36
  ) -> dict[str, str | None]:
22
37
  normalized_tool = str(tool or "").strip()
23
38
  normalized_file_path = str(file_path or "").strip()
24
39
  normalized_lock_id = str(lock_id or "").strip() or None
25
40
  normalized_exemption = str(exemption or "").strip().lower() or None
41
+ normalized_command = str(command or "").strip()
42
+ metadata_obj = metadata if isinstance(metadata, dict) else {}
43
+ explicit_exempt = bool(metadata_obj.get("exempt") is True)
44
+ strict_mode = os.environ.get("OMG_TDD_GATE_STRICT", "0").strip() == "1"
45
+
46
+ if explicit_exempt:
47
+ return {
48
+ "status": "exempt",
49
+ "reason": "metadata exemption allows mutation without lock",
50
+ "lock_id": normalized_lock_id,
51
+ }
26
52
 
27
53
  if normalized_exemption in _EXEMPTIONS:
28
54
  return {
@@ -31,36 +57,56 @@ def check_mutation_allowed(
31
57
  "lock_id": normalized_lock_id,
32
58
  }
33
59
 
34
- if normalized_tool not in _MUTATING_TOOLS:
60
+ requires_lock = normalized_tool in _MUTATING_TOOLS
61
+ if normalized_tool == "Bash":
62
+ requires_lock = _is_mutation_capable_bash(normalized_command)
63
+
64
+ if not requires_lock:
35
65
  return {
36
66
  "status": "allowed",
37
67
  "reason": "tool is read-only for mutation gate",
38
68
  "lock_id": normalized_lock_id,
39
69
  }
40
70
 
41
- if normalized_lock_id and _lock_exists(project_dir, normalized_lock_id):
71
+ resolved_run_id = str(run_id or "").strip() or resolve_current_run_id(project_dir=project_dir)
72
+ verification = verify_lock(project_dir, run_id=resolved_run_id, lock_id=normalized_lock_id)
73
+ if verification.get("status") == "ok":
42
74
  return {
43
75
  "status": "allowed",
44
76
  "reason": "active test intent lock found",
77
+ "lock_id": str(verification.get("lock_id") or normalized_lock_id or "") or None,
78
+ }
79
+
80
+ reason = str(verification.get("reason", "no_active_test_intent_lock"))
81
+ if strict_mode:
82
+ _write_block_artifact(project_dir, normalized_tool, normalized_file_path, reason)
83
+ return {
84
+ "status": "blocked",
85
+ "reason": reason,
45
86
  "lock_id": normalized_lock_id,
46
87
  }
47
88
 
48
- reason = (
49
- "mutation denied: active test intent lock is required for mutation tools"
50
- if not normalized_lock_id
51
- else f"mutation denied: lock_id '{normalized_lock_id}' not found"
89
+ warnings.warn(
90
+ f"mutation_gate_permissive_allow:{normalized_tool}:{reason}",
91
+ RuntimeWarning,
92
+ stacklevel=2,
52
93
  )
53
- _write_block_artifact(project_dir, normalized_tool, normalized_file_path, reason)
54
94
  return {
55
- "status": "blocked",
95
+ "status": "allowed",
56
96
  "reason": reason,
57
97
  "lock_id": normalized_lock_id,
58
98
  }
59
99
 
60
100
 
61
- def _lock_exists(project_dir: str, lock_id: str) -> bool:
62
- lock_path = Path(project_dir) / ".omg" / "state" / "test-intent-lock" / f"{lock_id}.json"
63
- return lock_path.is_file()
101
+ def _is_mutation_capable_bash(command: str) -> bool:
102
+ normalized_command = str(command or "").strip()
103
+ if not normalized_command:
104
+ return False
105
+ lowered = normalized_command.lower()
106
+ for pattern in _MUTATION_BASH_PATTERNS:
107
+ if re.search(pattern, lowered):
108
+ return True
109
+ return False
64
110
 
65
111
 
66
112
  def _write_block_artifact(project_dir: str, tool: str, file_path: str, reason: str) -> None:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "OmgCompatContractSnapshot",
3
- "contract_version": "2.1.0",
3
+ "contract_version": "2.1.4",
4
4
  "count": 47,
5
5
  "contracts": [
6
6
  {
@@ -912,5 +912,5 @@
912
912
  "notes": "Writes long-form memory artifact for writing workflows."
913
913
  }
914
914
  ],
915
- "generated_at": "2026-03-08T19:35:25.796113+00:00"
915
+ "generated_at": "2026-03-09T21:20:44.496932+00:00"
916
916
  }
@@ -125,7 +125,7 @@ def _read_repo_text(rel_path: str) -> str:
125
125
 
126
126
  @mcp.tool()
127
127
  def omg_policy_evaluate(tool: str, input: dict[str, Any]) -> dict[str, Any]:
128
- if tool in {"Write", "Edit", "MultiEdit"}:
128
+ if tool in {"Write", "Edit", "MultiEdit", "Bash"}:
129
129
  run_id_candidate = input.get("run_id") if isinstance(input, dict) else None
130
130
  run_id: str | None = None
131
131
  if isinstance(run_id_candidate, str) and run_id_candidate.strip():
@@ -138,9 +138,10 @@ def omg_policy_evaluate(tool: str, input: dict[str, Any]) -> dict[str, Any]:
138
138
  if not run_id:
139
139
  run_id = resolve_current_run_id()
140
140
 
141
- tool_plan_result = tool_plan_gate_check(_service().project_dir, run_id, tool)
142
- if tool_plan_result.get("status") == "blocked":
143
- return tool_plan_result
141
+ if tool in {"Write", "Edit", "MultiEdit"}:
142
+ tool_plan_result = tool_plan_gate_check(_service().project_dir, run_id, tool)
143
+ if tool_plan_result.get("status") == "blocked":
144
+ return tool_plan_result
144
145
 
145
146
  lock_id: str | None = None
146
147
  if isinstance(metadata, dict):
@@ -158,6 +159,9 @@ def omg_policy_evaluate(tool: str, input: dict[str, Any]) -> dict[str, Any]:
158
159
  "file_path": str(input.get("file_path", "")) if isinstance(input, dict) else "",
159
160
  "lock_id": lock_id,
160
161
  "exemption": exemption,
162
+ "command": str(input.get("command", "")) if isinstance(input, dict) else "",
163
+ "run_id": run_id,
164
+ "metadata": metadata if isinstance(metadata, dict) else None,
161
165
  }
162
166
  )
163
167
  if gate_status == 200 and gate_payload.get("status") == "blocked":
@@ -238,6 +242,12 @@ def omg_guide_assert(candidate: str, rules: dict[str, Any]) -> dict[str, Any]:
238
242
  return payload
239
243
 
240
244
 
245
+ @mcp.tool()
246
+ def omg_get_session_health(run_id: str | None = None) -> dict[str, Any]:
247
+ _status, payload = _service().session_health({"run_id": run_id})
248
+ return payload
249
+
250
+
241
251
  @mcp.prompt(name="omg_contract_summary", description="Summarize the OMG production contract and generated host outputs")
242
252
  def omg_contract_summary(channel: str = "public") -> str:
243
253
  return (
@@ -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)