UAT: agents invariant list --effective JSON output missing conflicts_resolved field — spec requires conflict resolution details in effective set output #2531

Open
opened 2026-04-03 18:49:03 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/invariant-effective-conflicts-resolved
  • Commit Message: fix(invariant): include conflicts_resolved in agents invariant list --effective JSON output
  • Milestone: v3.4.0
  • Parent Epic: #394

Background and Context

The specification defines the JSON output for agents invariant list --effective as:

{
  "command": "invariant list",
  "status": "ok",
  "exit_code": 0,
  "data": {
    "scope": "plan",
    "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
    "effective": true,
    "invariants": [
      { "id": "inv_01HXM9A1B", "source": "global", "text": "All public APIs must maintain backward compatibility" },
      { "id": "inv_01HXM9A2C", "source": "project", "text": "All endpoints must validate auth tokens" },
      { "id": "inv_01HXM9G3A", "source": "plan", "text": "All database queries must use parameterized statements" }
    ],
    "conflicts_resolved": [
      {
        "overridden": { "source": "global", "text": "Use shared DB pool" },
        "by": { "source": "plan", "text": "All database queries must use parameterized statements" }
      }
    ]
  },
  "messages": ["3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)"]
}

The current implementation returns a flat list of invariants with no conflict resolution information.

Steps to Reproduce

from typer.testing import CliRunner
from cleveragents.cli.commands import invariant as inv_module
from cleveragents.cli.commands.invariant import app

inv_module._service = None
runner = CliRunner()

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

svc = InvariantService()
svc.add_invariant('Never delete prod data', InvariantScope.GLOBAL, 'system')
svc.add_invariant('Never delete prod data', InvariantScope.PLAN, 'plan-123')  # conflict!
inv_module._service = svc

result = runner.invoke(app, ['list', '--effective', '--plan', 'plan-123', '--format', 'json'])
print(result.output)
# Output: [{"id": "...", "text": "Never delete prod data", "scope": "plan", ...}]
# Missing: conflicts_resolved field!

Expected Behavior (per spec)

The --effective output should include:

  1. A conflicts_resolved array showing which invariants were overridden and by which higher-precedence invariants
  2. Each invariant in the list should use "source" (not "scope") to indicate the scope level
  3. A summary message like "3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)"

Actual Behavior

The current output is a flat JSON array of invariant objects with fields id, text, scope, source_name, active, created_at. There is:

  • No conflicts_resolved field
  • No summary message
  • Uses scope instead of source for the scope level (minor naming inconsistency with spec)

Code Location

  • src/cleveragents/cli/commands/invariant.pylist_invariants() command
  • src/cleveragents/application/services/invariant_service.pylist_invariants() with effective=True returns a plain list, not a result with conflict info

Root Cause

InvariantService.list_invariants(effective=True) calls get_effective_invariants() which returns a list[Invariant] with no conflict tracking. The InvariantReconciliationActor correctly tracks conflicts via ReconciliationResult.conflicts, but this information is not surfaced through the list_invariants API or the CLI.

Impact

  • Users cannot see which invariants were overridden during conflict resolution
  • The CLI output does not match the spec's documented format
  • Debugging invariant conflicts requires manual inspection

Subtasks

  • Add a list_effective_with_conflicts() method (or extend list_invariants) to return conflict information alongside the effective set
  • Update agents invariant list --effective to include conflicts_resolved in JSON output
  • Update the summary message to include conflict count
  • Add unit tests for conflict reporting in effective set output

Definition of Done

  • agents invariant list --effective --format json includes conflicts_resolved array
  • Each entry in conflicts_resolved has overridden and by fields with source and text
  • Summary message includes conflict count
  • All tests pass

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

## Metadata - **Branch**: `fix/invariant-effective-conflicts-resolved` - **Commit Message**: `fix(invariant): include conflicts_resolved in agents invariant list --effective JSON output` - **Milestone**: v3.4.0 - **Parent Epic**: #394 ## Background and Context The specification defines the JSON output for `agents invariant list --effective` as: ```json { "command": "invariant list", "status": "ok", "exit_code": 0, "data": { "scope": "plan", "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J", "effective": true, "invariants": [ { "id": "inv_01HXM9A1B", "source": "global", "text": "All public APIs must maintain backward compatibility" }, { "id": "inv_01HXM9A2C", "source": "project", "text": "All endpoints must validate auth tokens" }, { "id": "inv_01HXM9G3A", "source": "plan", "text": "All database queries must use parameterized statements" } ], "conflicts_resolved": [ { "overridden": { "source": "global", "text": "Use shared DB pool" }, "by": { "source": "plan", "text": "All database queries must use parameterized statements" } } ] }, "messages": ["3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)"] } ``` The current implementation returns a flat list of invariants with no conflict resolution information. ## Steps to Reproduce ```python from typer.testing import CliRunner from cleveragents.cli.commands import invariant as inv_module from cleveragents.cli.commands.invariant import app inv_module._service = None runner = CliRunner() from cleveragents.application.services.invariant_service import InvariantService from cleveragents.domain.models.core.invariant import InvariantScope svc = InvariantService() svc.add_invariant('Never delete prod data', InvariantScope.GLOBAL, 'system') svc.add_invariant('Never delete prod data', InvariantScope.PLAN, 'plan-123') # conflict! inv_module._service = svc result = runner.invoke(app, ['list', '--effective', '--plan', 'plan-123', '--format', 'json']) print(result.output) # Output: [{"id": "...", "text": "Never delete prod data", "scope": "plan", ...}] # Missing: conflicts_resolved field! ``` ## Expected Behavior (per spec) The `--effective` output should include: 1. A `conflicts_resolved` array showing which invariants were overridden and by which higher-precedence invariants 2. Each invariant in the list should use `"source"` (not `"scope"`) to indicate the scope level 3. A summary message like "3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)" ## Actual Behavior The current output is a flat JSON array of invariant objects with fields `id`, `text`, `scope`, `source_name`, `active`, `created_at`. There is: - No `conflicts_resolved` field - No summary message - Uses `scope` instead of `source` for the scope level (minor naming inconsistency with spec) ## Code Location - `src/cleveragents/cli/commands/invariant.py` — `list_invariants()` command - `src/cleveragents/application/services/invariant_service.py` — `list_invariants()` with `effective=True` returns a plain list, not a result with conflict info ## Root Cause `InvariantService.list_invariants(effective=True)` calls `get_effective_invariants()` which returns a `list[Invariant]` with no conflict tracking. The `InvariantReconciliationActor` correctly tracks conflicts via `ReconciliationResult.conflicts`, but this information is not surfaced through the `list_invariants` API or the CLI. ## Impact - Users cannot see which invariants were overridden during conflict resolution - The CLI output does not match the spec's documented format - Debugging invariant conflicts requires manual inspection ## Subtasks - [ ] Add a `list_effective_with_conflicts()` method (or extend `list_invariants`) to return conflict information alongside the effective set - [ ] Update `agents invariant list --effective` to include `conflicts_resolved` in JSON output - [ ] Update the summary message to include conflict count - [ ] Add unit tests for conflict reporting in effective set output ## Definition of Done - `agents invariant list --effective --format json` includes `conflicts_resolved` array - Each entry in `conflicts_resolved` has `overridden` and `by` fields with `source` and `text` - Summary message includes conflict count - All tests pass --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: Should Have — Spec compliance or quality improvement.

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

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: Should Have — Spec compliance or quality improvement. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo added this to the v3.3.0 milestone 2026-04-05 05:07:04 +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.

Dependencies

No dependencies set.

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