oacp-cli 0.3.3__tar.gz → 0.3.4__tar.gz

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 (208) hide show
  1. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/CHANGELOG.md +13 -0
  2. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/PKG-INFO +1 -1
  3. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/agent_safety_defaults.md +1 -1
  4. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/autonomy.md +11 -7
  5. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/pyproject.toml +1 -1
  6. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/autonomy_gate.py +165 -34
  7. oacp_cli-0.3.4/tests/conformance/autonomy/expected/expired_message_pauses.yaml +8 -0
  8. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_commercial_pauses.yaml +9 -0
  9. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_config_pauses.yaml +9 -0
  10. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_credentials_pauses.yaml +9 -0
  11. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_memory_ssot_pauses.yaml +9 -0
  12. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_pricing_pauses.yaml +9 -0
  13. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_public_repo_pauses.yaml +9 -0
  14. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_secret_pauses.yaml +9 -0
  15. oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_side_effect_before_sensitive_pauses.yaml +9 -0
  16. oacp_cli-0.3.4/tests/conformance/autonomy/expected/invalid_message_pauses.yaml +8 -0
  17. oacp_cli-0.3.4/tests/conformance/autonomy/messages/expired_message.yaml +21 -0
  18. oacp_cli-0.3.4/tests/conformance/autonomy/messages/invalid_message.yaml +19 -0
  19. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_commercial.yaml +20 -0
  20. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_config.yaml +20 -0
  21. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_credentials.yaml +20 -0
  22. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_memory_ssot.yaml +20 -0
  23. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_pricing.yaml +20 -0
  24. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_public_repo.yaml +20 -0
  25. oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_secret.yaml +20 -0
  26. oacp_cli-0.3.4/tests/conformance/autonomy/messages/side_effect_before_sensitive.yaml +20 -0
  27. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_autonomy_conformance_fixtures.py +7 -0
  28. oacp_cli-0.3.4/tests/test_autonomy_gate.py +177 -0
  29. oacp_cli-0.3.3/tests/test_autonomy_gate.py +0 -83
  30. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/.github/workflows/ci.yml +0 -0
  31. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/.github/workflows/release.yml +0 -0
  32. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/.gitignore +0 -0
  33. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/CONTRIBUTING.md +0 -0
  34. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/LICENSE +0 -0
  35. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/Makefile +0 -0
  36. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/QUICKSTART.md +0 -0
  37. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/README.md +0 -0
  38. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/SECURITY.md +0 -0
  39. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/SPEC.md +0 -0
  40. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/from-claude-p.md +0 -0
  41. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/adoption.md +0 -0
  42. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/doctor.md +0 -0
  43. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/prompt_caching.md +0 -0
  44. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/runtime_capability_matrix.md +0 -0
  45. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/setup.md +0 -0
  46. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/unified_skill_spec.md +0 -0
  47. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/versioning.md +0 -0
  48. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/img/oacp-cli-demo.png +0 -0
  49. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/img/oacp-filesystem-tree.png +0 -0
  50. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/img/oacp-fleet-thread.png +0 -0
  51. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/agent_profiles.md +0 -0
  52. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/credential_scoping.md +0 -0
  53. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/cross_runtime_sync.md +0 -0
  54. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/dispatch_states.yaml +0 -0
  55. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/inbox_outbox.md +0 -0
  56. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/mcp_integration.md +0 -0
  57. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/multi_agent_shared_workspace.md +0 -0
  58. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/org_memory.md +0 -0
  59. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/packet_states.yaml +0 -0
  60. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/review_loop.md +0 -0
  61. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/runtime_capabilities.md +0 -0
  62. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/session_init.md +0 -0
  63. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/skills_manifest.yaml +0 -0
  64. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/task_negotiation.md +0 -0
  65. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/examples/quickstart/README.md +0 -0
  66. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/mcp_servers/oacp_coordinator.py +0 -0
  67. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/oacp/__init__.py +0 -0
  68. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/oacp/cli.py +0 -0
  69. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/_oacp_constants.py +0 -0
  70. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/_oacp_env.py +0 -0
  71. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/add_agent.py +0 -0
  72. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/agent_profile.py +0 -0
  73. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/check_quality_gate.py +0 -0
  74. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/codex_session_init.py +0 -0
  75. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/create_handoff_packet.py +0 -0
  76. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/handoff_schema.py +0 -0
  77. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_org_memory.py +0 -0
  78. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_packet.sh +0 -0
  79. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_project_workspace.py +0 -0
  80. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_project_workspace.sh +0 -0
  81. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/memory_archive_common.py +0 -0
  82. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/memory_cli.py +0 -0
  83. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/memory_sync.py +0 -0
  84. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/normalize_findings.py +0 -0
  85. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/oacp_doctor.py +0 -0
  86. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/oacp_inbox.py +0 -0
  87. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/oacp_watch.py +0 -0
  88. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/preflight.py +0 -0
  89. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/promote_to_archive.py +0 -0
  90. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/restore_from_archive.py +0 -0
  91. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/send_inbox_message.py +0 -0
  92. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/session_lifecycle_hooks.py +0 -0
  93. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/setup_runtime.py +0 -0
  94. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/update_workspace.sh +0 -0
  95. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/validate_agent_card.py +0 -0
  96. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/validate_message.py +0 -0
  97. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/write_event.py +0 -0
  98. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/agent_card.template.yaml +0 -0
  99. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/agent_profile.template.yaml +0 -0
  100. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/agent_status.template.yaml +0 -0
  101. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/checkpoint.template.md +0 -0
  102. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/claude/agents/role_agent.template.md +0 -0
  103. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/claude/rules/guardrail.template.md +0 -0
  104. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/findings_packet.template.yaml +0 -0
  105. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/github_actions_quality_gate.yaml +0 -0
  106. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/guardrails/coding_standards.template.md +0 -0
  107. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/guardrails/safe_commands.template.md +0 -0
  108. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/guardrails/secrets_rules.template.md +0 -0
  109. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/handoff_packet.template.yaml +0 -0
  110. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/inbox_message.template.yaml +0 -0
  111. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/manual_validation.template.md +0 -0
  112. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/merge_decision.template.md +0 -0
  113. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/decisions.md +0 -0
  114. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/events/.gitkeep +0 -0
  115. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/events/20260317-170120-example-api-convention.md +0 -0
  116. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/recent.md +0 -0
  117. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/rules.md +0 -0
  118. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/receiver_config.template.yaml +0 -0
  119. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/review_packet.template.md +0 -0
  120. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/roles/role_baseline.template.md +0 -0
  121. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/roles/role_definition.template.yaml +0 -0
  122. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/runtime_capabilities.yaml +0 -0
  123. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/skills_manifest.template.yaml +0 -0
  124. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/test_packet.template.md +0 -0
  125. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/README.md +0 -0
  126. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/checkpoint_breach.yaml +0 -0
  127. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/continuation_drift.yaml +0 -0
  128. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/continuation_within.yaml +0 -0
  129. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/top_level_side_effect_keys.yaml +0 -0
  130. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/always_pause.yaml +0 -0
  131. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/auto_review_continuation_enabled.yaml +0 -0
  132. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/auto_review_standard.yaml +0 -0
  133. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/auto_review_tight.yaml +0 -0
  134. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/malformed_config.yaml +0 -0
  135. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/always_pause_task.yaml +0 -0
  136. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/ambiguous_scope_pauses.yaml +0 -0
  137. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/brainstorm_destructive_pauses.yaml +0 -0
  138. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/brainstorm_side_effect_verbs_auto_accepts.yaml +0 -0
  139. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/brainstorm_without_profile_auto_accepts.yaml +0 -0
  140. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/checkpoint_breach_pauses.yaml +0 -0
  141. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/clean_auto_review_task.yaml +0 -0
  142. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_destructive_pauses.yaml +0 -0
  143. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_disabled_pauses.yaml +0 -0
  144. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_drift_pauses.yaml +0 -0
  145. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_enabled_auto_accepts.yaml +0 -0
  146. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_external_uncovered_pauses.yaml +0 -0
  147. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_dangerously_skip_permissions_pauses.yaml +0 -0
  148. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_external_side_effects_pauses.yaml +0 -0
  149. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_force_pauses.yaml +0 -0
  150. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_no_verify_pauses.yaml +0 -0
  151. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_no_verify_upper_pauses.yaml +0 -0
  152. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_rm_rf_pauses.yaml +0 -0
  153. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_sensitive_scope_pauses.yaml +0 -0
  154. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/malformed_config_pauses.yaml +0 -0
  155. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/missing_task_profile_pauses.yaml +0 -0
  156. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/path_like_deploy_auto_accepts.yaml +0 -0
  157. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/risk_obvious_no_profile_pauses.yaml +0 -0
  158. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/side_effect_booleans_pause.yaml +0 -0
  159. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/threshold_breach_pauses.yaml +0 -0
  160. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/tight_threshold_pauses.yaml +0 -0
  161. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/top_level_side_effect_actuals_ignored.yaml +0 -0
  162. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/unparsable_task_profile_pauses.yaml +0 -0
  163. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/ambiguous_scope.yaml +0 -0
  164. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/brainstorm_destructive.yaml +0 -0
  165. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/brainstorm_side_effect_verbs.yaml +0 -0
  166. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/brainstorm_without_profile.yaml +0 -0
  167. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/clean_task.yaml +0 -0
  168. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/continuation_grant.yaml +0 -0
  169. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/continuation_grant_destructive.yaml +0 -0
  170. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/continuation_grant_external_uncovered.yaml +0 -0
  171. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_dangerously_skip_permissions.yaml +0 -0
  172. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_external_side_effects.yaml +0 -0
  173. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_force.yaml +0 -0
  174. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_no_verify.yaml +0 -0
  175. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_no_verify_upper.yaml +0 -0
  176. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_rm_rf.yaml +0 -0
  177. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_sensitive_scope.yaml +0 -0
  178. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/missing_task_profile.yaml +0 -0
  179. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/path_like_deploy.yaml +0 -0
  180. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/risk_obvious_no_profile.yaml +0 -0
  181. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/side_effect_booleans.yaml +0 -0
  182. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/threshold_breach.yaml +0 -0
  183. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/unparsable_task_profile.yaml +0 -0
  184. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_add_agent.py +0 -0
  185. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_agent_profile.py +0 -0
  186. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_codex_session_init.py +0 -0
  187. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_create_handoff_packet.py +0 -0
  188. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_github_workflows.py +0 -0
  189. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_handoff_schema.py +0 -0
  190. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_init_project_workspace.py +0 -0
  191. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_memory_archive.py +0 -0
  192. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_cli.py +0 -0
  193. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_constants.py +0 -0
  194. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_coordinator.py +0 -0
  195. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_doctor.py +0 -0
  196. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_env.py +0 -0
  197. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_inbox.py +0 -0
  198. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_watch.py +0 -0
  199. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_preflight.py +0 -0
  200. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_review_loop.py +0 -0
  201. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_send_inbox_message.py +0 -0
  202. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_session_lifecycle_hooks.py +0 -0
  203. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_setup_runtime.py +0 -0
  204. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_update_workspace.py +0 -0
  205. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_validate_agent_card.py +0 -0
  206. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_validate_message.py +0 -0
  207. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_workspace_discovery.py +0 -0
  208. {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_write_event.py +0 -0
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.4] - 2026-06-11
9
+
10
+ ### Fixed
11
+
12
+ - Receiver autonomy Gate 1 now performs real message schema validation, expiry
13
+ comparison, SHA-256 hash recording, and same-receiver replay detection before
14
+ auto-accepting work.
15
+ - Receiver autonomy Gate 3 now pauses on credentials, pricing, commercial
16
+ content, and anchored config-sensitive scope, and evaluates external
17
+ side-effect hard stops before sensitive-scope hard stops to match the
18
+ protocol.
19
+
8
20
  ## [0.3.3] - 2026-06-11
9
21
 
10
22
  ### Added
@@ -180,6 +192,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
180
192
  - Checkout step in github-release workflow job (#19)
181
193
  - Pre-release audit fixes: SHA-pinned actions, dangling doc refs (#15, #16)
182
194
 
195
+ [0.3.4]: https://github.com/kiloloop/oacp/compare/v0.3.3...v0.3.4
183
196
  [0.3.3]: https://github.com/kiloloop/oacp/compare/v0.3.2...v0.3.3
184
197
  [0.3.2]: https://github.com/kiloloop/oacp/compare/v0.3.1...v0.3.2
185
198
  [0.3.1]: https://github.com/kiloloop/oacp/compare/v0.3.0...v0.3.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oacp-cli
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: Open Agent Coordination Protocol CLI for file-based multi-agent workflows
5
5
  Project-URL: Homepage, https://github.com/kiloloop/oacp
6
6
  Project-URL: Repository, https://github.com/kiloloop/oacp
@@ -40,7 +40,7 @@ Regardless of autonomy mode, receivers must pause on actual requests for:
40
40
 
41
41
  - Destructive command tokens: `rm -rf`, `--force`, `--no-verify`, `--dangerously-skip-permissions`
42
42
  - External side effects: push, deploy, merge, publish, credential rotation, dependency install
43
- - Sensitive scope: auth, config, secrets, dependencies, public repos, pricing/commercial content, memory SSOT
43
+ - Sensitive scope: auth, config, secrets, credentials, dependencies, public repos, pricing/commercial content, memory SSOT
44
44
 
45
45
  Profileless message types that are explicitly allowed for auto-review may log
46
46
  incidental side-effect verb mentions as notes instead of hard stops, but
@@ -97,8 +97,8 @@ If any required gate is missing or uncertain, the receiver pauses.
97
97
  as deploy/publish/merge are logged as notes instead of hard stops.
98
98
  Destructive tokens still pause.
99
99
  - Path-like tokens such as `packets/deploy/` are not deploy verbs.
100
- - Pause when the body touches auth, config, secrets, dependencies, public
101
- repos, pricing/commercial content, or memory SSOT.
100
+ - Pause when the body touches auth, config, secrets, credentials,
101
+ dependencies, public repos, pricing/commercial content, or memory SSOT.
102
102
  - Pause when file scope is ambiguous or broader than the declared profile.
103
103
  4. **Runtime/workspace**
104
104
  - Worktree is clean or the task can be isolated to a fresh branch.
@@ -114,11 +114,12 @@ Regardless of autonomy mode, receivers must pause on any of: destructive command
114
114
  tokens (`rm -rf`, `--force`, `--no-verify`,
115
115
  `--dangerously-skip-permissions`), external side effects
116
116
  (push/deploy/merge/publish/rotate/install), or modifications to auth, config,
117
- secrets, dependencies, public repos, pricing/commercial content, or memory SSOT,
118
- unless explicitly authorized by a separate safety-default exception.
117
+ secrets, credentials, dependencies, public repos, pricing/commercial content, or
118
+ memory SSOT, unless explicitly authorized by a separate safety-default
119
+ exception.
119
120
 
120
- Continuation grants do not override destructive tokens, auth/secrets,
121
- dependency, public-scope, pricing/commercial, or memory-SSOT hard stops.
121
+ Continuation grants do not override destructive tokens, auth/secrets/credentials,
122
+ dependency, public-scope, pricing/commercial, config, or memory-SSOT hard stops.
122
123
  When explicitly enabled, a valid continuation grant may cover declared external
123
124
  side effects only for the scoped PR, GitHub comment, or commit continuation
124
125
  fields that the grant marks true.
@@ -131,7 +132,7 @@ Every autonomy decision writes one YAML file:
131
132
 
132
133
  ```yaml
133
134
  schema_version: 1
134
- spec_version: "0.3.0"
135
+ spec_version: "0.3.1"
135
136
  created_at_utc: "2026-05-12T13:23:25Z"
136
137
  receiver: codex
137
138
  sender: iris
@@ -176,6 +177,9 @@ result:
176
177
 
177
178
  `policy_path` and `policy_sha256` may be null when the pause is caused by
178
179
  missing or malformed config. `sender` is logged only for traceability.
180
+ `spec_version: "0.3.1"` pins Gate 1 integrity enforcement: schema validation,
181
+ expiry rejection, raw YAML SHA-256 recording, and same-receiver replay
182
+ detection.
179
183
 
180
184
  ## State Transition Metadata
181
185
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oacp-cli"
7
- version = "0.3.3"
7
+ version = "0.3.4"
8
8
  description = "Open Agent Coordination Protocol CLI for file-based multi-agent workflows"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -11,6 +11,8 @@ scope-envelope contract. The module is intentionally separate from
11
11
  from __future__ import annotations
12
12
 
13
13
  import argparse
14
+ import datetime as dt
15
+ import hashlib
14
16
  import json
15
17
  import re
16
18
  import sys
@@ -19,6 +21,8 @@ from typing import Any, Dict, List, Optional, Sequence, Tuple
19
21
 
20
22
  import yaml
21
23
 
24
+ from validate_message import validate_message_dict
25
+
22
26
 
23
27
  VALID_MODES = {"always_pause", "auto_review"}
24
28
  POLICY_ACTIONS = {"pause"}
@@ -87,6 +91,18 @@ NON_DEMOTABLE_SIDE_EFFECT_PATTERNS = (
87
91
  SENSITIVE_SCOPE_PATTERNS = (
88
92
  ("auth", re.compile(r"(?<![\w/-])auth(?![\w/-])", re.IGNORECASE)),
89
93
  ("secrets", re.compile(r"(?<![\w/-])secrets?(?![\w/-])", re.IGNORECASE)),
94
+ ("credentials", re.compile(r"(?<![\w/-])credentials?(?![\w/-])", re.IGNORECASE)),
95
+ ("pricing", re.compile(r"(?<![\w/-])pricing(?![\w/-])", re.IGNORECASE)),
96
+ ("commercial", re.compile(r"(?<![\w/-])commercial(?![\w/-])", re.IGNORECASE)),
97
+ (
98
+ "config",
99
+ re.compile(
100
+ r"\bconfig(?:uration)?\s+(?:file|files|setting|settings|template|templates|yaml|yml)\b"
101
+ r"|\b(?:project|workspace|runtime|agent)\s+config(?:uration)?\b"
102
+ r"|\bconfig\.ya?ml\b",
103
+ re.IGNORECASE,
104
+ ),
105
+ ),
90
106
  (
91
107
  "public repo",
92
108
  re.compile(r"\bpublic\s+repositor(?:y|ies)|\bpublic\s+repo\b", re.IGNORECASE),
@@ -248,6 +264,57 @@ def first_match(
248
264
  return None
249
265
 
250
266
 
267
+ def message_sha256(
268
+ message: Dict[str, Any],
269
+ message_path: Optional[Path] = None,
270
+ ) -> str:
271
+ """Return the raw YAML hash when a path is available, otherwise a stable fallback."""
272
+ if message_path is not None:
273
+ return hashlib.sha256(message_path.read_bytes()).hexdigest()
274
+ serialized = yaml.safe_dump(message, sort_keys=True, allow_unicode=False).encode("utf-8")
275
+ return hashlib.sha256(serialized).hexdigest()
276
+
277
+
278
+ def message_expired(
279
+ message: Dict[str, Any],
280
+ now_utc: Optional[dt.datetime] = None,
281
+ ) -> bool:
282
+ expires_at = str(message.get("expires_at") or "").strip()
283
+ if not expires_at:
284
+ return False
285
+ now = now_utc or dt.datetime.now(dt.timezone.utc)
286
+ if now.tzinfo is None:
287
+ now = now.replace(tzinfo=dt.timezone.utc)
288
+ # validate_message_dict enforces Z-only format; ValueError here is defensive.
289
+ expires = dt.datetime.strptime(expires_at, "%Y-%m-%dT%H:%M:%SZ").replace(
290
+ tzinfo=dt.timezone.utc
291
+ )
292
+ return now >= expires
293
+
294
+
295
+ def prior_auto_accept_exists(
296
+ message_id: str,
297
+ receiver: str,
298
+ audit_dir: Optional[Path],
299
+ ) -> bool:
300
+ if not message_id or audit_dir is None or not audit_dir.is_dir():
301
+ return False
302
+ for audit_path in audit_dir.glob("*.yaml"):
303
+ try:
304
+ audit = yaml.safe_load(audit_path.read_text(encoding="utf-8"))
305
+ except (OSError, yaml.YAMLError):
306
+ continue
307
+ if not isinstance(audit, dict):
308
+ continue
309
+ if audit.get("message_id") != message_id:
310
+ continue
311
+ if audit.get("receiver") != receiver:
312
+ continue
313
+ if audit.get("decision") == "auto_accepted":
314
+ return True
315
+ return False
316
+
317
+
251
318
  def side_effect_notes_for_allowed_type(body: str) -> List[Dict[str, str]]:
252
319
  notes: List[Dict[str, str]] = []
253
320
  for label, pattern in SIDE_EFFECT_VERB_PATTERNS:
@@ -449,8 +516,13 @@ def evaluate_autonomy(
449
516
  message: Dict[str, Any],
450
517
  config: Dict[str, Any],
451
518
  actuals: Optional[Dict[str, Any]] = None,
519
+ message_path: Optional[Path] = None,
520
+ audit_dir: Optional[Path] = None,
521
+ receiver: str = "codex",
522
+ now_utc: Optional[dt.datetime] = None,
452
523
  ) -> Dict[str, Any]:
453
524
  """Evaluate a message/config pair and return a canonical decision dict."""
525
+ msg_hash = message_sha256(message, message_path)
454
526
  try:
455
527
  mode, policy = receiver_policy(config)
456
528
  except AutonomyConfigError:
@@ -459,6 +531,7 @@ def evaluate_autonomy(
459
531
  "decision": "paused",
460
532
  "mode": "always_pause",
461
533
  "reason_codes": ["config_malformed"],
534
+ "message_sha256": msg_hash,
462
535
  "scope_envelope": None,
463
536
  "logged_notes": [],
464
537
  "continuation_grant": {"present": False, "enabled": False},
@@ -471,21 +544,67 @@ def evaluate_autonomy(
471
544
  "decision": "paused",
472
545
  "mode": mode,
473
546
  "reason_codes": ["mode_always_pause"],
547
+ "message_sha256": msg_hash,
474
548
  "scope_envelope": None,
475
549
  "logged_notes": [],
476
550
  "continuation_grant": {"present": False, "enabled": False},
477
551
  "result": _base_result("paused", "always_pause", checkpoint),
478
552
  }
479
553
 
554
+ message_errors = validate_message_dict(message)
555
+ if message_errors:
556
+ checkpoint = evaluate_threshold_checkpoint(None, {}, actuals)
557
+ return {
558
+ "decision": "paused",
559
+ "mode": mode,
560
+ "reason_codes": ["message_invalid"],
561
+ "message_sha256": msg_hash,
562
+ "message_validation_errors": message_errors,
563
+ "scope_envelope": None,
564
+ "logged_notes": [],
565
+ "continuation_grant": {"present": False, "enabled": False},
566
+ "result": _base_result("paused", "message_invalid", checkpoint),
567
+ }
568
+
569
+ if message_expired(message, now_utc):
570
+ checkpoint = evaluate_threshold_checkpoint(None, {}, actuals)
571
+ return {
572
+ "decision": "paused",
573
+ "mode": mode,
574
+ "reason_codes": ["message_expired"],
575
+ "message_sha256": msg_hash,
576
+ "scope_envelope": None,
577
+ "logged_notes": [],
578
+ "continuation_grant": {"present": False, "enabled": False},
579
+ "result": _base_result("paused", "message_expired", checkpoint),
580
+ }
581
+
582
+ if prior_auto_accept_exists(str(message.get("id") or ""), receiver, audit_dir):
583
+ checkpoint = evaluate_threshold_checkpoint(None, {}, actuals)
584
+ return {
585
+ "decision": "paused",
586
+ "mode": mode,
587
+ "reason_codes": ["message_replayed"],
588
+ "message_sha256": msg_hash,
589
+ "scope_envelope": None,
590
+ "logged_notes": [],
591
+ "continuation_grant": {"present": False, "enabled": False},
592
+ "result": _base_result("paused", "message_replayed", checkpoint),
593
+ }
594
+
480
595
  body = str(message.get("body") or "")
481
596
  msg_type = str(message.get("type") or "")
482
597
  allow_without_profile = msg_type in policy["allow_without_task_profile"]
483
598
  logged_notes: List[Dict[str, str]] = []
484
599
 
600
+ def with_message_hash(decision: Dict[str, Any]) -> Dict[str, Any]:
601
+ decision["message_sha256"] = msg_hash
602
+ return decision
603
+
485
604
  profile, profile_error = extract_task_profile(body)
486
605
  if profile_error:
487
606
  checkpoint = evaluate_threshold_checkpoint(None, {}, actuals)
488
- return {
607
+ return with_message_hash({
489
608
  "decision": "paused",
490
609
  "mode": mode,
491
610
  "reason_codes": [profile_error],
@@ -493,12 +612,12 @@ def evaluate_autonomy(
493
612
  "logged_notes": logged_notes,
494
613
  "continuation_grant": {"present": False, "enabled": False},
495
614
  "result": _base_result("paused", profile_error, checkpoint),
496
- }
615
+ })
497
616
 
498
617
  if profile is None and not allow_without_profile:
499
618
  reason = "risk_obvious_no_profile" if obvious_no_profile_risk(body) else "task_profile_missing"
500
619
  checkpoint = evaluate_threshold_checkpoint(None, {}, actuals)
501
- return {
620
+ return with_message_hash({
502
621
  "decision": "paused",
503
622
  "mode": mode,
504
623
  "reason_codes": [reason],
@@ -506,7 +625,7 @@ def evaluate_autonomy(
506
625
  "logged_notes": logged_notes,
507
626
  "continuation_grant": {"present": False, "enabled": False},
508
627
  "result": _base_result("paused", reason, checkpoint),
509
- }
628
+ })
510
629
 
511
630
  envelope: Optional[Dict[str, Any]] = None
512
631
  profile_required_reason = "task_profile_present"
@@ -518,7 +637,7 @@ def evaluate_autonomy(
518
637
  envelope = normalize_scope_envelope(profile)
519
638
  except TaskProfileError:
520
639
  checkpoint = evaluate_threshold_checkpoint(None, {}, actuals)
521
- return {
640
+ return with_message_hash({
522
641
  "decision": "paused",
523
642
  "mode": mode,
524
643
  "reason_codes": ["task_profile_unparsable"],
@@ -526,12 +645,12 @@ def evaluate_autonomy(
526
645
  "logged_notes": logged_notes,
527
646
  "continuation_grant": {"present": False, "enabled": False},
528
647
  "result": _base_result("paused", "task_profile_unparsable", checkpoint),
529
- }
648
+ })
530
649
 
531
650
  matched = first_match(DESTRUCTIVE_PATTERNS, body)
532
651
  if matched:
533
652
  checkpoint = evaluate_threshold_checkpoint(envelope, {}, actuals)
534
- return {
653
+ return with_message_hash({
535
654
  "decision": "paused",
536
655
  "mode": mode,
537
656
  "reason_codes": ["hard_stop_destructive_command"],
@@ -540,52 +659,52 @@ def evaluate_autonomy(
540
659
  "logged_notes": logged_notes,
541
660
  "continuation_grant": {"present": False, "enabled": False},
542
661
  "result": _base_result("paused", "hard_stop", checkpoint),
543
- }
662
+ })
544
663
 
545
- matched = first_match(SENSITIVE_SCOPE_PATTERNS, body)
664
+ side_effect_patterns = NON_DEMOTABLE_SIDE_EFFECT_PATTERNS
665
+ if not allow_without_profile or profile is not None:
666
+ side_effect_patterns = SIDE_EFFECT_VERB_PATTERNS + side_effect_patterns
667
+ matched = first_match(side_effect_patterns, body)
546
668
  if matched:
547
669
  checkpoint = evaluate_threshold_checkpoint(envelope, {}, actuals)
548
- return {
670
+ return with_message_hash({
549
671
  "decision": "paused",
550
672
  "mode": mode,
551
- "reason_codes": ["hard_stop_sensitive_scope"],
673
+ "reason_codes": ["hard_stop_external_side_effect"],
552
674
  "matched_pattern": matched,
553
675
  "scope_envelope": envelope,
554
676
  "logged_notes": logged_notes,
555
677
  "continuation_grant": {"present": False, "enabled": False},
556
678
  "result": _base_result("paused", "hard_stop", checkpoint),
557
- }
679
+ })
558
680
 
559
- matched = first_match(AMBIGUOUS_SCOPE_PATTERNS, body)
681
+ matched = first_match(SENSITIVE_SCOPE_PATTERNS, body)
560
682
  if matched:
561
683
  checkpoint = evaluate_threshold_checkpoint(envelope, {}, actuals)
562
- return {
684
+ return with_message_hash({
563
685
  "decision": "paused",
564
686
  "mode": mode,
565
- "reason_codes": ["file_scope_ambiguous"],
687
+ "reason_codes": ["hard_stop_sensitive_scope"],
566
688
  "matched_pattern": matched,
567
689
  "scope_envelope": envelope,
568
690
  "logged_notes": logged_notes,
569
691
  "continuation_grant": {"present": False, "enabled": False},
570
- "result": _base_result("paused", "ambiguous_scope", checkpoint),
571
- }
692
+ "result": _base_result("paused", "hard_stop", checkpoint),
693
+ })
572
694
 
573
- side_effect_patterns = NON_DEMOTABLE_SIDE_EFFECT_PATTERNS
574
- if not allow_without_profile or profile is not None:
575
- side_effect_patterns = SIDE_EFFECT_VERB_PATTERNS + side_effect_patterns
576
- matched = first_match(side_effect_patterns, body)
695
+ matched = first_match(AMBIGUOUS_SCOPE_PATTERNS, body)
577
696
  if matched:
578
697
  checkpoint = evaluate_threshold_checkpoint(envelope, {}, actuals)
579
- return {
698
+ return with_message_hash({
580
699
  "decision": "paused",
581
700
  "mode": mode,
582
- "reason_codes": ["hard_stop_external_side_effect"],
701
+ "reason_codes": ["file_scope_ambiguous"],
583
702
  "matched_pattern": matched,
584
703
  "scope_envelope": envelope,
585
704
  "logged_notes": logged_notes,
586
705
  "continuation_grant": {"present": False, "enabled": False},
587
- "result": _base_result("paused", "hard_stop", checkpoint),
588
- }
706
+ "result": _base_result("paused", "ambiguous_scope", checkpoint),
707
+ })
589
708
 
590
709
  grant_result: Dict[str, Any] = {"present": False, "enabled": False}
591
710
  if envelope is not None:
@@ -605,7 +724,7 @@ def evaluate_autonomy(
605
724
  hard_profile_reasons.append("public_visibility_pause")
606
725
  if hard_profile_reasons:
607
726
  checkpoint = evaluate_threshold_checkpoint(envelope, grant_result, actuals)
608
- return {
727
+ return with_message_hash({
609
728
  "decision": "paused",
610
729
  "mode": mode,
611
730
  "reason_codes": hard_profile_reasons,
@@ -613,7 +732,7 @@ def evaluate_autonomy(
613
732
  "logged_notes": logged_notes,
614
733
  "continuation_grant": grant_result,
615
734
  "result": _base_result("paused", "hard_stop", checkpoint),
616
- }
735
+ })
617
736
 
618
737
  reasons = _threshold_reasons(envelope, policy["thresholds"])
619
738
  side_effect_reasons = _side_effect_reasons(envelope, grant_result)
@@ -622,7 +741,7 @@ def evaluate_autonomy(
622
741
  reasons.extend(side_effect_reasons)
623
742
  if reasons:
624
743
  checkpoint = evaluate_threshold_checkpoint(envelope, grant_result, actuals)
625
- return {
744
+ return with_message_hash({
626
745
  "decision": "paused",
627
746
  "mode": mode,
628
747
  "reason_codes": reasons,
@@ -630,11 +749,11 @@ def evaluate_autonomy(
630
749
  "logged_notes": logged_notes,
631
750
  "continuation_grant": grant_result,
632
751
  "result": _base_result("paused", "auto_review_paused", checkpoint),
633
- }
752
+ })
634
753
 
635
754
  checkpoint = evaluate_threshold_checkpoint(envelope, grant_result, actuals)
636
755
  if checkpoint["evaluated"] and checkpoint["breached"]:
637
- return {
756
+ return with_message_hash({
638
757
  "decision": "paused",
639
758
  "mode": mode,
640
759
  "reason_codes": ["threshold_checkpoint_breached"],
@@ -642,7 +761,7 @@ def evaluate_autonomy(
642
761
  "logged_notes": logged_notes,
643
762
  "continuation_grant": grant_result,
644
763
  "result": _base_result("paused", "threshold_checkpoint_breached", checkpoint),
645
- }
764
+ })
646
765
 
647
766
  reason_codes = [
648
767
  "message_valid",
@@ -658,7 +777,7 @@ def evaluate_autonomy(
658
777
  if grant_result.get("decision") == "accepted":
659
778
  reason_codes.append("continuation_grant_accepted")
660
779
 
661
- return {
780
+ return with_message_hash({
662
781
  "decision": "auto_accepted",
663
782
  "mode": mode,
664
783
  "reason_codes": reason_codes,
@@ -666,7 +785,7 @@ def evaluate_autonomy(
666
785
  "logged_notes": logged_notes,
667
786
  "continuation_grant": grant_result,
668
787
  "result": _base_result("done", "auto_accepted", checkpoint),
669
- }
788
+ })
670
789
 
671
790
 
672
791
  def main(argv: Optional[Sequence[str]] = None) -> int:
@@ -674,13 +793,25 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
674
793
  parser.add_argument("--config", required=True, type=Path)
675
794
  parser.add_argument("--message", required=True, type=Path)
676
795
  parser.add_argument("--actuals", type=Path)
796
+ parser.add_argument("--audit-dir", type=Path)
797
+ parser.add_argument("--receiver", default="codex")
677
798
  args = parser.parse_args(argv)
678
799
 
679
800
  try:
680
801
  config = load_yaml_file(args.config)
681
802
  message = load_yaml_file(args.message)
682
803
  actuals = load_yaml_file(args.actuals) if args.actuals else None
683
- print(json.dumps(evaluate_autonomy(message, config, actuals), indent=2))
804
+ print(json.dumps(
805
+ evaluate_autonomy(
806
+ message,
807
+ config,
808
+ actuals,
809
+ message_path=args.message,
810
+ audit_dir=args.audit_dir,
811
+ receiver=args.receiver,
812
+ ),
813
+ indent=2,
814
+ ))
684
815
  return 0
685
816
  except Exception as exc:
686
817
  print(f"ERROR: {exc}", file=sys.stderr)
@@ -0,0 +1,8 @@
1
+ case: expired_message_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/expired_message.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - message_expired
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_commercial_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_commercial.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "commercial"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_config_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_config.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "config"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_credentials_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_credentials.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "credentials"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_memory_ssot_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_memory_ssot.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "memory SSOT"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_pricing_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_pricing.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "pricing"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_public_repo_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_public_repo.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "public repo"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_sensitive_secret_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/sensitive_secret.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_sensitive_scope
9
+ matched_pattern: "secrets"
@@ -0,0 +1,9 @@
1
+ case: hard_stop_side_effect_before_sensitive_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/side_effect_before_sensitive.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - hard_stop_external_side_effect
9
+ matched_pattern: "merge"
@@ -0,0 +1,8 @@
1
+ case: invalid_message_pauses
2
+ config: configs/auto_review_standard.yaml
3
+ message: messages/invalid_message.yaml
4
+ expected:
5
+ decision: paused
6
+ mode: auto_review
7
+ reason_codes:
8
+ - message_invalid
@@ -0,0 +1,21 @@
1
+ id: msg-20260512121200-iris-expired
2
+ from: iris
3
+ to: codex
4
+ type: task_request
5
+ priority: P2
6
+ created_at_utc: "2026-05-12T12:12:00Z"
7
+ expires_at: "2020-01-01T00:00:00Z"
8
+ subject: "Expired task"
9
+ body: |
10
+ ## Task
11
+ Update one documentation paragraph for clarity.
12
+
13
+ task_profile:
14
+ estimated_minutes: 20
15
+ risk_tier: P3
16
+ expected_files_touched: 1
17
+ destructive_ops: false
18
+ external_side_effects: false
19
+ touches_auth_config_or_secrets: false
20
+ touches_dependencies: false
21
+ public_visibility: false
@@ -0,0 +1,19 @@
1
+ id: msg-20260512121300-iris-invalid
2
+ from: iris
3
+ type: task_request
4
+ priority: P2
5
+ created_at_utc: "2026-05-12T12:13:00Z"
6
+ subject: "Invalid task"
7
+ body: |
8
+ ## Task
9
+ Update one documentation paragraph for clarity.
10
+
11
+ task_profile:
12
+ estimated_minutes: 20
13
+ risk_tier: P3
14
+ expected_files_touched: 1
15
+ destructive_ops: false
16
+ external_side_effects: false
17
+ touches_auth_config_or_secrets: false
18
+ touches_dependencies: false
19
+ public_visibility: false
@@ -0,0 +1,20 @@
1
+ id: msg-20260512121400-iris-commercial
2
+ from: iris
3
+ to: codex
4
+ type: task_request
5
+ priority: P2
6
+ created_at_utc: "2026-05-12T12:14:00Z"
7
+ subject: "Commercial terms update"
8
+ body: |
9
+ ## Task
10
+ Update the commercial terms summary for the product page.
11
+
12
+ task_profile:
13
+ estimated_minutes: 10
14
+ risk_tier: P3
15
+ expected_files_touched: 1
16
+ destructive_ops: false
17
+ external_side_effects: false
18
+ touches_auth_config_or_secrets: false
19
+ touches_dependencies: false
20
+ public_visibility: false