UAT: NamespacedProjectModel.from_domain() always discards project invariants, automation profile, and invariant actor — these fields are never persisted #2403

Open
opened 2026-04-03 17:34:41 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/namespaced-project-model-missing-domain-fields
  • Commit Message: fix(data-models): add invariants, automation_profile, and invariant_actor fields to NamespacedProject domain model
  • Milestone: v3.4.0
  • Parent Epic: #397

Description

The NamespacedProjectModel.from_domain() method in src/cleveragents/infrastructure/database/models.py (lines 1359–1391) hardcodes invariants_json=json.dumps([]), automation_profile=None, and invariant_actor=None when converting from the domain model to the database model.

Expected Behavior (from spec)

The ns_projects table has invariants_json, automation_profile, and invariant_actor columns. These represent project-level invariants, the default automation profile for plans created under this project, and the actor used for invariant reconciliation. Per the specification, projects can carry invariants that flow into plans, and projects can have a default automation profile.

Actual Behavior

When a NamespacedProject domain object is persisted via from_domain(), these three fields are always set to their empty/null defaults regardless of what the domain object contains:

model = cls(
    namespaced_name=project.namespaced_name,
    namespace=project.namespace,
    description=project.description,
    invariants_json=json.dumps([]),   # ← ALWAYS empty, ignores any project invariants
    automation_profile=None,           # ← ALWAYS null, ignores project's automation profile
    invariant_actor=None,              # ← ALWAYS null, ignores project's invariant actor
    context_policy_json=context_policy_json,
    tags_json=tags_json_str,
    created_by=None,
    created_at=project.created_at.isoformat(),
    updated_at=project.updated_at.isoformat(),
)

Root Cause

The NamespacedProject domain model (src/cleveragents/domain/models/core/project.py) does not have invariants, automation_profile, or invariant_actor fields. These are database-level fields that exist in NamespacedProjectModel but have no corresponding domain model fields, creating a data loss scenario.

Code Locations

  • src/cleveragents/infrastructure/database/models.py:1359-1391from_domain() method
  • src/cleveragents/infrastructure/database/models.py:1260-1310NamespacedProjectModel column definitions
  • src/cleveragents/domain/models/core/project.py:339-553NamespacedProject domain model (missing these fields)

Impact

  1. Project-level invariants cannot be stored or retrieved — they are silently discarded on every save
  2. Project-level default automation profiles cannot be stored — plans created from this project will not inherit the project's automation profile
  3. Project-level invariant actors cannot be stored — invariant reconciliation cannot be configured per-project

Subtasks

  • Add invariants: list[Invariant] field to NamespacedProject domain model (src/cleveragents/domain/models/core/project.py)
  • Add automation_profile: str | None field to NamespacedProject domain model
  • Add invariant_actor: str | None field to NamespacedProject domain model
  • Update NamespacedProjectModel.from_domain() to serialize invariants to JSON instead of hardcoding []
  • Update NamespacedProjectModel.from_domain() to pass automation_profile from the domain object
  • Update NamespacedProjectModel.from_domain() to pass invariant_actor from the domain object
  • Update NamespacedProjectModel.to_domain() (if present) to deserialize these fields back into the domain model
  • Update all NamespacedProject constructors and factory methods to accept the new fields
  • Write Behave unit tests covering round-trip persistence of invariants, automation_profile, and invariant_actor
  • Write Robot Framework integration tests verifying the fields survive a full save/load cycle
  • Ensure nox -e typecheck (Pyright) passes with full static typing on all new fields

Definition of Done

  • NamespacedProject domain model has invariants, automation_profile, and invariant_actor fields with correct types
  • NamespacedProjectModel.from_domain() correctly serializes all three fields (no hardcoded empty values)
  • NamespacedProjectModel.to_domain() correctly deserializes all three fields
  • Round-trip test: a NamespacedProject with non-empty invariants, a set automation profile, and a set invariant actor survives from_domain()to_domain() without data loss
  • All Behave unit tests pass (nox -e unit_tests)
  • All Robot Framework integration tests pass (nox -e integration_tests)
  • All nox stages pass
  • Coverage >= 97%

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/namespaced-project-model-missing-domain-fields` - **Commit Message**: `fix(data-models): add invariants, automation_profile, and invariant_actor fields to NamespacedProject domain model` - **Milestone**: v3.4.0 - **Parent Epic**: #397 ## Description The `NamespacedProjectModel.from_domain()` method in `src/cleveragents/infrastructure/database/models.py` (lines 1359–1391) hardcodes `invariants_json=json.dumps([])`, `automation_profile=None`, and `invariant_actor=None` when converting from the domain model to the database model. ### Expected Behavior (from spec) The `ns_projects` table has `invariants_json`, `automation_profile`, and `invariant_actor` columns. These represent project-level invariants, the default automation profile for plans created under this project, and the actor used for invariant reconciliation. Per the specification, projects can carry invariants that flow into plans, and projects can have a default automation profile. ### Actual Behavior When a `NamespacedProject` domain object is persisted via `from_domain()`, these three fields are always set to their empty/null defaults regardless of what the domain object contains: ```python model = cls( namespaced_name=project.namespaced_name, namespace=project.namespace, description=project.description, invariants_json=json.dumps([]), # ← ALWAYS empty, ignores any project invariants automation_profile=None, # ← ALWAYS null, ignores project's automation profile invariant_actor=None, # ← ALWAYS null, ignores project's invariant actor context_policy_json=context_policy_json, tags_json=tags_json_str, created_by=None, created_at=project.created_at.isoformat(), updated_at=project.updated_at.isoformat(), ) ``` ### Root Cause The `NamespacedProject` domain model (`src/cleveragents/domain/models/core/project.py`) does not have `invariants`, `automation_profile`, or `invariant_actor` fields. These are database-level fields that exist in `NamespacedProjectModel` but have no corresponding domain model fields, creating a data loss scenario. ### Code Locations - `src/cleveragents/infrastructure/database/models.py:1359-1391` — `from_domain()` method - `src/cleveragents/infrastructure/database/models.py:1260-1310` — `NamespacedProjectModel` column definitions - `src/cleveragents/domain/models/core/project.py:339-553` — `NamespacedProject` domain model (missing these fields) ### Impact 1. Project-level invariants cannot be stored or retrieved — they are silently discarded on every save 2. Project-level default automation profiles cannot be stored — plans created from this project will not inherit the project's automation profile 3. Project-level invariant actors cannot be stored — invariant reconciliation cannot be configured per-project ## Subtasks - [ ] Add `invariants: list[Invariant]` field to `NamespacedProject` domain model (`src/cleveragents/domain/models/core/project.py`) - [ ] Add `automation_profile: str | None` field to `NamespacedProject` domain model - [ ] Add `invariant_actor: str | None` field to `NamespacedProject` domain model - [ ] Update `NamespacedProjectModel.from_domain()` to serialize `invariants` to JSON instead of hardcoding `[]` - [ ] Update `NamespacedProjectModel.from_domain()` to pass `automation_profile` from the domain object - [ ] Update `NamespacedProjectModel.from_domain()` to pass `invariant_actor` from the domain object - [ ] Update `NamespacedProjectModel.to_domain()` (if present) to deserialize these fields back into the domain model - [ ] Update all `NamespacedProject` constructors and factory methods to accept the new fields - [ ] Write Behave unit tests covering round-trip persistence of invariants, automation_profile, and invariant_actor - [ ] Write Robot Framework integration tests verifying the fields survive a full save/load cycle - [ ] Ensure `nox -e typecheck` (Pyright) passes with full static typing on all new fields ## Definition of Done - [ ] `NamespacedProject` domain model has `invariants`, `automation_profile`, and `invariant_actor` fields with correct types - [ ] `NamespacedProjectModel.from_domain()` correctly serializes all three fields (no hardcoded empty values) - [ ] `NamespacedProjectModel.to_domain()` correctly deserializes all three fields - [ ] Round-trip test: a `NamespacedProject` with non-empty invariants, a set automation profile, and a set invariant actor survives `from_domain()` → `to_domain()` without data loss - [ ] All Behave unit tests pass (`nox -e unit_tests`) - [ ] All Robot Framework integration tests pass (`nox -e integration_tests`) - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.4.0 milestone 2026-04-03 17:34:46 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: High — Project invariants, automation profile, and invariant actor being discarded on persistence means these core domain concepts are non-functional. Data written is silently lost on read-back.
  • Milestone: v3.4.0 (as specified in issue metadata)
  • MoSCoW: Must Have — Invariants are a core concept in the plan lifecycle. Without persistence, the invariant system is broken. This blocks the Decision Framework and Plan Lifecycle features.
  • Parent Epic: #397 (Server & Autonomy Infrastructure)

The issue is well-described with clear code references and a definition of done. Valid and actionable.


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

Issue triaged by project owner: - **State**: Verified - **Priority**: High — Project invariants, automation profile, and invariant actor being discarded on persistence means these core domain concepts are non-functional. Data written is silently lost on read-back. - **Milestone**: v3.4.0 (as specified in issue metadata) - **MoSCoW**: Must Have — Invariants are a core concept in the plan lifecycle. Without persistence, the invariant system is broken. This blocks the Decision Framework and Plan Lifecycle features. - **Parent Epic**: #397 (Server & Autonomy Infrastructure) The issue is well-described with clear code references and a definition of done. Valid and actionable. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo removed this from the v3.4.0 milestone 2026-04-06 21:01:28 +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.

Blocks
#397 Epic: Server & Autonomy Infrastructure
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2403
No description provided.