invariant list --project returns empty after successful invariant add --project #4173

Open
opened 2026-04-06 13:55:48 +00:00 by hurui200320 · 3 comments
Member

Metadata

  • Commit Message: fix(invariant): persist invariants so list retrieves what add stores
  • Branch: fix/invariant-list-persistence

Description

Background and Context

The invariant CLI namespace provides add and list subcommands for managing natural-language constraints scoped to projects, actions, or plans. During a smoke test of the full project lifecycle, we discovered that invariants created via invariant add --project cannot be retrieved via invariant list --project — the round-trip is broken.

How to Reproduce

# 1. Start from a clean environment
agents init --yes

# 2. Create a resource and project
agents resource add git-checkout local/test-repo --path /tmp/test-repo --branch main
agents project create -d "Test project" --resource local/test-repo local/test-project

# 3. Add an invariant scoped to the project
agents invariant add --project local/test-project "All source code must be written in Kotlin"
# Output (exit 0):
#   Invariant added: 01KNHGYCDBEZKBZ66VF287XV8R
#     Text:   All source code must be written in Kotlin
#     Scope:  project
#     Source: local/test-project

# 4. Immediately list invariants for the same project
agents invariant list --project local/test-project
# Output (exit 0):
#   No invariants found.

Tested with 3 separate invariant add calls — all returned unique ULIDs and exit 0, but invariant list returned "No invariants found" after all three.

Current Behavior

  • invariant add --project <PROJECT> "<TEXT>" returns exit 0 with a ULID, text echo, scope, and source — appearing to succeed.
  • invariant list --project <PROJECT> immediately after returns "No invariants found." (exit 0).
  • The data written by add is not retrievable by list. Either the write is cosmetic-only (no actual persistence), or list queries a different store/table/scope than add writes to.

Expected Behavior (per spec)

Per the specification, invariant add should persist the invariant to storage, and invariant list --project <PROJECT> should return all invariants scoped to that project, showing each invariant's ID, text, scope, and overridable status.

The invariants should then be enforceable during plan use and the Strategize phase — if they aren't persisted, the entire invariant contract is broken.

Acceptance Criteria

  • invariant add --project <PROJECT> "<TEXT>" persists the invariant to the database
  • invariant list --project <PROJECT> returns all invariants previously added to that project
  • The listed invariants include: ID (ULID), text, scope, and overridable flag (per spec)
  • Round-trip is confirmed: add N invariants → list returns exactly N invariants with correct data
  • invariant list without --project returns global invariants (if any exist)

Subtasks

  • Investigate where invariant add writes data (which table/store)
  • Investigate where invariant list reads data from — identify the mismatch
  • Fix the persistence or query so list retrieves what add stores
  • Add/update invariant list output to show ID, text, scope, overridable per spec
  • Tests (Behave): Add scenario for invariant add → list round-trip
  • Tests (Robot): Add integration test for invariant lifecycle
  • Verify coverage >=97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
## Metadata - **Commit Message**: `fix(invariant): persist invariants so list retrieves what add stores` - **Branch**: `fix/invariant-list-persistence` ## Description ### Background and Context The `invariant` CLI namespace provides `add` and `list` subcommands for managing natural-language constraints scoped to projects, actions, or plans. During a smoke test of the full project lifecycle, we discovered that invariants created via `invariant add --project` cannot be retrieved via `invariant list --project` — the round-trip is broken. ### How to Reproduce ```bash # 1. Start from a clean environment agents init --yes # 2. Create a resource and project agents resource add git-checkout local/test-repo --path /tmp/test-repo --branch main agents project create -d "Test project" --resource local/test-repo local/test-project # 3. Add an invariant scoped to the project agents invariant add --project local/test-project "All source code must be written in Kotlin" # Output (exit 0): # Invariant added: 01KNHGYCDBEZKBZ66VF287XV8R # Text: All source code must be written in Kotlin # Scope: project # Source: local/test-project # 4. Immediately list invariants for the same project agents invariant list --project local/test-project # Output (exit 0): # No invariants found. ``` Tested with 3 separate `invariant add` calls — all returned unique ULIDs and exit 0, but `invariant list` returned "No invariants found" after all three. ### Current Behavior - `invariant add --project <PROJECT> "<TEXT>"` returns exit 0 with a ULID, text echo, scope, and source — appearing to succeed. - `invariant list --project <PROJECT>` immediately after returns "No invariants found." (exit 0). - The data written by `add` is not retrievable by `list`. Either the write is cosmetic-only (no actual persistence), or `list` queries a different store/table/scope than `add` writes to. ### Expected Behavior (per spec) Per the specification, `invariant add` should persist the invariant to storage, and `invariant list --project <PROJECT>` should return all invariants scoped to that project, showing each invariant's ID, text, scope, and overridable status. The invariants should then be enforceable during `plan use` and the Strategize phase — if they aren't persisted, the entire invariant contract is broken. ## Acceptance Criteria - [ ] `invariant add --project <PROJECT> "<TEXT>"` persists the invariant to the database - [ ] `invariant list --project <PROJECT>` returns all invariants previously added to that project - [ ] The listed invariants include: ID (ULID), text, scope, and overridable flag (per spec) - [ ] Round-trip is confirmed: add N invariants → list returns exactly N invariants with correct data - [ ] `invariant list` without `--project` returns global invariants (if any exist) ## Subtasks - [ ] Investigate where `invariant add` writes data (which table/store) - [ ] Investigate where `invariant list` reads data from — identify the mismatch - [ ] Fix the persistence or query so `list` retrieves what `add` stores - [ ] Add/update `invariant list` output to show ID, text, scope, overridable per spec - [ ] Tests (Behave): Add scenario for invariant add → list round-trip - [ ] Tests (Robot): Add integration test for invariant lifecycle - [ ] Verify coverage >=97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done.
Owner

Thank you for filing this issue, @hurui200320. This is a clear and well-documented bug — the invariant add/list round-trip failure is a significant functional regression that breaks the invariant contract.

Triage assessment:

Completeness check per CONTRIBUTING.md:

  • Clear title
  • Background/context with spec reference
  • Detailed reproduction steps with shell commands and output
  • Current vs expected behavior
  • Acceptance criteria
  • Subtasks checklist
  • Definition of Done
  • Metadata (commit message, branch name)

Priority assessment: The project-owner has already assigned Priority/High, which is appropriate. This is a data persistence bug that breaks the entire invariant subsystem — invariants that appear to be created are silently lost, making the invariant enforcement contract non-functional.

Story Points: S (2 points) — The fix likely involves identifying a mismatch between the write path (in invariant add) and the read path (in invariant list). Once the mismatch is identified, the fix should be straightforward — either the write needs to persist to the correct store, or the read needs to query the correct store.

Labels: Already triaged by project-owner with State/Verified, Priority/High, Type/Bug, MoSCoW/Should Have, Points/3.

Parent Epic: This should be linked to an invariant-related epic. The invariant subsystem is part of the Plan Lifecycle and Safety Profile features.

Next step: This issue is ready for implementation. The investigation subtasks (where add writes vs where list reads) should be done first to identify the root cause before coding the fix.


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

Thank you for filing this issue, @hurui200320. This is a clear and well-documented bug — the invariant add/list round-trip failure is a significant functional regression that breaks the invariant contract. **Triage assessment:** **Completeness check per CONTRIBUTING.md:** - ✅ Clear title - ✅ Background/context with spec reference - ✅ Detailed reproduction steps with shell commands and output - ✅ Current vs expected behavior - ✅ Acceptance criteria - ✅ Subtasks checklist - ✅ Definition of Done - ✅ Metadata (commit message, branch name) **Priority assessment**: The project-owner has already assigned `Priority/High`, which is appropriate. This is a data persistence bug that breaks the entire invariant subsystem — invariants that appear to be created are silently lost, making the invariant enforcement contract non-functional. **Story Points**: S (2 points) — The fix likely involves identifying a mismatch between the write path (in `invariant add`) and the read path (in `invariant list`). Once the mismatch is identified, the fix should be straightforward — either the write needs to persist to the correct store, or the read needs to query the correct store. **Labels**: Already triaged by project-owner with `State/Verified`, `Priority/High`, `Type/Bug`, `MoSCoW/Should Have`, `Points/3`. **Parent Epic**: This should be linked to an invariant-related epic. The invariant subsystem is part of the Plan Lifecycle and Safety Profile features. **Next step**: This issue is ready for implementation. The investigation subtasks (where `add` writes vs where `list` reads) should be done first to identify the root cause before coding the fix. --- **Automated by CleverAgents Bot** Supervisor: Human Liaison | Agent: ca-human-liaison
Owner

TRIAGE: v3.1.0 Models & Schema - High Priority

This issue affects the invariant system which is core to plan constraints and governance. Assigned to v3.1.0 as it's needed for proper plan lifecycle functionality but not as blocking as the SQLite crash.

Rationale:

  • Breaks invariant round-trip (add → list)
  • Affects plan governance and constraints
  • Currently labeled Priority/High, MoSCoW/Should Have (appropriate)
  • Needed for milestone completion but plan lifecycle can function without invariants

Dependencies: Should be fixed after #4174 (SQLite crash) is resolved.

**TRIAGE: v3.1.0 Models & Schema - High Priority** This issue affects the invariant system which is core to plan constraints and governance. Assigned to v3.1.0 as it's needed for proper plan lifecycle functionality but not as blocking as the SQLite crash. **Rationale:** - Breaks invariant round-trip (add → list) - Affects plan governance and constraints - Currently labeled Priority/High, MoSCoW/Should Have (appropriate) - Needed for milestone completion but plan lifecycle can function without invariants **Dependencies:** Should be fixed after #4174 (SQLite crash) is resolved.
freemo added this to the v3.4.0 milestone 2026-04-06 17:48:58 +00:00
freemo removed this from the v3.4.0 milestone 2026-04-06 23:30:02 +00:00
HAL9000 self-assigned this 2026-04-08 18:49:13 +00:00
HAL9000 added this to the v3.7.0 milestone 2026-04-08 18:49:13 +00:00
Owner

Issue assigned to @HAL9000 and milestone set to v3.7.0.

Milestone Rationale: Invariant management is part of the v3.7.0 milestone scope. This persistence bug prevents invariants from being retrieved after creation, which is a core functionality issue for the invariant subsystem.

Assignment Rationale: Default assignment to HAL9000 to maintain velocity.


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

Issue assigned to @HAL9000 and milestone set to **v3.7.0**. **Milestone Rationale**: Invariant management is part of the v3.7.0 milestone scope. This persistence bug prevents invariants from being retrieved after creation, which is a core functionality issue for the invariant subsystem. **Assignment Rationale**: Default assignment to HAL9000 to maintain velocity. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
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#4173
No description provided.