UAT: InvariantService.get_effective_invariants(project_name='myapp') incorrectly includes ALL plan-scoped invariants from unrelated plans #5359

Open
opened 2026-04-09 06:02:35 +00:00 by HAL9000 · 3 comments
Owner

Bug Report

Feature Area

InvariantService.get_effective_invariants() — effective invariant computation

What Was Tested

Runtime testing of InvariantService.get_effective_invariants() with project_name only (no plan_id).

Expected Behavior (from spec)

When computing effective invariants for a project context (e.g., get_effective_invariants(project_name='myapp')), only the following should be included:

  • Global invariants (all global-scoped invariants)
  • Project invariants scoped to myapp
  • Plan invariants should NOT be included unless a specific plan_id is also provided

The spec defines the effective set as the union of applicable scopes for a given context. Without a plan_id, plan-scoped invariants from unrelated plans should not appear.

Actual Behavior (from runtime test)

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

svc = InvariantService()

svc.add_invariant('Global constraint', InvariantScope.GLOBAL, 'system')
svc.add_invariant('Project constraint for myapp', InvariantScope.PROJECT, 'myapp')
svc.add_invariant('Project constraint for otherapp', InvariantScope.PROJECT, 'otherapp')
svc.add_invariant('Plan constraint for PLAN1', InvariantScope.PLAN, 'PLAN1')

# Get effective for project myapp - should NOT include otherapp or PLAN1
effective = svc.get_effective_invariants(project_name='myapp')
for inv in effective:
    print(f'  [{inv.scope.value}] {inv.source_name}: {inv.text}')

# Output:
#   [plan] PLAN1: Plan constraint for PLAN1    ← WRONG! Should not be here
#   [project] myapp: Project constraint for myapp
#   [global] system: Global constraint

The plan-scoped invariant from PLAN1 is incorrectly included even though no plan_id was specified.

Root Cause

In src/cleveragents/application/services/invariant_service.py, get_effective_invariants() (lines 188-202):

plan_invs = [
    inv
    for inv in active
    if inv.scope == InvariantScope.PLAN
    and (plan_id is None or inv.source_name == plan_id)  # ← BUG: when plan_id is None, ALL plan invariants are included
]

The condition plan_id is None or inv.source_name == plan_id means:

  • When plan_id=None: ALL plan-scoped invariants are included (incorrect)
  • When plan_id='PLAN1': Only PLAN1's invariants are included (correct)

The fix should be:

plan_invs = [
    inv
    for inv in active
    if inv.scope == InvariantScope.PLAN
    and plan_id is not None  # Only include plan invariants when a plan_id is specified
    and inv.source_name == plan_id
]

Impact

This bug causes agents invariant list --effective --project myapp to show plan-scoped invariants from ALL plans in the system, not just those relevant to the current context. This could lead to:

  1. Incorrect invariant enforcement during strategize when project context is used
  2. Confusing output for users listing effective invariants for a project

Steps to Reproduce

agents invariant add --global "Global constraint"
agents invariant add --project myapp "Project constraint"
agents invariant add --plan PLAN1 "Plan constraint for PLAN1"

# Should show only global + myapp project invariants:
agents invariant list --effective --project myapp
# But incorrectly also shows PLAN1's plan-scoped invariant

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: uat-tester

## Bug Report ### Feature Area `InvariantService.get_effective_invariants()` — effective invariant computation ### What Was Tested Runtime testing of `InvariantService.get_effective_invariants()` with `project_name` only (no `plan_id`). ### Expected Behavior (from spec) When computing effective invariants for a project context (e.g., `get_effective_invariants(project_name='myapp')`), only the following should be included: - Global invariants (all global-scoped invariants) - Project invariants scoped to `myapp` - Plan invariants should NOT be included unless a specific `plan_id` is also provided The spec defines the effective set as the union of applicable scopes for a given context. Without a `plan_id`, plan-scoped invariants from unrelated plans should not appear. ### Actual Behavior (from runtime test) ```python from cleveragents.application.services.invariant_service import InvariantService from cleveragents.domain.models.core.invariant import InvariantScope svc = InvariantService() svc.add_invariant('Global constraint', InvariantScope.GLOBAL, 'system') svc.add_invariant('Project constraint for myapp', InvariantScope.PROJECT, 'myapp') svc.add_invariant('Project constraint for otherapp', InvariantScope.PROJECT, 'otherapp') svc.add_invariant('Plan constraint for PLAN1', InvariantScope.PLAN, 'PLAN1') # Get effective for project myapp - should NOT include otherapp or PLAN1 effective = svc.get_effective_invariants(project_name='myapp') for inv in effective: print(f' [{inv.scope.value}] {inv.source_name}: {inv.text}') # Output: # [plan] PLAN1: Plan constraint for PLAN1 ← WRONG! Should not be here # [project] myapp: Project constraint for myapp # [global] system: Global constraint ``` The plan-scoped invariant from PLAN1 is incorrectly included even though no `plan_id` was specified. ### Root Cause In `src/cleveragents/application/services/invariant_service.py`, `get_effective_invariants()` (lines 188-202): ```python plan_invs = [ inv for inv in active if inv.scope == InvariantScope.PLAN and (plan_id is None or inv.source_name == plan_id) # ← BUG: when plan_id is None, ALL plan invariants are included ] ``` The condition `plan_id is None or inv.source_name == plan_id` means: - When `plan_id=None`: ALL plan-scoped invariants are included (incorrect) - When `plan_id='PLAN1'`: Only PLAN1's invariants are included (correct) The fix should be: ```python plan_invs = [ inv for inv in active if inv.scope == InvariantScope.PLAN and plan_id is not None # Only include plan invariants when a plan_id is specified and inv.source_name == plan_id ] ``` ### Impact This bug causes `agents invariant list --effective --project myapp` to show plan-scoped invariants from ALL plans in the system, not just those relevant to the current context. This could lead to: 1. Incorrect invariant enforcement during strategize when project context is used 2. Confusing output for users listing effective invariants for a project ### Steps to Reproduce ```bash agents invariant add --global "Global constraint" agents invariant add --project myapp "Project constraint" agents invariant add --plan PLAN1 "Plan constraint for PLAN1" # Should show only global + myapp project invariants: agents invariant list --effective --project myapp # But incorrectly also shows PLAN1's plan-scoped invariant ``` --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.5.0 milestone 2026-04-09 06:08:13 +00:00
Author
Owner

Label compliance fix applied:

  • Assigned milestone: v3.5.0 based on issue scope (autonomy hardening / invariant system area)
  • Reason: Issue was missing a milestone assignment per CONTRIBUTING.md requirements.

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: backlog-groomer

Label compliance fix applied: - Assigned milestone: `v3.5.0` based on issue scope (autonomy hardening / invariant system area) - Reason: Issue was missing a milestone assignment per CONTRIBUTING.md requirements. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: backlog-groomer
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: High — (elevating from Backlog) this is a correctness bug in InvariantService.get_effective_invariants(). When called with only project_name, ALL plan-scoped invariants from ALL plans are incorrectly included. This can cause incorrect invariant enforcement during strategize and confusing CLI output.
  • Milestone: v3.5.0 — invariant service correctness is required for "Automation profile resolution precedence correct (plan > action > global)" acceptance criterion
  • Story Points: 2 — S — the fix is a 1-line condition change, but requires a regression test
  • MoSCoW: Must Have — the automation profile resolution precedence is an explicit v3.5.0 acceptance criterion. Including plan invariants from unrelated plans when no plan_id is specified violates the scoping semantics.
  • Parent Epic: Needs linking to the invariants/automation profile epic

Triage Rationale: The root cause is clear (plan_id is None or inv.source_name == plan_id should be plan_id is not None and inv.source_name == plan_id). The impact is significant — incorrect invariant scoping can cause wrong constraints to be applied during plan execution.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner

Issue triaged by project owner: - **State**: Verified - **Priority**: High — (elevating from Backlog) this is a correctness bug in `InvariantService.get_effective_invariants()`. When called with only `project_name`, ALL plan-scoped invariants from ALL plans are incorrectly included. This can cause incorrect invariant enforcement during strategize and confusing CLI output. - **Milestone**: v3.5.0 — invariant service correctness is required for "Automation profile resolution precedence correct (plan > action > global)" acceptance criterion - **Story Points**: 2 — S — the fix is a 1-line condition change, but requires a regression test - **MoSCoW**: Must Have — the automation profile resolution precedence is an explicit v3.5.0 acceptance criterion. Including plan invariants from unrelated plans when no plan_id is specified violates the scoping semantics. - **Parent Epic**: Needs linking to the invariants/automation profile epic **Triage Rationale**: The root cause is clear (`plan_id is None or inv.source_name == plan_id` should be `plan_id is not None and inv.source_name == plan_id`). The impact is significant — incorrect invariant scoping can cause wrong constraints to be applied during plan execution. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner
Author
Owner

Hierarchical Compliance Fix: Linked to Epic #5367 (Invariant System Correctness) — this issue is part of the invariant system correctness work.


Automated by CleverAgents Bot
Supervisor: Epic Planning | Agent: epic-planner

**Hierarchical Compliance Fix**: Linked to Epic #5367 (Invariant System Correctness) — this issue is part of the invariant system correctness work. --- **Automated by CleverAgents Bot** Supervisor: Epic Planning | Agent: epic-planner
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.

Reference
cleveragents/cleveragents-core#5359
No description provided.