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.
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/CHANGELOG.md +13 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/PKG-INFO +1 -1
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/agent_safety_defaults.md +1 -1
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/autonomy.md +11 -7
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/pyproject.toml +1 -1
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/autonomy_gate.py +165 -34
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/expired_message_pauses.yaml +8 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_commercial_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_config_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_credentials_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_memory_ssot_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_pricing_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_public_repo_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_secret_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_side_effect_before_sensitive_pauses.yaml +9 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/expected/invalid_message_pauses.yaml +8 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/expired_message.yaml +21 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/invalid_message.yaml +19 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_commercial.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_config.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_credentials.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_memory_ssot.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_pricing.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_public_repo.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/sensitive_secret.yaml +20 -0
- oacp_cli-0.3.4/tests/conformance/autonomy/messages/side_effect_before_sensitive.yaml +20 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_autonomy_conformance_fixtures.py +7 -0
- oacp_cli-0.3.4/tests/test_autonomy_gate.py +177 -0
- oacp_cli-0.3.3/tests/test_autonomy_gate.py +0 -83
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/.github/workflows/ci.yml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/.github/workflows/release.yml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/.gitignore +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/CONTRIBUTING.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/LICENSE +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/Makefile +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/QUICKSTART.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/README.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/SECURITY.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/SPEC.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/from-claude-p.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/adoption.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/doctor.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/prompt_caching.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/runtime_capability_matrix.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/setup.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/unified_skill_spec.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/guides/versioning.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/img/oacp-cli-demo.png +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/img/oacp-filesystem-tree.png +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/img/oacp-fleet-thread.png +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/agent_profiles.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/credential_scoping.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/cross_runtime_sync.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/dispatch_states.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/inbox_outbox.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/mcp_integration.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/multi_agent_shared_workspace.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/org_memory.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/packet_states.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/review_loop.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/runtime_capabilities.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/session_init.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/skills_manifest.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/docs/protocol/task_negotiation.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/examples/quickstart/README.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/mcp_servers/oacp_coordinator.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/oacp/__init__.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/oacp/cli.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/_oacp_constants.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/_oacp_env.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/add_agent.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/agent_profile.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/check_quality_gate.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/codex_session_init.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/create_handoff_packet.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/handoff_schema.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_org_memory.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_packet.sh +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_project_workspace.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/init_project_workspace.sh +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/memory_archive_common.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/memory_cli.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/memory_sync.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/normalize_findings.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/oacp_doctor.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/oacp_inbox.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/oacp_watch.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/preflight.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/promote_to_archive.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/restore_from_archive.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/send_inbox_message.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/session_lifecycle_hooks.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/setup_runtime.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/update_workspace.sh +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/validate_agent_card.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/validate_message.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/scripts/write_event.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/agent_card.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/agent_profile.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/agent_status.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/checkpoint.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/claude/agents/role_agent.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/claude/rules/guardrail.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/findings_packet.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/github_actions_quality_gate.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/guardrails/coding_standards.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/guardrails/safe_commands.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/guardrails/secrets_rules.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/handoff_packet.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/inbox_message.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/manual_validation.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/merge_decision.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/decisions.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/events/.gitkeep +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/events/20260317-170120-example-api-convention.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/recent.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/org-memory/rules.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/receiver_config.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/review_packet.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/roles/role_baseline.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/roles/role_definition.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/runtime_capabilities.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/skills_manifest.template.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/templates/test_packet.template.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/README.md +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/checkpoint_breach.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/continuation_drift.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/continuation_within.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/actuals/top_level_side_effect_keys.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/always_pause.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/auto_review_continuation_enabled.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/auto_review_standard.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/auto_review_tight.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/configs/malformed_config.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/always_pause_task.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/ambiguous_scope_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/brainstorm_destructive_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/brainstorm_side_effect_verbs_auto_accepts.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/brainstorm_without_profile_auto_accepts.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/checkpoint_breach_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/clean_auto_review_task.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_destructive_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_disabled_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_drift_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_enabled_auto_accepts.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/continuation_grant_external_uncovered_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_dangerously_skip_permissions_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_external_side_effects_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_force_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_no_verify_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_no_verify_upper_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_rm_rf_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/hard_stop_sensitive_scope_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/malformed_config_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/missing_task_profile_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/path_like_deploy_auto_accepts.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/risk_obvious_no_profile_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/side_effect_booleans_pause.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/threshold_breach_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/tight_threshold_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/top_level_side_effect_actuals_ignored.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/expected/unparsable_task_profile_pauses.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/ambiguous_scope.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/brainstorm_destructive.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/brainstorm_side_effect_verbs.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/brainstorm_without_profile.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/clean_task.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/continuation_grant.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/continuation_grant_destructive.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/continuation_grant_external_uncovered.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_dangerously_skip_permissions.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_external_side_effects.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_force.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_no_verify.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_no_verify_upper.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_rm_rf.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/hard_stop_sensitive_scope.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/missing_task_profile.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/path_like_deploy.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/risk_obvious_no_profile.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/side_effect_booleans.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/threshold_breach.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/conformance/autonomy/messages/unparsable_task_profile.yaml +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_add_agent.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_agent_profile.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_codex_session_init.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_create_handoff_packet.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_github_workflows.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_handoff_schema.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_init_project_workspace.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_memory_archive.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_cli.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_constants.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_coordinator.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_doctor.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_env.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_inbox.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_oacp_watch.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_preflight.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_review_loop.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_send_inbox_message.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_session_lifecycle_hooks.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_setup_runtime.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_update_workspace.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_validate_agent_card.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_validate_message.py +0 -0
- {oacp_cli-0.3.3 → oacp_cli-0.3.4}/tests/test_workspace_discovery.py +0 -0
- {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
|
+
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,
|
|
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
|
|
118
|
-
unless explicitly authorized by a separate safety-default
|
|
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.
|
|
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
|
|
|
@@ -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
|
-
|
|
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": ["
|
|
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(
|
|
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": ["
|
|
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", "
|
|
571
|
-
}
|
|
692
|
+
"result": _base_result("paused", "hard_stop", checkpoint),
|
|
693
|
+
})
|
|
572
694
|
|
|
573
|
-
|
|
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": ["
|
|
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", "
|
|
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(
|
|
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)
|
oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_credentials_pauses.yaml
ADDED
|
@@ -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"
|
oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_memory_ssot_pauses.yaml
ADDED
|
@@ -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"
|
oacp_cli-0.3.4/tests/conformance/autonomy/expected/hard_stop_sensitive_public_repo_pauses.yaml
ADDED
|
@@ -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_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,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
|