UAT: NamespacedName.validate_namespace() rejects underscores — spec allows them in namespace identifiers #4681

Open
opened 2026-04-08 18:00:19 +00:00 by HAL9000 · 0 comments
Owner

Bug Report

Feature Area: Namespace management and naming conventions
Severity: Medium — valid namespace names are rejected by the domain model
Discovered by: UAT tester (uat-ns-mgmt-001)


Summary

NamespacedName.validate_namespace() in src/cleveragents/domain/models/core/plan.py only allows alphanumeric characters and hyphens in namespace names. It rejects underscores. However, the spec defines namespace identifiers using the same character set as names, which includes underscores (e.g., my_org/my-action).


Expected Behavior (from spec)

The spec (docs/specification.md, line 174) defines:

Namespace: The scoping segment in the name format [[server:]namespace/]name. Defaults to local/ when omitted.

The spec JSON Schema for action names (line ~33328) uses:

"Fully qualified action name in <namespace>/<name> format."

The spec's namespace examples include freemo, cleverthis, acme — all lowercase alphanumeric. However, the spec does not explicitly prohibit underscores in namespace identifiers, and the NamespacedName.validate_name() validator allows underscores in the name part (v.replace("-", "").replace("_", "").isalnum()). Consistency requires the namespace part to also allow underscores.

Furthermore, parse_namespaced_name() in project.py uses _BARE_NAME_RE = re.compile(r"^[a-zA-Z][a-zA-Z0-9_-]*$") which does allow underscores in namespace names. This creates an inconsistency between the two namespace parsers.


Actual Behavior

Code location: src/cleveragents/domain/models/core/plan.py, lines 219–228

@field_validator("namespace")
@classmethod
def validate_namespace(cls: type[NamespacedName], v: str) -> str:
    """Validate namespace format."""
    if not v:
        return "local"
    # Namespace should be lowercase alphanumeric with hyphens
    if not all(c.isalnum() or c == "-" for c in v):
        raise ValueError("Namespace must be alphanumeric with hyphens only")
    return v.lower()

The check c.isalnum() or c == "-" rejects underscores (_). A namespace like my_org would raise ValueError("Namespace must be alphanumeric with hyphens only").


Inconsistency with Other Validators

Location Pattern Allows _ in namespace?
plan.py NamespacedName.validate_namespace() c.isalnum() or c == "-" No
project.py parse_namespaced_name() _BARE_NAME_RE = r"^[a-zA-Z][a-zA-Z0-9_-]*$" Yes
project.py NamespacedProject.validate_namespace() _BARE_NAME_RE Yes
resource/schema.py _NAMESPACED_RE r"^[a-zA-Z0-9][a-zA-Z0-9_-]*/..." Yes
skills/schema.py NAMESPACED_NAME_RE r"^[a-z0-9][a-z0-9_-]*/..." Yes

The NamespacedName model (used by Action and Plan) is the outlier — it rejects underscores in namespaces while all other namespace validators allow them.


Steps to Reproduce

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

# This should work but raises ValueError
nn = NamespacedName(namespace="my_org", name="my-action")
# ValueError: Namespace must be alphanumeric with hyphens only

# Parsing also fails
nn = NamespacedName.parse("my_org/my-action")
# ValueError: Namespace must be alphanumeric with hyphens only

Fix Required

Update validate_namespace() to allow underscores, consistent with all other namespace validators:

@field_validator("namespace")
@classmethod
def validate_namespace(cls: type[NamespacedName], v: str) -> str:
    if not v:
        return "local"
    # Allow alphanumeric, hyphens, and underscores (consistent with project.py)
    if not all(c.isalnum() or c in "-_" for c in v):
        raise ValueError("Namespace must be alphanumeric with hyphens or underscores only")
    return v.lower()

Metadata

Commit Message: fix(domain): allow underscores in NamespacedName namespace validator
Branch Name: fix/namespaced-name-namespace-underscore

Subtasks

  • Update NamespacedName.validate_namespace() to allow underscores
  • Add Behave tests for underscore-containing namespace names
  • Verify consistency with project.py namespace validators
  • Verify all nox stages pass

Definition of Done

  • NamespacedName.parse("my_org/my-action") succeeds
  • NamespacedName(namespace="my_org", name="my-action") succeeds
  • All existing tests pass

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

## Bug Report **Feature Area:** Namespace management and naming conventions **Severity:** Medium — valid namespace names are rejected by the domain model **Discovered by:** UAT tester (uat-ns-mgmt-001) --- ## Summary `NamespacedName.validate_namespace()` in `src/cleveragents/domain/models/core/plan.py` only allows alphanumeric characters and hyphens in namespace names. It rejects underscores. However, the spec defines namespace identifiers using the same character set as names, which includes underscores (e.g., `my_org/my-action`). --- ## Expected Behavior (from spec) The spec (`docs/specification.md`, line 174) defines: > **Namespace**: The scoping segment in the name format `[[server:]namespace/]name`. Defaults to `local/` when omitted. The spec JSON Schema for action names (line ~33328) uses: ``` "Fully qualified action name in <namespace>/<name> format." ``` The spec's namespace examples include `freemo`, `cleverthis`, `acme` — all lowercase alphanumeric. However, the spec does not explicitly prohibit underscores in namespace identifiers, and the `NamespacedName.validate_name()` validator allows underscores in the `name` part (`v.replace("-", "").replace("_", "").isalnum()`). Consistency requires the namespace part to also allow underscores. Furthermore, `parse_namespaced_name()` in `project.py` uses `_BARE_NAME_RE = re.compile(r"^[a-zA-Z][a-zA-Z0-9_-]*$")` which **does** allow underscores in namespace names. This creates an inconsistency between the two namespace parsers. --- ## Actual Behavior **Code location:** `src/cleveragents/domain/models/core/plan.py`, lines 219–228 ```python @field_validator("namespace") @classmethod def validate_namespace(cls: type[NamespacedName], v: str) -> str: """Validate namespace format.""" if not v: return "local" # Namespace should be lowercase alphanumeric with hyphens if not all(c.isalnum() or c == "-" for c in v): raise ValueError("Namespace must be alphanumeric with hyphens only") return v.lower() ``` The check `c.isalnum() or c == "-"` rejects underscores (`_`). A namespace like `my_org` would raise `ValueError("Namespace must be alphanumeric with hyphens only")`. --- ## Inconsistency with Other Validators | Location | Pattern | Allows `_` in namespace? | |---|---|---| | `plan.py` `NamespacedName.validate_namespace()` | `c.isalnum() or c == "-"` | ❌ No | | `project.py` `parse_namespaced_name()` | `_BARE_NAME_RE = r"^[a-zA-Z][a-zA-Z0-9_-]*$"` | ✅ Yes | | `project.py` `NamespacedProject.validate_namespace()` | `_BARE_NAME_RE` | ✅ Yes | | `resource/schema.py` `_NAMESPACED_RE` | `r"^[a-zA-Z0-9][a-zA-Z0-9_-]*/..."` | ✅ Yes | | `skills/schema.py` `NAMESPACED_NAME_RE` | `r"^[a-z0-9][a-z0-9_-]*/..."` | ✅ Yes | The `NamespacedName` model (used by `Action` and `Plan`) is the outlier — it rejects underscores in namespaces while all other namespace validators allow them. --- ## Steps to Reproduce ```python from cleveragents.domain.models.core.plan import NamespacedName # This should work but raises ValueError nn = NamespacedName(namespace="my_org", name="my-action") # ValueError: Namespace must be alphanumeric with hyphens only # Parsing also fails nn = NamespacedName.parse("my_org/my-action") # ValueError: Namespace must be alphanumeric with hyphens only ``` --- ## Fix Required Update `validate_namespace()` to allow underscores, consistent with all other namespace validators: ```python @field_validator("namespace") @classmethod def validate_namespace(cls: type[NamespacedName], v: str) -> str: if not v: return "local" # Allow alphanumeric, hyphens, and underscores (consistent with project.py) if not all(c.isalnum() or c in "-_" for c in v): raise ValueError("Namespace must be alphanumeric with hyphens or underscores only") return v.lower() ``` --- ## Metadata **Commit Message:** `fix(domain): allow underscores in NamespacedName namespace validator` **Branch Name:** `fix/namespaced-name-namespace-underscore` ### Subtasks - [ ] Update `NamespacedName.validate_namespace()` to allow underscores - [ ] Add Behave tests for underscore-containing namespace names - [ ] Verify consistency with `project.py` namespace validators - [ ] Verify all nox stages pass ### Definition of Done - [ ] `NamespacedName.parse("my_org/my-action")` succeeds - [ ] `NamespacedName(namespace="my_org", name="my-action")` succeeds - [ ] All existing tests pass --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.5.0 milestone 2026-04-08 18:05:38 +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.

Dependencies

No dependencies set.

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