UAT: Context model plan_id field uses int type instead of ULID string — violates spec identity contract #3661

Open
opened 2026-04-05 21:12:57 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/context-plan-id-ulid-type
  • Commit Message: fix(domain/context): replace int plan_id with ULID string to match spec identity contract
  • Milestone: None (Backlog)
  • Parent Epic: #396 (Epic: ACMS Context Pipeline)

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

What Was Tested

Reviewed the Context domain model in src/cleveragents/domain/models/core/context.py and compared it against the specification's identity contract for plan references.

Expected Behavior (from spec)

Per docs/specification.md (Naming & Identity section):

ULID: Universally Unique Lexicographically Sortable Identifier. Assigned to plans, decisions, resources, correction attempts, and validation attachments.

Per the spec DDL (line 45565):

plan_id TEXT PRIMARY KEY,  -- ULID

The plan_id field on any model that references a plan MUST be a ULID string (26-character Crockford base32 string matching ^[0-9A-HJKMNP-TV-Z]{26}$), not an integer.

Actual Behavior (from code)

In src/cleveragents/domain/models/core/context.py, line 61:

class Context(BaseModel):
    id: int | None = Field(None)
    plan_id: int = Field(..., gt=0)  # BUG: should be str with ULID pattern

The plan_id field is typed as int with a gt=0 constraint. This is incompatible with the ULID-based plan identity system used throughout the rest of the codebase (e.g., Plan.identity.plan_id, Decision.plan_id, SubplanStatus.subplan_id all use ULID strings).

Impact

  1. Type incompatibility: Any code that creates a Context object with a ULID plan_id (the correct type) will fail Pydantic validation.
  2. Data integrity: If persisted, integer plan_ids cannot be joined with the plans table which uses TEXT ULID primary keys.
  3. Inconsistency: All other models that reference plans use ULID strings. This model is the only exception, suggesting it was not updated when the v3 plan model was introduced.

Steps to Reproduce

from cleveragents.domain.models.core.context import Context
# This should work but fails because plan_id expects int:
ctx = Context(plan_id="01HXM7A9BCDEFGHJKMNPQRSTVW", path="/some/file.py")
# ValidationError: plan_id must be > 0 (int validation)

Code Location

  • src/cleveragents/domain/models/core/context.py, line 61
  • Compare with correct usage in src/cleveragents/domain/models/core/decision.py line ~200: plan_id: str = Field(..., pattern=ULID_PATTERN)

Suggested Fix

Change plan_id: int = Field(..., gt=0) to:

ULID_PATTERN = r"^[0-9A-HJKMNP-TV-Z]{26}$"
plan_id: str = Field(..., description="ULID of the parent plan", pattern=ULID_PATTERN)

Also update id: int | None = Field(None) to use a proper identifier type consistent with the rest of the system.

Subtasks

  • Change Context.plan_id type from int to str with ULID pattern validation
  • Change Context.id to use an appropriate identifier type (ULID string or None)
  • Update all existing unit tests (Behave) that construct Context objects to use valid ULID strings for plan_id
  • Add new Behave scenario: Context rejects non-ULID values for plan_id
  • Run nox -e typecheck to confirm Pyright passes with the new types
  • Run nox -e unit_tests and nox -e coverage_report to confirm ≥97% coverage

Definition of Done

  • Context.plan_id is typed as str with ULID pattern validation (^[0-9A-HJKMNP-TV-Z]{26}$)
  • Context.id uses an appropriate identifier type (ULID string or None) consistent with the rest of the system
  • Existing tests updated to use ULID strings for plan_id
  • New Behave test scenario verifies Context rejects non-ULID plan_id values
  • All nox stages pass
  • Coverage >= 97%

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

## Metadata - **Branch**: `fix/context-plan-id-ulid-type` - **Commit Message**: `fix(domain/context): replace int plan_id with ULID string to match spec identity contract` - **Milestone**: None (Backlog) - **Parent Epic**: #396 (Epic: ACMS Context Pipeline) > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.5.0 (Corrections + Context). It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. ## What Was Tested Reviewed the `Context` domain model in `src/cleveragents/domain/models/core/context.py` and compared it against the specification's identity contract for plan references. ## Expected Behavior (from spec) Per `docs/specification.md` (Naming & Identity section): > ULID: Universally Unique Lexicographically Sortable Identifier. Assigned to plans, decisions, resources, correction attempts, and validation attachments. Per the spec DDL (line 45565): ```sql plan_id TEXT PRIMARY KEY, -- ULID ``` The `plan_id` field on any model that references a plan MUST be a ULID string (26-character Crockford base32 string matching `^[0-9A-HJKMNP-TV-Z]{26}$`), not an integer. ## Actual Behavior (from code) In `src/cleveragents/domain/models/core/context.py`, line 61: ```python class Context(BaseModel): id: int | None = Field(None) plan_id: int = Field(..., gt=0) # BUG: should be str with ULID pattern ``` The `plan_id` field is typed as `int` with a `gt=0` constraint. This is incompatible with the ULID-based plan identity system used throughout the rest of the codebase (e.g., `Plan.identity.plan_id`, `Decision.plan_id`, `SubplanStatus.subplan_id` all use ULID strings). ## Impact 1. **Type incompatibility**: Any code that creates a `Context` object with a ULID plan_id (the correct type) will fail Pydantic validation. 2. **Data integrity**: If persisted, integer plan_ids cannot be joined with the plans table which uses TEXT ULID primary keys. 3. **Inconsistency**: All other models that reference plans use ULID strings. This model is the only exception, suggesting it was not updated when the v3 plan model was introduced. ## Steps to Reproduce ```python from cleveragents.domain.models.core.context import Context # This should work but fails because plan_id expects int: ctx = Context(plan_id="01HXM7A9BCDEFGHJKMNPQRSTVW", path="/some/file.py") # ValidationError: plan_id must be > 0 (int validation) ``` ## Code Location - `src/cleveragents/domain/models/core/context.py`, line 61 - Compare with correct usage in `src/cleveragents/domain/models/core/decision.py` line ~200: `plan_id: str = Field(..., pattern=ULID_PATTERN)` ## Suggested Fix Change `plan_id: int = Field(..., gt=0)` to: ```python ULID_PATTERN = r"^[0-9A-HJKMNP-TV-Z]{26}$" plan_id: str = Field(..., description="ULID of the parent plan", pattern=ULID_PATTERN) ``` Also update `id: int | None = Field(None)` to use a proper identifier type consistent with the rest of the system. ## Subtasks - [ ] Change `Context.plan_id` type from `int` to `str` with ULID pattern validation - [ ] Change `Context.id` to use an appropriate identifier type (ULID string or `None`) - [ ] Update all existing unit tests (Behave) that construct `Context` objects to use valid ULID strings for `plan_id` - [ ] Add new Behave scenario: `Context` rejects non-ULID values for `plan_id` - [ ] Run `nox -e typecheck` to confirm Pyright passes with the new types - [ ] Run `nox -e unit_tests` and `nox -e coverage_report` to confirm ≥97% coverage ## Definition of Done - [ ] `Context.plan_id` is typed as `str` with ULID pattern validation (`^[0-9A-HJKMNP-TV-Z]{26}$`) - [ ] `Context.id` uses an appropriate identifier type (ULID string or `None`) consistent with the rest of the system - [ ] Existing tests updated to use ULID strings for `plan_id` - [ ] New Behave test scenario verifies `Context` rejects non-ULID `plan_id` values - [ ] All nox stages pass - [ ] Coverage >= 97% --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.5.0 milestone 2026-04-05 22:12:34 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Critical — The Context model's plan_id field uses int instead of ULID str, making it impossible to create Context objects with valid ULID plan references. This breaks the spec's identity contract and causes type incompatibility with the rest of the domain model.
  • Milestone: v3.5.0 (Corrections + Context — this is a context model correction that belongs in this milestone)
  • Story Points: 2 — S — Single model field type change plus test updates. The fix is well-defined: change int to str with ULID pattern.
  • MoSCoW: Must Have — The spec's identity contract requires ULID strings for all plan references. This is a "MUST" requirement. The Context model is the only model that deviates, and it breaks Pydantic validation for any code using ULID plan IDs.
  • Parent Epic: #396 (ACMS Context Pipeline)

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

Issue triaged by project owner: - **State**: Verified - **Priority**: Critical — The `Context` model's `plan_id` field uses `int` instead of ULID `str`, making it impossible to create `Context` objects with valid ULID plan references. This breaks the spec's identity contract and causes type incompatibility with the rest of the domain model. - **Milestone**: v3.5.0 (Corrections + Context — this is a context model correction that belongs in this milestone) - **Story Points**: 2 — S — Single model field type change plus test updates. The fix is well-defined: change `int` to `str` with ULID pattern. - **MoSCoW**: Must Have — The spec's identity contract requires ULID strings for all plan references. This is a "MUST" requirement. The Context model is the only model that deviates, and it breaks Pydantic validation for any code using ULID plan IDs. - **Parent Epic**: #396 (ACMS Context Pipeline) --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo removed this from the v3.5.0 milestone 2026-04-06 21:05:31 +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
#396 Epic: ACMS Context Pipeline
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3661
No description provided.