UAT: Invariant IDs missing inv_ prefix — spec requires inv_<ULID> format but implementation uses raw ULIDs #3242

Open
opened 2026-04-05 08:24:23 +00:00 by freemo · 3 comments
Owner

Metadata

  • Branch: fix/invariant-id-inv-prefix
  • Commit Message: fix(domain/invariant): add inv_ prefix to invariant ID generation to match spec
  • Milestone: None (backlog)
  • Parent Epic: #362

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

Background and Context

The specification (docs/specification.md) consistently shows invariant IDs with an inv_ prefix throughout all examples and output formats. The current implementation generates and stores raw ULIDs without this prefix, causing a divergence between the spec and the actual CLI output.

Current Behavior

The Invariant domain model (src/cleveragents/domain/models/core/invariant.py) uses default_factory=lambda: str(ULID()) which produces raw ULIDs like 01JQAAAAAAAAAAAAAAAAAA01 without the inv_ prefix.

The InvariantService.add_invariant() method (src/cleveragents/application/services/invariant_service.py) also generates IDs using str(ULID()) without the prefix.

This means:

  1. agents invariant add displays raw ULID IDs (e.g., 01JQAAAAAAAAAAAAAAAAAA01)
  2. agents invariant list shows raw ULID IDs in the ID column
  3. agents invariant remove requires a raw ULID argument, not the inv_-prefixed ID shown in the spec

Steps to reproduce:

  1. Run agents invariant add --global "Test constraint"
  2. Observe the ID in the output — it will be a raw ULID without inv_ prefix
  3. Compare with spec example: ID: inv_01HXM9A1B

Expected Behavior

Per docs/specification.md §17820–18179, all invariant IDs must carry the inv_ prefix:

  • inv_01HXM9A1B (global invariant example)
  • inv_01HXM9A2C (project invariant example)
  • inv_01HXM9G3A (plan invariant example)
  • inv_01HXM9H4B (action invariant example)
  • inv_01HXM9A1C (remove command example: agents invariant remove inv_01HXM9A1C)

The agents invariant remove command takes <INVARIANT_ID> as argument, and the spec example shows: agents invariant remove inv_01HXM9A1C

The JSON and YAML output formats also show the prefixed ID:

{ "id": "inv_01HXM9A1B" }

Acceptance Criteria

  • Invariant.id field default factory generates IDs in inv_<ULID> format
  • agents invariant add output displays IDs with inv_ prefix
  • agents invariant list ID column shows inv_-prefixed IDs
  • agents invariant remove inv_<ULID> accepts and resolves inv_-prefixed IDs
  • JSON and YAML output formats include the inv_ prefix in the id field
  • Existing persisted raw-ULID IDs are handled gracefully (migration or validation)

Supporting Information

Code locations:

  • src/cleveragents/domain/models/core/invariant.py: Invariant.id field default_factory
  • src/cleveragents/application/services/invariant_service.py: add_invariant() method

Related issues: #3192, #3196 (invariant output format bugs that also reference the inv_ prefix in their expected output)

Spec references: docs/specification.md §17820 (ID: inv_01HXM9A1B), §17831 (ID: inv_01HXM9A2C), §17842 (ID: inv_01HXM9G3A), §17853 (ID: inv_01HXM9H4B), §18125 (agents invariant remove inv_01HXM9A1C)

Subtasks

  • Update Invariant.id default factory in src/cleveragents/domain/models/core/invariant.py to generate inv_<ULID> format
  • Update InvariantService.add_invariant() in src/cleveragents/application/services/invariant_service.py if it overrides ID generation
  • Verify agents invariant remove CLI argument parsing accepts inv_-prefixed IDs
  • Add/update input validation to accept inv_<ULID> format in remove command
  • Consider migration strategy for any existing persisted raw-ULID invariant IDs
  • Tests (Behave): Add/update BDD scenarios asserting inv_ prefix in invariant add output
  • Tests (Behave): Add/update BDD scenarios asserting inv_ prefix in invariant list ID column
  • Tests (Behave): Add/update BDD scenario for invariant remove inv_<ULID> with prefixed ID
  • Tests (Robot): Add/update integration test verifying end-to-end inv_ prefix round-trip
  • 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.
  • Invariant.id generation produces inv_<ULID> format matching the spec in all code paths.
  • All CLI commands (add, list, remove) display and accept inv_-prefixed IDs.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly (fix(domain/invariant): add inv_ prefix to invariant ID generation to match spec), followed by a blank line, then additional lines providing relevant implementation details.
  • The commit is pushed to the remote on the branch fix/invariant-id-inv-prefix.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
  • All nox stages pass.
  • Coverage ≥ 97%.

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

## Metadata - **Branch**: `fix/invariant-id-inv-prefix` - **Commit Message**: `fix(domain/invariant): add inv_ prefix to invariant ID generation to match spec` - **Milestone**: None (backlog) - **Parent Epic**: #362 > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.7.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. ## Background and Context The specification (`docs/specification.md`) consistently shows invariant IDs with an `inv_` prefix throughout all examples and output formats. The current implementation generates and stores raw ULIDs without this prefix, causing a divergence between the spec and the actual CLI output. ## Current Behavior The `Invariant` domain model (`src/cleveragents/domain/models/core/invariant.py`) uses `default_factory=lambda: str(ULID())` which produces raw ULIDs like `01JQAAAAAAAAAAAAAAAAAA01` without the `inv_` prefix. The `InvariantService.add_invariant()` method (`src/cleveragents/application/services/invariant_service.py`) also generates IDs using `str(ULID())` without the prefix. This means: 1. `agents invariant add` displays raw ULID IDs (e.g., `01JQAAAAAAAAAAAAAAAAAA01`) 2. `agents invariant list` shows raw ULID IDs in the ID column 3. `agents invariant remove` requires a raw ULID argument, not the `inv_`-prefixed ID shown in the spec **Steps to reproduce:** 1. Run `agents invariant add --global "Test constraint"` 2. Observe the ID in the output — it will be a raw ULID without `inv_` prefix 3. Compare with spec example: `ID: inv_01HXM9A1B` ## Expected Behavior Per `docs/specification.md` §17820–18179, all invariant IDs must carry the `inv_` prefix: - `inv_01HXM9A1B` (global invariant example) - `inv_01HXM9A2C` (project invariant example) - `inv_01HXM9G3A` (plan invariant example) - `inv_01HXM9H4B` (action invariant example) - `inv_01HXM9A1C` (remove command example: `agents invariant remove inv_01HXM9A1C`) The `agents invariant remove` command takes `<INVARIANT_ID>` as argument, and the spec example shows: `agents invariant remove inv_01HXM9A1C` The JSON and YAML output formats also show the prefixed ID: ```json { "id": "inv_01HXM9A1B" } ``` ## Acceptance Criteria - `Invariant.id` field default factory generates IDs in `inv_<ULID>` format - `agents invariant add` output displays IDs with `inv_` prefix - `agents invariant list` ID column shows `inv_`-prefixed IDs - `agents invariant remove inv_<ULID>` accepts and resolves `inv_`-prefixed IDs - JSON and YAML output formats include the `inv_` prefix in the `id` field - Existing persisted raw-ULID IDs are handled gracefully (migration or validation) ## Supporting Information **Code locations:** - `src/cleveragents/domain/models/core/invariant.py`: `Invariant.id` field `default_factory` - `src/cleveragents/application/services/invariant_service.py`: `add_invariant()` method **Related issues:** #3192, #3196 (invariant output format bugs that also reference the `inv_` prefix in their expected output) **Spec references:** `docs/specification.md` §17820 (`ID: inv_01HXM9A1B`), §17831 (`ID: inv_01HXM9A2C`), §17842 (`ID: inv_01HXM9G3A`), §17853 (`ID: inv_01HXM9H4B`), §18125 (`agents invariant remove inv_01HXM9A1C`) ## Subtasks - [ ] Update `Invariant.id` default factory in `src/cleveragents/domain/models/core/invariant.py` to generate `inv_<ULID>` format - [ ] Update `InvariantService.add_invariant()` in `src/cleveragents/application/services/invariant_service.py` if it overrides ID generation - [ ] Verify `agents invariant remove` CLI argument parsing accepts `inv_`-prefixed IDs - [ ] Add/update input validation to accept `inv_<ULID>` format in remove command - [ ] Consider migration strategy for any existing persisted raw-ULID invariant IDs - [ ] Tests (Behave): Add/update BDD scenarios asserting `inv_` prefix in `invariant add` output - [ ] Tests (Behave): Add/update BDD scenarios asserting `inv_` prefix in `invariant list` ID column - [ ] Tests (Behave): Add/update BDD scenario for `invariant remove inv_<ULID>` with prefixed ID - [ ] Tests (Robot): Add/update integration test verifying end-to-end `inv_` prefix round-trip - [ ] 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. - `Invariant.id` generation produces `inv_<ULID>` format matching the spec in all code paths. - All CLI commands (`add`, `list`, `remove`) display and accept `inv_`-prefixed IDs. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly (`fix(domain/invariant): add inv_ prefix to invariant ID generation to match spec`), followed by a blank line, then additional lines providing relevant implementation details. - The commit is pushed to the remote on the branch `fix/invariant-id-inv-prefix`. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. - All nox stages pass. - Coverage ≥ 97%. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
freemo added this to the v3.2.0 milestone 2026-04-05 08:41:27 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified — clear spec-vs-implementation mismatch with multiple spec section references
  • Priority: Medium — spec compliance issue affecting all invariant CLI commands. The commands work but produce non-spec-compliant IDs.
  • Milestone: v3.2.0 — invariant management is core v3.2.0 scope (Decisions + Validations + Invariants)
  • MoSCoW: Should Have — the spec consistently uses inv_ prefix in all examples (§17820–18179). This is a spec compliance issue that affects the user-facing API contract. Related to #3192 and #3196 which also reference the inv_ prefix.
  • Parent Epic: #362 (referenced in issue body)

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

Issue triaged by project owner: - **State**: Verified — clear spec-vs-implementation mismatch with multiple spec section references - **Priority**: Medium — spec compliance issue affecting all invariant CLI commands. The commands work but produce non-spec-compliant IDs. - **Milestone**: v3.2.0 — invariant management is core v3.2.0 scope (Decisions + Validations + Invariants) - **MoSCoW**: Should Have — the spec consistently uses `inv_` prefix in all examples (§17820–18179). This is a spec compliance issue that affects the user-facing API contract. Related to #3192 and #3196 which also reference the `inv_` prefix. - **Parent Epic**: #362 (referenced in issue body) --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Medium
  • Milestone: v3.2.0 (assigned — invariant ID format is M3 Decisions + Validations + Invariants scope)
  • MoSCoW: Should Have — the spec consistently uses inv_<ULID> format across all invariant examples; missing prefix is a spec compliance gap that affects CLI output consistency
  • Parent Epic: #362 (Security & Safety Hardening)

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

Issue triaged by project owner: - **State**: Verified - **Priority**: Medium - **Milestone**: v3.2.0 (assigned — invariant ID format is M3 Decisions + Validations + Invariants scope) - **MoSCoW**: Should Have — the spec consistently uses `inv_<ULID>` format across all invariant examples; missing prefix is a spec compliance gap that affects CLI output consistency - **Parent Epic**: #362 (Security & Safety Hardening) --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Author
Owner

Label compliance fix applied:

  • Removed duplicate MoSCoW/Should have (org-level) — keeping MoSCoW/Should Have (repo-level)
  • Reason: Issue had two conflicting MoSCoW labels from org and repo label sets. Removed the org-level duplicate to maintain clean label state.

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

Label compliance fix applied: - Removed duplicate `MoSCoW/Should have` (org-level) — keeping `MoSCoW/Should Have` (repo-level) - Reason: Issue had two conflicting MoSCoW labels from org and repo label sets. Removed the org-level duplicate to maintain clean label state. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: ca-backlog-groomer
freemo removed this from the v3.2.0 milestone 2026-04-06 20:51:14 +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
#362 Epic: Security & Safety Hardening
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3242
No description provided.