BUG-HUNT: [consistency] Actor namespace collision between user-defined and built-in actors due to case normalization #7127

Open
opened 2026-04-10 08:00:20 +00:00 by HAL9000 · 1 comment
Owner

Metadata

  • Branch: bugfix/actor-registry-namespace-case-normalization-collision
  • Commit Message: fix(actor): apply consistent case normalization in ActorRegistry to prevent namespace collisions between user-defined and built-in actors
  • Milestone: (none — backlog, see note below)
  • Parent Epic: #396

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

Background and Context

There is an inconsistency in namespace validation and normalization in src/cleveragents/actor/registry.py that can cause silent collisions between user-defined actors and auto-generated built-in actors. The system applies different naming rules to different actor types, creating potential conflicts that are difficult to diagnose.

The root cause is that _actor_name() (used for built-in actors) applies .lower() to both provider and model name components, while _ensure_namespaced() (used for user-defined actors) performs no case normalization at all.

Current Behavior

Two code paths produce actor keys with different case handling:

def _actor_name(self, provider_name: str, model_name: str) -> str:
    """Build a canonical ``namespace/identifier`` actor name."""
    sanitized_provider = provider_name.replace("/", "-").lower()  # LOWERCASED
    sanitized_model = model_name.replace("/", "-").lower()        # LOWERCASED
    return f"{sanitized_provider}/{sanitized_model}"

@staticmethod
def _ensure_namespaced(name: str) -> str:
    """Ensure *name* follows the ``namespace/identifier`` convention."""
    if "/" not in name:
        return f"local/{name}"  # NO CASE NORMALIZATION
    return name                 # NO CASE NORMALIZATION

Collision Scenario:

  1. User creates a custom actor with name "Local/Test" → stored as "Local/Test"
  2. User references actor as "Test" (no namespace) → _ensure_namespaced("Test")"local/test" (auto-prefixed with lowercase "local/")
  3. Provider registry generates built-in actor → _actor_name("Local", "Test")"local/test"
  4. COLLISION: Both resolve to the same key "local/test" but represent different actors

Additionally, the docstring in _actor_name() explicitly acknowledges a breaking change:

"Lowercasing is a behavior change — previously mixed-case built-in actors (e.g. OpenAI/gpt-4) were stored as-is. After this fix they are superseded by lowercased versions on the next ensure_built_in_actors() call."

This means existing configurations that stored actors under mixed-case keys (e.g., "OpenAI/gpt-4") will silently lose their registrations on the next startup.

Expected Behavior

Actor name normalization must be consistent across all code paths. Either:

  1. All actor names (user-defined and built-in) are normalized to lowercase at registration and lookup time, OR
  2. Case-sensitive comparison is used consistently everywhere with no implicit lowercasing

The schema.py validation (requires exactly one / with non-empty parts) does not prevent "Local" vs "local" namespace conflicts, so normalization must happen at the registry layer.

Acceptance Criteria

  • _ensure_namespaced() applies the same case normalization as _actor_name() (or both are updated to a shared normalization function)
  • A user-defined actor named "Local/Test" and a built-in actor generated from provider "Local" / model "Test" do not collide
  • Existing actors stored under mixed-case keys are migrated or a migration guide is provided
  • The breaking change noted in the _actor_name() docstring is documented in the changelog

Supporting Information

  • File: src/cleveragents/actor/registry.py
  • Methods: _actor_name() (~lines 50–65), _ensure_namespaced() (~lines 70–75)
  • Related issue: #7095 (race condition in ensure_built_in_actors() — same file, same method area)
  • Schema validation gap: schema.py validates format but not case-normalized uniqueness

Subtasks

  • Audit all call sites of _ensure_namespaced() and _actor_name() to understand full impact
  • Implement a shared _normalize_actor_name() helper that applies consistent lowercasing and / sanitization
  • Update _ensure_namespaced() to use the shared normalization helper
  • Update _actor_name() to use the shared normalization helper
  • Add a database migration or startup migration to normalize existing mixed-case actor keys
  • Tests (Behave): Add scenarios for namespace collision detection and case normalization consistency
  • Tests (Robot): Add integration test verifying user-defined and built-in actor names do not collide
  • Update changelog to document the breaking change for mixed-case actor names
  • 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.
  • 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: Bug Hunt Cycle 2 Batch 2 | Agent: new-issue-creator

## Metadata - **Branch**: `bugfix/actor-registry-namespace-case-normalization-collision` - **Commit Message**: `fix(actor): apply consistent case normalization in ActorRegistry to prevent namespace collisions between user-defined and built-in actors` - **Milestone**: *(none — backlog, see note below)* - **Parent Epic**: #396 > **Backlog note:** This issue was discovered during autonomous operation > on milestone v3.4.0. It does not block milestone completion and has been > placed in the backlog for human review and future milestone assignment. ## Background and Context There is an inconsistency in namespace validation and normalization in `src/cleveragents/actor/registry.py` that can cause silent collisions between user-defined actors and auto-generated built-in actors. The system applies different naming rules to different actor types, creating potential conflicts that are difficult to diagnose. The root cause is that `_actor_name()` (used for built-in actors) applies `.lower()` to both provider and model name components, while `_ensure_namespaced()` (used for user-defined actors) performs no case normalization at all. ## Current Behavior Two code paths produce actor keys with different case handling: ```python def _actor_name(self, provider_name: str, model_name: str) -> str: """Build a canonical ``namespace/identifier`` actor name.""" sanitized_provider = provider_name.replace("/", "-").lower() # LOWERCASED sanitized_model = model_name.replace("/", "-").lower() # LOWERCASED return f"{sanitized_provider}/{sanitized_model}" @staticmethod def _ensure_namespaced(name: str) -> str: """Ensure *name* follows the ``namespace/identifier`` convention.""" if "/" not in name: return f"local/{name}" # NO CASE NORMALIZATION return name # NO CASE NORMALIZATION ``` **Collision Scenario:** 1. User creates a custom actor with name `"Local/Test"` → stored as `"Local/Test"` 2. User references actor as `"Test"` (no namespace) → `_ensure_namespaced("Test")` → `"local/test"` (auto-prefixed with lowercase `"local/"`) 3. Provider registry generates built-in actor → `_actor_name("Local", "Test")` → `"local/test"` 4. **COLLISION**: Both resolve to the same key `"local/test"` but represent different actors Additionally, the docstring in `_actor_name()` explicitly acknowledges a breaking change: > *"Lowercasing is a behavior change — previously mixed-case built-in actors (e.g. `OpenAI/gpt-4`) were stored as-is. After this fix they are superseded by lowercased versions on the next `ensure_built_in_actors()` call."* This means existing configurations that stored actors under mixed-case keys (e.g., `"OpenAI/gpt-4"`) will silently lose their registrations on the next startup. ## Expected Behavior Actor name normalization must be consistent across all code paths. Either: 1. All actor names (user-defined and built-in) are normalized to lowercase at registration and lookup time, OR 2. Case-sensitive comparison is used consistently everywhere with no implicit lowercasing The `schema.py` validation (requires exactly one `/` with non-empty parts) does not prevent `"Local"` vs `"local"` namespace conflicts, so normalization must happen at the registry layer. ## Acceptance Criteria - [ ] `_ensure_namespaced()` applies the same case normalization as `_actor_name()` (or both are updated to a shared normalization function) - [ ] A user-defined actor named `"Local/Test"` and a built-in actor generated from provider `"Local"` / model `"Test"` do not collide - [ ] Existing actors stored under mixed-case keys are migrated or a migration guide is provided - [ ] The breaking change noted in the `_actor_name()` docstring is documented in the changelog ## Supporting Information - **File**: `src/cleveragents/actor/registry.py` - **Methods**: `_actor_name()` (~lines 50–65), `_ensure_namespaced()` (~lines 70–75) - **Related issue**: #7095 (race condition in `ensure_built_in_actors()` — same file, same method area) - **Schema validation gap**: `schema.py` validates format but not case-normalized uniqueness ## Subtasks - [ ] Audit all call sites of `_ensure_namespaced()` and `_actor_name()` to understand full impact - [ ] Implement a shared `_normalize_actor_name()` helper that applies consistent lowercasing and `/` sanitization - [ ] Update `_ensure_namespaced()` to use the shared normalization helper - [ ] Update `_actor_name()` to use the shared normalization helper - [ ] Add a database migration or startup migration to normalize existing mixed-case actor keys - [ ] Tests (Behave): Add scenarios for namespace collision detection and case normalization consistency - [ ] Tests (Robot): Add integration test verifying user-defined and built-in actor names do not collide - [ ] Update changelog to document the breaking change for mixed-case actor names - [ ] 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. - 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: Bug Hunt Cycle 2 Batch 2 | Agent: new-issue-creator
Author
Owner

Verified — Critical consistency bug: actor namespace collision. MoSCoW: Must-have. Priority: Critical.


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

✅ **Verified** — Critical consistency bug: actor namespace collision. MoSCoW: Must-have. Priority: Critical. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
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#7127
No description provided.