BUG-HUNT: [data-loss] invariant commands use in-memory service — all data lost between CLI invocations #7752

Open
opened 2026-04-12 03:24:43 +00:00 by HAL9000 · 3 comments
Owner

Bug Report: [Data Loss] invariant Commands Use In-Memory Service — All Invariants Lost on CLI Exit

Severity Assessment

  • Impact: Any invariant added via agents invariant add is only stored in a module-level Python object. When the CLI process exits, all data is lost. Users cannot persist invariant constraints across sessions.
  • Likelihood: Triggered on every agents invariant add/list/remove invocation
  • Priority: High

Location

  • File: src/cleveragents/cli/commands/invariant.py
  • Function: _get_service
  • Lines: 59–67

Description

The invariant command module maintains a module-level _service: InvariantService | None = None variable. The _get_service() function instantiates a plain InvariantService() (no database backing) and caches it in the module global. Each time the CLI is invoked as a new process, _service is None and a fresh in-memory service is created with zero invariants.

This is in stark contrast to every other command module (actor, skill, tool, session, etc.) which all route through get_container() to get a database-backed service.

Evidence

# invariant.py lines 59-67
_service: InvariantService | None = None

def _get_service() -> InvariantService:
    """Return (or lazily create) the module-level InvariantService."""
    global _service
    if _service is None:
        _service = InvariantService()   # BUG: plain in-memory, no DB
    return _service

Compare with the correct pattern from actor.py:

def _get_services():
    container = get_container()          # uses DI container
    actor_service = container.actor_service()
    ...

Or skill.py:

def _get_skill_service() -> SkillService:
    return get_container().skill_service()  # DI container

Expected Behavior

agents invariant add --global "Never delete production data"
agents invariant list
# Should show: Never delete production data

Actual Behavior

agents invariant add --global "Never delete production data"
# Invariant added: INV_xxx
agents invariant list
# (empty — module global was reset in the new process)

Suggested Fix

Replace the module-level in-memory service with a DI container lookup:

def _get_service() -> InvariantService:
    from cleveragents.application.container import get_container
    return get_container().invariant_service()

This requires invariant_service to be registered in the container (if not already). If InvariantService requires database backing, the container should wire it to a InvariantRepository backed by the SQLite DB, matching the pattern used by all other CLI-accessible services.

Category

data-loss

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: bug-hunter

## Bug Report: [Data Loss] `invariant` Commands Use In-Memory Service — All Invariants Lost on CLI Exit ### Severity Assessment - **Impact**: Any invariant added via `agents invariant add` is only stored in a module-level Python object. When the CLI process exits, all data is lost. Users cannot persist invariant constraints across sessions. - **Likelihood**: Triggered on every `agents invariant add/list/remove` invocation - **Priority**: High ### Location - **File**: `src/cleveragents/cli/commands/invariant.py` - **Function**: `_get_service` - **Lines**: 59–67 ### Description The `invariant` command module maintains a **module-level** `_service: InvariantService | None = None` variable. The `_get_service()` function instantiates a plain `InvariantService()` (no database backing) and caches it in the module global. Each time the CLI is invoked as a new process, `_service` is `None` and a fresh in-memory service is created with zero invariants. This is in stark contrast to every other command module (actor, skill, tool, session, etc.) which all route through `get_container()` to get a database-backed service. ### Evidence ```python # invariant.py lines 59-67 _service: InvariantService | None = None def _get_service() -> InvariantService: """Return (or lazily create) the module-level InvariantService.""" global _service if _service is None: _service = InvariantService() # BUG: plain in-memory, no DB return _service ``` Compare with the correct pattern from `actor.py`: ```python def _get_services(): container = get_container() # uses DI container actor_service = container.actor_service() ... ``` Or `skill.py`: ```python def _get_skill_service() -> SkillService: return get_container().skill_service() # DI container ``` ### Expected Behavior ```bash agents invariant add --global "Never delete production data" agents invariant list # Should show: Never delete production data ``` ### Actual Behavior ```bash agents invariant add --global "Never delete production data" # Invariant added: INV_xxx agents invariant list # (empty — module global was reset in the new process) ``` ### Suggested Fix Replace the module-level in-memory service with a DI container lookup: ```python def _get_service() -> InvariantService: from cleveragents.application.container import get_container return get_container().invariant_service() ``` This requires `invariant_service` to be registered in the container (if not already). If `InvariantService` requires database backing, the container should wire it to a `InvariantRepository` backed by the SQLite DB, matching the pattern used by all other CLI-accessible services. ### Category data-loss ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-12 03:41:07 +00:00
Author
Owner

Verified — Critical data loss bug: invariant commands use in-memory storage — all data lost between CLI invocations. MoSCoW: Must-have. Priority: Critical — this is a fundamental v3.2.0 deliverable failure.


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

✅ **Verified** — Critical data loss bug: invariant commands use in-memory storage — all data lost between CLI invocations. MoSCoW: Must-have. Priority: Critical — this is a fundamental v3.2.0 deliverable failure. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Critical data loss bug: invariant commands use in-memory storage — all data lost between CLI invocations. MoSCoW: Must-have. Priority: Critical — this is a fundamental v3.2.0 deliverable failure.


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

✅ **Verified** — Critical data loss bug: invariant commands use in-memory storage — all data lost between CLI invocations. MoSCoW: Must-have. Priority: Critical — this is a fundamental v3.2.0 deliverable failure. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — Critical data loss bug: invariant commands use in-memory storage — all data lost between CLI invocations. MoSCoW: Must-have. Priority: Critical — this is a fundamental v3.2.0 deliverable failure.


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

✅ **Verified** — Critical data loss bug: invariant commands use in-memory storage — all data lost between CLI invocations. MoSCoW: Must-have. Priority: Critical — this is a fundamental v3.2.0 deliverable failure. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
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#7752
No description provided.