UAT: NamespacedName.validate_namespace() and validate_name() in plan.py allow names starting with digits — spec requires names to start with a letter #2147

Open
opened 2026-04-03 04:25:51 +00:00 by freemo · 2 comments
Owner

Metadata

  • Branch: bugfix/m7-namespacedname-digit-start-validation
  • Commit Message: fix(plan): enforce letter-start rule in NamespacedName namespace and name validators
  • Milestone: v3.7.0
  • Parent Epic: #368

Background and Context

Code-level analysis of src/cleveragents/domain/models/core/plan.py revealed that the NamespacedName class validators do not enforce the spec-required rule that namespace and name components must begin with a letter.

Per docs/specification.md §Namespaces and ADR-002, the namespace format is [[server:]namespace/]name. The spec states names should be "stable identifiers (kebab-case recommended)." The project.py implementation correctly uses _BARE_NAME_RE = re.compile(r"^[a-zA-Z][a-zA-Z0-9_-]*$") which requires names to start with a letter — consistent with standard identifier conventions.

Current Behavior

NamespacedName in src/cleveragents/domain/models/core/plan.py has two validators that do not enforce the "must start with a letter" rule:

  1. validate_namespace() uses all(c.isalnum() or c == "-" for c in v) — allows 123abc/my-action
  2. validate_name() uses v.replace("-", "").replace("_", "").isalnum() — allows local/123-action
@field_validator("namespace")
@classmethod
def validate_namespace(cls: type[NamespacedName], v: str) -> str:
    if not all(c.isalnum() or c == "-" for c in v):  # Allows digit-starting names
        raise ValueError("Namespace must be alphanumeric with hyphens only")
    return v.lower()

@field_validator("name")
@classmethod
def validate_name(cls: type[NamespacedName], v: str) -> str:
    if not v.replace("-", "").replace("_", "").isalnum():  # Allows digit-starting names
        raise ValueError("Name must be alphanumeric with hyphens or underscores")
    return v.lower()

Steps to reproduce:

from cleveragents.domain.models.core.plan import NamespacedName

# These should fail but don't:
nn = NamespacedName.parse("123abc/my-action")  # namespace starts with digit
print(nn)  # Prints: 123abc/my-action

nn2 = NamespacedName(namespace="local", name="123-action")  # name starts with digit
print(nn2)  # Prints: local/123-action

Expected Behavior

Both validate_namespace() and validate_name() should reject any component that begins with a digit, raising a ValidationError. The validators should use a regex pattern equivalent to ^[a-zA-Z][a-zA-Z0-9_-]*$ (consistent with project.py's _BARE_NAME_RE).

Acceptance Criteria

  • NamespacedName.parse("123abc/my-action") raises a ValidationError.
  • NamespacedName(namespace="local", name="123-action") raises a ValidationError.
  • NamespacedName.parse("valid-ns/valid-name") continues to succeed.
  • NamespacedName.parse("abc123/my-action") continues to succeed (digit after first letter is valid).
  • The fix is consistent with the _BARE_NAME_RE pattern in project.py.
  • All existing NamespacedName tests continue to pass.

Supporting Information

  • Code location (bug): src/cleveragents/domain/models/core/plan.pyNamespacedName.validate_namespace() (~line 221) and NamespacedName.validate_name() (~line 232)
  • Reference implementation: src/cleveragents/domain/models/core/project.py_BARE_NAME_RE (~line 39)
  • Spec reference: docs/specification.md §Namespaces and ADR-002
  • TDD issue (blocks this): #2145

Subtasks

  • Confirm TDD issue #2145 is merged to master before beginning fix work
  • Replace validate_namespace() character-by-character check with a regex enforcing ^[a-zA-Z][a-zA-Z0-9-]*$
  • Replace validate_name() strip-and-isalnum check with a regex enforcing ^[a-zA-Z][a-zA-Z0-9_-]*$
  • Update validator error messages to clearly state "must start with a letter"
  • Remove @tdd_expected_fail tag from all @tdd_issue_<N> scenarios in the test suite (where N is this issue's number)
  • Run nox -s unit_tests and confirm the TDD scenarios now pass
  • Run nox (all default sessions), fix any errors
  • Verify coverage >= 97% via nox -s coverage_report

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.
  • All nox stages pass.
  • Coverage >= 97%.

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

## Metadata - **Branch**: `bugfix/m7-namespacedname-digit-start-validation` - **Commit Message**: `fix(plan): enforce letter-start rule in NamespacedName namespace and name validators` - **Milestone**: v3.7.0 - **Parent Epic**: #368 ## Background and Context Code-level analysis of `src/cleveragents/domain/models/core/plan.py` revealed that the `NamespacedName` class validators do not enforce the spec-required rule that namespace and name components must begin with a letter. Per `docs/specification.md` §Namespaces and ADR-002, the namespace format is `[[server:]namespace/]name`. The spec states names should be "stable identifiers (kebab-case recommended)." The `project.py` implementation correctly uses `_BARE_NAME_RE = re.compile(r"^[a-zA-Z][a-zA-Z0-9_-]*$")` which requires names to start with a letter — consistent with standard identifier conventions. ## Current Behavior `NamespacedName` in `src/cleveragents/domain/models/core/plan.py` has two validators that do **not** enforce the "must start with a letter" rule: 1. `validate_namespace()` uses `all(c.isalnum() or c == "-" for c in v)` — allows `123abc/my-action` 2. `validate_name()` uses `v.replace("-", "").replace("_", "").isalnum()` — allows `local/123-action` ```python @field_validator("namespace") @classmethod def validate_namespace(cls: type[NamespacedName], v: str) -> str: if not all(c.isalnum() or c == "-" for c in v): # Allows digit-starting names raise ValueError("Namespace must be alphanumeric with hyphens only") return v.lower() @field_validator("name") @classmethod def validate_name(cls: type[NamespacedName], v: str) -> str: if not v.replace("-", "").replace("_", "").isalnum(): # Allows digit-starting names raise ValueError("Name must be alphanumeric with hyphens or underscores") return v.lower() ``` **Steps to reproduce:** ```python from cleveragents.domain.models.core.plan import NamespacedName # These should fail but don't: nn = NamespacedName.parse("123abc/my-action") # namespace starts with digit print(nn) # Prints: 123abc/my-action nn2 = NamespacedName(namespace="local", name="123-action") # name starts with digit print(nn2) # Prints: local/123-action ``` ## Expected Behavior Both `validate_namespace()` and `validate_name()` should reject any component that begins with a digit, raising a `ValidationError`. The validators should use a regex pattern equivalent to `^[a-zA-Z][a-zA-Z0-9_-]*$` (consistent with `project.py`'s `_BARE_NAME_RE`). ## Acceptance Criteria - `NamespacedName.parse("123abc/my-action")` raises a `ValidationError`. - `NamespacedName(namespace="local", name="123-action")` raises a `ValidationError`. - `NamespacedName.parse("valid-ns/valid-name")` continues to succeed. - `NamespacedName.parse("abc123/my-action")` continues to succeed (digit after first letter is valid). - The fix is consistent with the `_BARE_NAME_RE` pattern in `project.py`. - All existing `NamespacedName` tests continue to pass. ## Supporting Information - **Code location (bug):** `src/cleveragents/domain/models/core/plan.py` — `NamespacedName.validate_namespace()` (~line 221) and `NamespacedName.validate_name()` (~line 232) - **Reference implementation:** `src/cleveragents/domain/models/core/project.py` — `_BARE_NAME_RE` (~line 39) - **Spec reference:** `docs/specification.md` §Namespaces and ADR-002 - **TDD issue (blocks this):** #2145 ## Subtasks - [ ] Confirm TDD issue #2145 is merged to `master` before beginning fix work - [ ] Replace `validate_namespace()` character-by-character check with a regex enforcing `^[a-zA-Z][a-zA-Z0-9-]*$` - [ ] Replace `validate_name()` strip-and-isalnum check with a regex enforcing `^[a-zA-Z][a-zA-Z0-9_-]*$` - [ ] Update validator error messages to clearly state "must start with a letter" - [ ] Remove `@tdd_expected_fail` tag from all `@tdd_issue_<N>` scenarios in the test suite (where N is this issue's number) - [ ] Run `nox -s unit_tests` and confirm the TDD scenarios now pass - [ ] Run `nox` (all default sessions), fix any errors - [ ] Verify coverage >= 97% via `nox -s coverage_report` ## 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. - All nox stages pass. - Coverage >= 97%. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.7.0 milestone 2026-04-03 04:26:08 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Critical (confirmed) — NamespacedName validators allow names starting with digits, which violates the spec's naming conventions and is inconsistent with project.py's _BARE_NAME_RE. This is a data integrity issue — invalid names could be persisted and cause downstream failures.
  • Milestone: v3.7.0 (confirmed — Plan Lifecycle Epic #368)
  • MoSCoW: Should Have — While this is a spec violation, the practical impact depends on whether digit-starting names are actually being created. The fix is straightforward (replace character checks with regex) and should be done for consistency with project.py.
  • Parent Epic: #368 (confirmed correct)
  • Dependency: Blocked by TDD issue #2145

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

Issue triaged by project owner: - **State**: Verified - **Priority**: Critical (confirmed) — `NamespacedName` validators allow names starting with digits, which violates the spec's naming conventions and is inconsistent with `project.py`'s `_BARE_NAME_RE`. This is a data integrity issue — invalid names could be persisted and cause downstream failures. - **Milestone**: v3.7.0 (confirmed — Plan Lifecycle Epic #368) - **MoSCoW**: Should Have — While this is a spec violation, the practical impact depends on whether digit-starting names are actually being created. The fix is straightforward (replace character checks with regex) and should be done for consistency with `project.py`. - **Parent Epic**: #368 (confirmed correct) - **Dependency**: Blocked by TDD issue #2145 --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo self-assigned this 2026-04-03 16:58:01 +00:00
Author
Owner

Starting implementation on branch bugfix/m7-namespacedname-digit-start-validation.

Fresh run — no prior state detected.

Subtask dependency analysis:

  • Wave 1 (independent): Subtasks 1-4 (confirm TDD merged, fix validators, update error messages) — all touch plan.py and can be done together
  • Wave 2 (depends on Wave 1): Subtask 5 (remove @tdd_expected_fail tags)
  • Wave 3 (depends on Wave 2): Subtasks 6-8 (run tests, nox, coverage)

TDD status: Issue #2145 commit 33c1e4cd is confirmed merged to master.


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

Starting implementation on branch `bugfix/m7-namespacedname-digit-start-validation`. **Fresh run** — no prior state detected. **Subtask dependency analysis:** - Wave 1 (independent): Subtasks 1-4 (confirm TDD merged, fix validators, update error messages) — all touch `plan.py` and can be done together - Wave 2 (depends on Wave 1): Subtask 5 (remove `@tdd_expected_fail` tags) - Wave 3 (depends on Wave 2): Subtasks 6-8 (run tests, nox, coverage) **TDD status:** Issue #2145 commit `33c1e4cd` is confirmed merged to master. ✅ --- **Automated by CleverAgents Bot** Supervisor: Implementation | Agent: ca-issue-worker
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.

Reference
cleveragents/cleveragents-core#2147
No description provided.