UAT: bug(resource-registry): NamespacedProject domain model missing invariants field, stored via raw SQL workaround #2941

Open
opened 2026-04-05 02:53:07 +00:00 by freemo · 5 comments
Owner

Metadata

  • Commit Message: fix(resource-registry): add invariants field to NamespacedProject domain model
  • Branch: bugfix/namespaced-project-invariants-field
  • Parent Epic: #353
  • Milestone: v3.1.0

Background and Context

The spec defines invariants as a first-class part of the project data model:

Invariant: A natural-language constraint on plan execution scoped to global, project, action, or plan level. Action invariants are promoted to plan-level when the action is used, so the runtime precedence chain is three-tier: plan > project > global.

Projects are expected to store and expose their invariants as part of the domain model, enabling the Invariant Reconciliation Actor to read them at Strategize time.

Current Behavior

The NamespacedProject domain model in src/cleveragents/domain/models/core/project.py has no invariants field. The DB model (NamespacedProjectModel) stores invariants as invariants_json (a JSON text column), but the domain model never exposes them.

When invariants are set via agents project create --invariant "...", they are persisted via a raw SQL workaround in _store_project_extras() in cli/commands/project.py:

def _store_project_extras(
    namespaced_name: str,
    invariant_texts: list[str] | None = None,
    inv_actor: str | None = None,
) -> None:
    """Persist invariant list and invariant_actor directly via SQL session.

    These fields live on the ``ns_projects`` table but are not exposed on
    the ``NamespacedProject`` Pydantic domain model (they're JSON columns),
    so we update them via a lightweight session outside the repository API.
    """

This means:

  1. Invariants set on a project are never returned when the project is fetched via repo.get()
  2. agents project show does not display project invariants
  3. The Invariant Reconciliation Actor cannot read project invariants from the domain model
  4. NamespacedProjectModel.to_domain() does not populate invariants

Expected Behavior

NamespacedProject should have an invariants field (list of Invariant or list of strings), populated from invariants_json when loading from the DB. The to_domain() method in NamespacedProjectModel should deserialize invariants_json into the domain model's invariants field. The _store_project_extras() raw SQL workaround should be replaced with proper domain model support.

Acceptance Criteria

  • NamespacedProject has an invariants: list[str] (or list[Invariant]) field
  • NamespacedProjectModel.to_domain() populates invariants from invariants_json
  • NamespacedProjectModel.from_domain() serializes invariants to invariants_json
  • agents project show displays project invariants
  • agents project create --invariant "..." stores invariants via the domain model (not raw SQL)
  • The Invariant Reconciliation Actor can read project invariants from the domain model
  • Unit tests cover invariant round-trip (create → persist → fetch → display)

Subtasks

  • Add invariants: list[str] field to NamespacedProject domain model
  • Update NamespacedProjectModel.to_domain() to deserialize invariants_json
  • Update NamespacedProjectModel.from_domain() to serialize invariants
  • Remove _store_project_extras() raw SQL workaround from cli/commands/project.py
  • Update agents project create to use the domain model for invariants
  • Update agents project show to display invariants
  • Add unit tests for invariant persistence and retrieval
  • Run nox and ensure all sessions pass

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.
  • 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.

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

## Metadata - **Commit Message**: `fix(resource-registry): add invariants field to NamespacedProject domain model` - **Branch**: `bugfix/namespaced-project-invariants-field` - **Parent Epic**: #353 - **Milestone**: v3.1.0 ## Background and Context The spec defines invariants as a first-class part of the project data model: > **Invariant**: A natural-language constraint on plan execution scoped to global, project, action, or plan level. Action invariants are promoted to plan-level when the action is used, so the runtime precedence chain is three-tier: plan > project > global. Projects are expected to store and expose their invariants as part of the domain model, enabling the Invariant Reconciliation Actor to read them at Strategize time. ## Current Behavior The `NamespacedProject` domain model in `src/cleveragents/domain/models/core/project.py` has **no `invariants` field**. The DB model (`NamespacedProjectModel`) stores invariants as `invariants_json` (a JSON text column), but the domain model never exposes them. When invariants are set via `agents project create --invariant "..."`, they are persisted via a raw SQL workaround in `_store_project_extras()` in `cli/commands/project.py`: ```python def _store_project_extras( namespaced_name: str, invariant_texts: list[str] | None = None, inv_actor: str | None = None, ) -> None: """Persist invariant list and invariant_actor directly via SQL session. These fields live on the ``ns_projects`` table but are not exposed on the ``NamespacedProject`` Pydantic domain model (they're JSON columns), so we update them via a lightweight session outside the repository API. """ ``` This means: 1. Invariants set on a project are never returned when the project is fetched via `repo.get()` 2. `agents project show` does not display project invariants 3. The Invariant Reconciliation Actor cannot read project invariants from the domain model 4. `NamespacedProjectModel.to_domain()` does not populate invariants ## Expected Behavior `NamespacedProject` should have an `invariants` field (list of `Invariant` or list of strings), populated from `invariants_json` when loading from the DB. The `to_domain()` method in `NamespacedProjectModel` should deserialize `invariants_json` into the domain model's `invariants` field. The `_store_project_extras()` raw SQL workaround should be replaced with proper domain model support. ## Acceptance Criteria - [ ] `NamespacedProject` has an `invariants: list[str]` (or `list[Invariant]`) field - [ ] `NamespacedProjectModel.to_domain()` populates `invariants` from `invariants_json` - [ ] `NamespacedProjectModel.from_domain()` serializes `invariants` to `invariants_json` - [ ] `agents project show` displays project invariants - [ ] `agents project create --invariant "..."` stores invariants via the domain model (not raw SQL) - [ ] The Invariant Reconciliation Actor can read project invariants from the domain model - [ ] Unit tests cover invariant round-trip (create → persist → fetch → display) ## Subtasks - [ ] Add `invariants: list[str]` field to `NamespacedProject` domain model - [ ] Update `NamespacedProjectModel.to_domain()` to deserialize `invariants_json` - [ ] Update `NamespacedProjectModel.from_domain()` to serialize `invariants` - [ ] Remove `_store_project_extras()` raw SQL workaround from `cli/commands/project.py` - [ ] Update `agents project create` to use the domain model for invariants - [ ] Update `agents project show` to display invariants - [ ] Add unit tests for invariant persistence and retrieval - [ ] Run `nox` and ensure all sessions pass ## 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. - 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**. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
Author
Owner

Label compliance fix applied:

  • Added missing labels: Priority/High, State/Unverified, Type/Bug
  • Reason: Issue was missing all required labels per CONTRIBUTING.md. Inferred Type/Bug from the "UAT: bug" prefix. Applied Priority/High (domain model missing field is high severity) and State/Unverified as defaults.

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

Label compliance fix applied: - Added missing labels: `Priority/High`, `State/Unverified`, `Type/Bug` - Reason: Issue was missing all required labels per CONTRIBUTING.md. Inferred `Type/Bug` from the "UAT: bug" prefix. Applied `Priority/High` (domain model missing field is high severity) and `State/Unverified` as defaults. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: ca-backlog-groomer
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Confirmed
  • MoSCoW: Should Have

Valid finding verified during batch triage.


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

Issue triaged by project owner: - **State**: Verified - **Priority**: Confirmed - **MoSCoW**: Should Have Valid finding verified during batch triage. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo added this to the v3.2.0 milestone 2026-04-05 04:49:24 +00:00
Author
Owner

Milestone compliance fix applied:

  • Assigned to milestone: v3.2.0
  • Reason: Issue is State/Verified (ready for implementation) but had no milestone. Issue body references Milestone: v3.1.0 which is no longer an active open milestone. Assigned to the earliest active milestone v3.2.0 as the appropriate target.

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

Milestone compliance fix applied: - Assigned to milestone: `v3.2.0` - Reason: Issue is `State/Verified` (ready for implementation) but had no milestone. Issue body references `Milestone: v3.1.0` which is no longer an active open milestone. Assigned to the earliest active milestone `v3.2.0` as the appropriate target. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: ca-backlog-groomer
Author
Owner

Starting implementation on branch bugfix/namespaced-project-invariants-field.

Plan:

  1. Add invariants: list[str] and invariant_actor: str | None fields to NamespacedProject domain model
  2. Update NamespacedProjectModel.to_domain() to deserialize invariants_json and invariant_actor
  3. Update NamespacedProjectModel.from_domain() to serialize invariants and invariant_actor
  4. Remove _store_project_extras() raw SQL workaround from cli/commands/project.py
  5. Update agents project create to use domain model for invariants
  6. Update agents project show to display invariants
  7. Add BDD unit tests for invariant persistence and retrieval
  8. Run nox quality gates

Automated by CleverAgents Bot
Supervisor: Implementation | Agent: ca-issue-worker

Starting implementation on branch `bugfix/namespaced-project-invariants-field`. **Plan:** 1. Add `invariants: list[str]` and `invariant_actor: str | None` fields to `NamespacedProject` domain model 2. Update `NamespacedProjectModel.to_domain()` to deserialize `invariants_json` and `invariant_actor` 3. Update `NamespacedProjectModel.from_domain()` to serialize `invariants` and `invariant_actor` 4. Remove `_store_project_extras()` raw SQL workaround from `cli/commands/project.py` 5. Update `agents project create` to use domain model for invariants 6. Update `agents project show` to display invariants 7. Add BDD unit tests for invariant persistence and retrieval 8. Run `nox` quality gates --- **Automated by CleverAgents Bot** Supervisor: Implementation | Agent: ca-issue-worker
freemo removed this from the v3.2.0 milestone 2026-04-06 22:28:09 +00:00
Author
Owner

This issue has been moved to the backlog as part of an aggressive grooming of the v3.2.0 milestone. It has been deemed non-critical for the minimal viability of the milestone and will be addressed in a future release.

This issue has been moved to the backlog as part of an aggressive grooming of the v3.2.0 milestone. It has been deemed non-critical for the minimal viability of the milestone and will be addressed in a future release.
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#2941
No description provided.