UAT: agents invariant CLI creates bare InvariantService() bypassing DI container — invariants lost across CLI invocations (regression of #1022) #3566

Open
opened 2026-04-05 19:48:38 +00:00 by freemo · 2 comments
Owner

Metadata

  • Branch: fix/invariant-cli-di-container-regression
  • Commit Message: fix(cli): wire InvariantService to DI container and persistence layer
  • Milestone: None (Backlog)
  • Parent Epic: #374

Background

Issue #1022 ("InvariantService uses in-memory storage only — invariants lost between CLI invocations") was closed as fixed, but the CLI _get_service() function in src/cleveragents/cli/commands/invariant.py still creates a bare InvariantService() without using the DI container:

# Module-level service instance (in-memory, same lifetime as CLI process)
_service: InvariantService | None = None

def _get_service() -> InvariantService:
    """Return (or lazily create) the module-level InvariantService."""
    global _service
    if _service is None:
        _service = InvariantService()  # ← bare constructor, no DI container
    return _service

Additionally, the DI container in src/cleveragents/application/container.py registers InvariantService as a Singleton without a UnitOfWork or database URL:

# Invariant Service - Singleton (in-memory invariant management)
invariant_service = providers.Singleton(
    InvariantService,
)

This means:

  1. The CLI creates its own in-memory InvariantService instance, separate from the container's singleton
  2. Even if the CLI used the container's singleton, the container's InvariantService has no persistence layer
  3. Invariants added via agents invariant add are lost when the CLI process exits

Code locations:

  • src/cleveragents/cli/commands/invariant.py lines 56–65 (_get_service())
  • src/cleveragents/application/container.py lines 624–626 (container registration without UoW)

Steps to Reproduce

agents invariant add --project myapp "All APIs must validate auth tokens"
# Output: Invariant added: 01HXYZ...
agents invariant list --project myapp
# Output: No invariants found.

Expected Behavior (from spec and issue #1022 acceptance criteria)

  • agents invariant add --project X "text" persists the invariant to the SQLite database
  • agents invariant list --project X in a subsequent CLI invocation returns the persisted invariant
  • agents invariant remove <ID> soft-deletes the invariant in the database
  • The CLI _get_service() resolves InvariantService from the DI container (not bare constructor)

Actual Behavior

  1. agents invariant add --project X "text" succeeds and prints an invariant ID
  2. agents invariant list --project X immediately after in a new CLI invocation returns "No invariants found."
  3. The invariant is stored in the process-local dict and garbage-collected on exit

Root Cause

The fix for #1022 was supposed to:

  1. Wire InvariantService to a database repository
  2. Update CLI _get_service() to use the DI container
  3. Pass UnitOfWork to InvariantService

None of these changes appear to be present in the current codebase. The InvariantService.__init__ signature only accepts event_bus: EventBus | None = None — there is no unit_of_work parameter.

Subtasks

  • Add unit_of_work parameter to InvariantService.__init__
  • Implement InvariantRepository with add/list/get/soft-delete
  • Add InvariantModel to models.py (or verify it exists)
  • Create Alembic migration for invariants table (or verify it exists)
  • Update container to pass unit_of_work to InvariantService
  • Update CLI _get_service() to resolve from DI container
  • Run nox (all default sessions), fix any errors

Definition of Done

  • agents invariant add persists across CLI invocations
  • agents invariant list retrieves from database
  • agents invariant remove soft-deletes in database
  • CLI _get_service() uses DI container
  • All nox stages pass
  • Coverage >= 97%

Backlog note: This issue was discovered during autonomous operation
on milestone v3.2.0. It does not block milestone completion and has been
placed in the backlog for human review and future milestone assignment.


Automated by CleverAgents Bot
Supervisor: Acting on behalf of: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/invariant-cli-di-container-regression` - **Commit Message**: `fix(cli): wire InvariantService to DI container and persistence layer` - **Milestone**: None (Backlog) - **Parent Epic**: #374 ## Background Issue #1022 ("InvariantService uses in-memory storage only — invariants lost between CLI invocations") was closed as fixed, but the CLI `_get_service()` function in `src/cleveragents/cli/commands/invariant.py` still creates a bare `InvariantService()` without using the DI container: ```python # Module-level service instance (in-memory, same lifetime as CLI process) _service: InvariantService | None = None def _get_service() -> InvariantService: """Return (or lazily create) the module-level InvariantService.""" global _service if _service is None: _service = InvariantService() # ← bare constructor, no DI container return _service ``` Additionally, the DI container in `src/cleveragents/application/container.py` registers `InvariantService` as a Singleton **without** a `UnitOfWork` or database URL: ```python # Invariant Service - Singleton (in-memory invariant management) invariant_service = providers.Singleton( InvariantService, ) ``` This means: 1. The CLI creates its own in-memory `InvariantService` instance, separate from the container's singleton 2. Even if the CLI used the container's singleton, the container's `InvariantService` has no persistence layer 3. Invariants added via `agents invariant add` are lost when the CLI process exits **Code locations**: - `src/cleveragents/cli/commands/invariant.py` lines 56–65 (`_get_service()`) - `src/cleveragents/application/container.py` lines 624–626 (container registration without UoW) ## Steps to Reproduce ```bash agents invariant add --project myapp "All APIs must validate auth tokens" # Output: Invariant added: 01HXYZ... agents invariant list --project myapp # Output: No invariants found. ``` ## Expected Behavior (from spec and issue #1022 acceptance criteria) - `agents invariant add --project X "text"` persists the invariant to the SQLite database - `agents invariant list --project X` in a subsequent CLI invocation returns the persisted invariant - `agents invariant remove <ID>` soft-deletes the invariant in the database - The CLI `_get_service()` resolves `InvariantService` from the DI container (not bare constructor) ## Actual Behavior 1. `agents invariant add --project X "text"` succeeds and prints an invariant ID 2. `agents invariant list --project X` immediately after in a new CLI invocation returns "No invariants found." 3. The invariant is stored in the process-local dict and garbage-collected on exit ## Root Cause The fix for #1022 was supposed to: 1. Wire `InvariantService` to a database repository 2. Update CLI `_get_service()` to use the DI container 3. Pass `UnitOfWork` to `InvariantService` None of these changes appear to be present in the current codebase. The `InvariantService.__init__` signature only accepts `event_bus: EventBus | None = None` — there is no `unit_of_work` parameter. ## Subtasks - [ ] Add `unit_of_work` parameter to `InvariantService.__init__` - [ ] Implement `InvariantRepository` with add/list/get/soft-delete - [ ] Add `InvariantModel` to `models.py` (or verify it exists) - [ ] Create Alembic migration for `invariants` table (or verify it exists) - [ ] Update container to pass `unit_of_work` to `InvariantService` - [ ] Update CLI `_get_service()` to resolve from DI container - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done - [ ] `agents invariant add` persists across CLI invocations - [ ] `agents invariant list` retrieves from database - [ ] `agents invariant remove` soft-deletes in database - [ ] CLI `_get_service()` uses DI container - [ ] All `nox` stages pass - [ ] Coverage >= 97% > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.2.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. --- **Automated by CleverAgents Bot** Supervisor: Acting on behalf of: UAT Testing | Agent: ca-new-issue-creator
Author
Owner

Issue verified and triaged:

  • Priority: Critical — the CLI creates a bare InvariantService() bypassing the DI container, causing invariants to be lost across CLI invocations. This is closely related to #3539 (InvariantService in-memory storage).
  • Milestone: Needs assignment — recommend v3.2.0 (M3: Decisions + Validations + Invariants) as invariant persistence is a core acceptance criterion.
  • Story Points: 5 (L) — requires InvariantRepository, InvariantModel, DI wiring, and CLI _get_service() refactor.
  • Parent Epic: #374 (already linked)
  • Note: This issue overlaps significantly with #3539. Both address the same root cause (InvariantService lacks persistence). Consider consolidating or implementing together.
  • Next step: This issue is now ready for implementation.

Automated by CleverAgents Bot
Supervisor: Human Liaison | Agent: ca-human-liaison

Issue verified and triaged: - **Priority**: Critical — the CLI creates a bare InvariantService() bypassing the DI container, causing invariants to be lost across CLI invocations. This is closely related to #3539 (InvariantService in-memory storage). - **Milestone**: Needs assignment — recommend v3.2.0 (M3: Decisions + Validations + Invariants) as invariant persistence is a core acceptance criterion. - **Story Points**: 5 (L) — requires InvariantRepository, InvariantModel, DI wiring, and CLI _get_service() refactor. - **Parent Epic**: #374 (already linked) - **Note**: This issue overlaps significantly with #3539. Both address the same root cause (InvariantService lacks persistence). Consider consolidating or implementing together. - **Next step**: This issue is now ready for implementation. --- **Automated by CleverAgents Bot** Supervisor: Human Liaison | Agent: ca-human-liaison
freemo added this to the v3.3.0 milestone 2026-04-05 20:08:14 +00:00
Author
Owner

MoSCoW classification: Must Have

Rationale: This is a regression of #1022 — the InvariantService CLI still creates a bare InvariantService() bypassing the DI container, causing invariants to be lost between CLI invocations. Data persistence is a fundamental requirement per the spec. The invariant system cannot function correctly if invariants don't survive between CLI calls. This directly blocks the invariant management workflow (add → list → use in plan) and is classified as Priority/Critical.

Milestone assigned: v3.3.0 (Corrections + Subplans + Checkpoints — invariant management is a core requirement).


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

MoSCoW classification: **Must Have** Rationale: This is a regression of #1022 — the InvariantService CLI still creates a bare `InvariantService()` bypassing the DI container, causing invariants to be lost between CLI invocations. Data persistence is a fundamental requirement per the spec. The invariant system cannot function correctly if invariants don't survive between CLI calls. This directly blocks the invariant management workflow (add → list → use in plan) and is classified as Priority/Critical. Milestone assigned: **v3.3.0** (Corrections + Subplans + Checkpoints — invariant management is a core requirement). --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo removed this from the v3.3.0 milestone 2026-04-06 23:38:30 +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.

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