Files
cleveragents-core/features/automation_profile_precedence_chain.feature
T
HAL9000 3577bf95ba
CI / lint (pull_request) Successful in 56s
CI / quality (pull_request) Successful in 55s
CI / typecheck (pull_request) Successful in 1m2s
CI / security (pull_request) Successful in 1m11s
CI / helm (pull_request) Successful in 31s
CI / build (pull_request) Successful in 33s
CI / push-validation (pull_request) Successful in 29s
CI / unit_tests (pull_request) Successful in 6m49s
CI / docker (pull_request) Successful in 1m32s
CI / integration_tests (pull_request) Successful in 9m20s
CI / coverage (pull_request) Successful in 8m1s
CI / status-check (pull_request) Successful in 5s
feat: implement automation profile precedence chain plan action global
Implementation of the four-level automation profile precedence chain
(plan > action > project > global) as defined in the v3.5.0 specification.

Core implementation (src/):
  - PrecedenceSource StrEnum with PLAN, ACTION, PROJECT, GLOBAL levels
  - PrecedenceResolution frozen dataclass capturing full resolution state
  - resolve_precedence_chain() with plan > action > project > global logic
  - _resolve_global_profile() with explicit > env var > default fallback
  - Comprehensive debug logging for observability

BDD tests (features/):
  - automation_profile_precedence_chain.feature: 30 scenarios covering all
    16 combinations of plan/action/project/global configurations plus edge
    cases, logging verification, enum values, env var override, and custom registry
  - step definitions with proper log handler cleanup via context._cleanup_handlers

CI compliance fixes (bd8b6748):
  - ruff format applied to step definitions (fixes CI lint gate)
  - CHANGELOG.md updated with accurate 4-level chain description
  - test_reports/ artifacts removed; directory added to .gitignore
  - tdd_a2a_sdk_dependency.feature reverted to use correct Client import

ISSUES CLOSED: #8234
2026-06-02 01:25:33 -04:00

237 lines
12 KiB
Gherkin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Feature: Automation Profile Precedence Chain (plan > action > project > global)
The automation profile resolution follows a strict four-level precedence
chain: plan-level > action-level > project-level > global-level. This ensures that
fine-grained overrides work as intended for autonomous plan execution.
# ============================================================
# All 16 combinations: plan(set/unset) × action(set/unset) × project(set/unset) × global(set/default)
# ============================================================
# --- Combination 1: plan=set, action=set, project=set, global=set plan wins ---
Scenario: Combination 1 - plan overrides action, project, and explicit global
Given the global profile is configured as "cautious"
When I resolve the precedence chain with plan "ci" action "auto" project "trusted"
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 2: plan=set, action=set, project=set, global=default → plan wins ---
Scenario: Combination 2 - plan overrides action and project when global is default
Given the global profile is the default
When I resolve the precedence chain with plan "ci" action "auto" project "trusted"
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 3: plan=set, action=set, project=unset, global=set → plan wins ---
Scenario: Combination 3 - plan overrides action and explicit global when project is absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with plan "ci" action "auto" and no project
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 4: plan=set, action=set, project=unset, global=default → plan wins ---
Scenario: Combination 4 - plan overrides action when project and global are default
Given the global profile is the default
When I resolve the precedence chain with plan "ci" action "auto" and no project
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 5: plan=set, action=unset, project=set, global=set → plan wins ---
Scenario: Combination 5 - plan overrides project and explicit global when action is absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with plan "ci" and no action project "trusted"
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 6: plan=set, action=unset, project=set, global=default → plan wins ---
Scenario: Combination 6 - plan overrides project when action and global are default
Given the global profile is the default
When I resolve the precedence chain with plan "ci" and no action project "trusted"
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 7: plan=set, action=unset, project=unset, global=set → plan wins ---
Scenario: Combination 7 - plan overrides explicit global when action and project are absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with plan "ci" and no action and no project
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 8: plan=set, action=unset, project=unset, global=default → plan wins ---
Scenario: Combination 8 - plan overrides default global when action and project are absent
Given the global profile is the default
When I resolve the precedence chain with plan "ci" and no action and no project
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# --- Combination 9: plan=unset, action=set, project=set, global=set → action wins ---
Scenario: Combination 9 - action overrides project and explicit global when plan is absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with no plan and action "auto" project "trusted"
Then the resolved precedence profile name should be "auto"
And the precedence source should be "action"
# --- Combination 10: plan=unset, action=set, project=set, global=default → action wins ---
Scenario: Combination 10 - action overrides project when plan and global are default
Given the global profile is the default
When I resolve the precedence chain with no plan and action "auto" project "trusted"
Then the resolved precedence profile name should be "auto"
And the precedence source should be "action"
# --- Combination 11: plan=unset, action=set, project=unset, global=set → action wins ---
Scenario: Combination 11 - action overrides explicit global when plan and project are absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with no plan and action "auto" and no project
Then the resolved precedence profile name should be "auto"
And the precedence source should be "action"
# --- Combination 12: plan=unset, action=set, project=unset, global=default → action wins ---
Scenario: Combination 12 - action overrides default global when plan and project are absent
Given the global profile is the default
When I resolve the precedence chain with no plan and action "auto" and no project
Then the resolved precedence profile name should be "auto"
And the precedence source should be "action"
# --- Combination 13: plan=unset, action=unset, project=set, global=set → project wins ---
Scenario: Combination 13 - project overrides explicit global when plan and action are absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with no plan and no action project "trusted"
Then the resolved precedence profile name should be "trusted"
And the precedence source should be "project"
# --- Combination 14: plan=unset, action=unset, project=set, global=default → project wins ---
Scenario: Combination 14 - project overrides default global when plan and action are absent
Given the global profile is the default
When I resolve the precedence chain with no plan and no action project "trusted"
Then the resolved precedence profile name should be "trusted"
And the precedence source should be "project"
# --- Combination 15: plan=unset, action=unset, project=unset, global=set → global wins ---
Scenario: Combination 15 - explicit global used when plan, action, and project are absent
Given the global profile is configured as "cautious"
When I resolve the precedence chain with no plan and no action and no project
Then the resolved precedence profile name should be "cautious"
And the precedence source should be "global"
# --- Combination 16: plan=unset, action=unset, project=unset, global=default → global default ---
Scenario: Combination 16 - default global (manual) used when nothing is set
Given the global profile is the default
When I resolve the precedence chain with no plan and no action and no project
Then the resolved precedence profile name should be "manual"
And the precedence source should be "global"
# ============================================================
# Debug logging verification
# ============================================================
Scenario: Resolution chain is logged at debug level
Given the global profile is the default
And debug logging is captured for the precedence module
When I resolve the precedence chain with plan "ci" action "auto" project "trusted"
Then a debug log entry should mention the resolved profile name "ci"
And the debug log entry should mention the source "plan"
# ============================================================
# Resolution result fields
# ============================================================
Scenario: Resolution result exposes plan profile field
Given the global profile is the default
When I resolve the precedence chain with plan "ci" action "auto" project "trusted"
Then the resolution plan_profile field should be "ci"
And the resolution action_profile field should be "auto"
And the resolution project_profile field should be "trusted"
Scenario: Resolution result exposes global profile field
Given the global profile is configured as "cautious"
When I resolve the precedence chain with no plan and no action and no project
Then the resolution global_profile field should be "cautious"
Scenario: Resolution result exposes the full AutomationProfile object
Given the global profile is the default
When I resolve the precedence chain with plan "manual" and no action and no project
Then the resolved precedence profile object should have name "manual"
And the resolved precedence profile decompose_task should be 1.0
# ============================================================
# Environment variable global override
# ============================================================
Scenario: Env var sets global profile when no explicit global is configured
Given the global profile is the default
And the env var CLEVERAGENTS_AUTOMATION_PROFILE is "trusted"
When I resolve the precedence chain with no plan and no action and no project
Then the resolved precedence profile name should be "trusted"
And the precedence source should be "global"
Scenario: Plan-level still overrides env var global
Given the global profile is the default
And the env var CLEVERAGENTS_AUTOMATION_PROFILE is "trusted"
When I resolve the precedence chain with plan "ci" and no action and no project
Then the resolved precedence profile name should be "ci"
And the precedence source should be "plan"
# ============================================================
# Custom profile registry
# ============================================================
Scenario: Custom profile registry is used for resolution
Given the global profile is the default
And a custom profile registry contains "acme/deploy" with select_tool 0.5
When I resolve the precedence chain with plan "acme/deploy" and no action and no project
Then the resolved precedence profile name should be "acme/deploy"
And the precedence source should be "plan"
# ============================================================
# Empty string treated as absent
# ============================================================
Scenario: Empty string plan profile is treated as absent
Given the global profile is the default
When I resolve the precedence chain with empty plan and action "auto" and no project
Then the resolved precedence profile name should be "auto"
And the precedence source should be "action"
Scenario: Empty string action profile is treated as absent
Given the global profile is the default
When I resolve the precedence chain with plan absent and empty action and no project
Then the resolved precedence profile name should be "manual"
And the precedence source should be "global"
Scenario: Empty string project profile is treated as absent
Given the global profile is the default
When I resolve the precedence chain with plan absent and action absent and empty project
Then the resolved precedence profile name should be "manual"
And the precedence source should be "global"
# ============================================================
# PrecedenceSource enum values
# ============================================================
Scenario: PrecedenceSource PLAN has value "plan"
Then the PrecedenceSource PLAN value should be "plan"
Scenario: PrecedenceSource ACTION has value "action"
Then the PrecedenceSource ACTION value should be "action"
Scenario: PrecedenceSource PROJECT has value "project"
Then the PrecedenceSource PROJECT value should be "project"
Scenario: PrecedenceSource GLOBAL has value "global"
Then the PrecedenceSource GLOBAL value should be "global"