UAT: agents invariant list --effective --action excludes action-scoped invariants from effective set — spec requires action invariants to be included #2836

Open
opened 2026-04-04 20:46:17 +00:00 by freemo · 0 comments
Owner

Metadata

  • Branch: fix/invariant-effective-action-scope-excluded
  • Commit Message: fix(invariant): pass action_name to get_effective_invariants when scope is ACTION
  • Milestone: v3.3.0
  • Parent Epic: #394

Bug Report

Background and Context

The specification defines agents invariant list --effective --action ACTION as showing the "final, reconciled set of invariants that apply to a given context." For an action context, this should include action-scoped invariants + global invariants (at minimum), following the four-tier precedence chain: plan > action > project > global.

What Was Tested

Code analysis and runtime testing of src/cleveragents/application/services/invariant_service.py — the get_effective_invariants() method and list_invariants() method.

Expected Behavior (from spec)

When running agents invariant list --effective --action deploy-service, the output should include:

  1. Action-scoped invariants for deploy-service
  2. Global invariants

The --effective flag is documented as showing "the final, reconciled set of invariants that apply to a given context, taking precedence into account."

Actual Behavior

The get_effective_invariants() method signature only accepts plan_id and project_name parameters:

def get_effective_invariants(
    self,
    plan_id: str | None = None,
    project_name: str | None = None,
) -> list[Invariant]:

When list_invariants(scope=InvariantScope.ACTION, source_name='deploy-service', effective=True) is called, it calls get_effective_invariants(plan_id=None, project_name=None) — the action scope is completely ignored.

Result: Action-scoped invariants are excluded from the effective set. Instead, ALL project-scoped invariants (scope leakage) and global invariants are returned.

Steps to Reproduce

from cleveragents.application.services.invariant_service import InvariantService
from cleveragents.domain.models.core.invariant import InvariantScope

svc = InvariantService()
svc.add_invariant(text='Global rule', scope=InvariantScope.GLOBAL, source_name='system')
svc.add_invariant(text='Action rule', scope=InvariantScope.ACTION, source_name='deploy-service')
svc.add_invariant(text='Project rule', scope=InvariantScope.PROJECT, source_name='myproject')

# Simulate: agents invariant list --effective --action deploy-service
effective = svc.list_invariants(scope=InvariantScope.ACTION, source_name='deploy-service', effective=True)

# Expected: ['Global rule', 'Action rule'] (2 items)
# Actual: ['Project rule', 'Global rule'] (2 items - wrong! action rule missing, project rule leaked)

Code Location

  • src/cleveragents/application/services/invariant_service.pyget_effective_invariants() method (lines 165–200)
  • src/cleveragents/application/services/invariant_service.pylist_invariants() method (lines 107–138)

This is related to but distinct from the scope leakage bug being fixed in PR #1202. PR #1202 fixes the scope leakage (project invariants being included when no project context is given), but does not fix the action invariant exclusion issue described here.

Subtasks

  • Add action_name: str | None = None parameter to get_effective_invariants() in invariant_service.py
  • Update list_invariants() to pass action_name=source_name when scope == InvariantScope.ACTION
  • Update get_effective_invariants() internals to include action-scoped invariants when action_name is provided
  • Write Behave unit tests (in features/) covering the action-scope effective set scenario
  • Write Robot Framework integration tests (in robot/) verifying CLI output for agents invariant list --effective --action
  • Ensure no # type: ignore suppressions are introduced; all types must be fully statically typed (Pyright clean)

Definition of Done

  • get_effective_invariants() accepts action_name parameter and correctly includes action-scoped invariants in the effective set
  • list_invariants(scope=ACTION, source_name=X, effective=True) returns action-scoped invariants for X plus global invariants
  • No scope leakage: project invariants are not included when only action context is provided
  • Behave unit tests pass and cover the new behaviour
  • Robot Framework integration tests pass for the CLI command
  • All nox stages pass
  • Coverage >= 97%
  • PR merged and this issue closed

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/invariant-effective-action-scope-excluded` - **Commit Message**: `fix(invariant): pass action_name to get_effective_invariants when scope is ACTION` - **Milestone**: v3.3.0 - **Parent Epic**: #394 ## Bug Report ### Background and Context The specification defines `agents invariant list --effective --action ACTION` as showing the "final, reconciled set of invariants that apply to a given context." For an action context, this should include action-scoped invariants + global invariants (at minimum), following the four-tier precedence chain: `plan > action > project > global`. ### What Was Tested Code analysis and runtime testing of `src/cleveragents/application/services/invariant_service.py` — the `get_effective_invariants()` method and `list_invariants()` method. ### Expected Behavior (from spec) When running `agents invariant list --effective --action deploy-service`, the output should include: 1. Action-scoped invariants for `deploy-service` 2. Global invariants The `--effective` flag is documented as showing "the final, reconciled set of invariants that apply to a given context, taking precedence into account." ### Actual Behavior The `get_effective_invariants()` method signature only accepts `plan_id` and `project_name` parameters: ```python def get_effective_invariants( self, plan_id: str | None = None, project_name: str | None = None, ) -> list[Invariant]: ``` When `list_invariants(scope=InvariantScope.ACTION, source_name='deploy-service', effective=True)` is called, it calls `get_effective_invariants(plan_id=None, project_name=None)` — the action scope is completely ignored. **Result**: Action-scoped invariants are excluded from the effective set. Instead, ALL project-scoped invariants (scope leakage) and global invariants are returned. ### Steps to Reproduce ```python from cleveragents.application.services.invariant_service import InvariantService from cleveragents.domain.models.core.invariant import InvariantScope svc = InvariantService() svc.add_invariant(text='Global rule', scope=InvariantScope.GLOBAL, source_name='system') svc.add_invariant(text='Action rule', scope=InvariantScope.ACTION, source_name='deploy-service') svc.add_invariant(text='Project rule', scope=InvariantScope.PROJECT, source_name='myproject') # Simulate: agents invariant list --effective --action deploy-service effective = svc.list_invariants(scope=InvariantScope.ACTION, source_name='deploy-service', effective=True) # Expected: ['Global rule', 'Action rule'] (2 items) # Actual: ['Project rule', 'Global rule'] (2 items - wrong! action rule missing, project rule leaked) ``` ### Code Location - `src/cleveragents/application/services/invariant_service.py` — `get_effective_invariants()` method (lines 165–200) - `src/cleveragents/application/services/invariant_service.py` — `list_invariants()` method (lines 107–138) ### Note on Related Work This is related to but distinct from the scope leakage bug being fixed in PR #1202. PR #1202 fixes the scope leakage (project invariants being included when no project context is given), but does **not** fix the action invariant exclusion issue described here. ## Subtasks - [ ] Add `action_name: str | None = None` parameter to `get_effective_invariants()` in `invariant_service.py` - [ ] Update `list_invariants()` to pass `action_name=source_name` when `scope == InvariantScope.ACTION` - [ ] Update `get_effective_invariants()` internals to include action-scoped invariants when `action_name` is provided - [ ] Write Behave unit tests (in `features/`) covering the action-scope effective set scenario - [ ] Write Robot Framework integration tests (in `robot/`) verifying CLI output for `agents invariant list --effective --action` - [ ] Ensure no `# type: ignore` suppressions are introduced; all types must be fully statically typed (Pyright clean) ## Definition of Done - [ ] `get_effective_invariants()` accepts `action_name` parameter and correctly includes action-scoped invariants in the effective set - [ ] `list_invariants(scope=ACTION, source_name=X, effective=True)` returns action-scoped invariants for `X` plus global invariants - [ ] No scope leakage: project invariants are not included when only action context is provided - [ ] Behave unit tests pass and cover the new behaviour - [ ] Robot Framework integration tests pass for the CLI command - [ ] All nox stages pass - [ ] Coverage >= 97% - [ ] PR merged and this issue closed --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.3.0 milestone 2026-04-04 20:46:23 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#394 Epic: Decision Framework
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2836
No description provided.