UAT: SubplanService.spawn() generates duplicate child plan names when spawning multiple subplans in rapid succession #3749

Open
opened 2026-04-05 22:28:14 +00:00 by freemo · 0 comments
Owner

Background and Context

SubplanService.spawn() in application/services/subplan_service.py generates child plan names using f"subplan-{subplan_id[:8]}" (line 269). The subplan_id is a full ULID (26 characters), but only the first 8 characters are used for the name. The first 10 characters of a ULID represent the timestamp component, and ULIDs generated within the same millisecond share the same first 8 timestamp characters.

Current Behavior

When spawn() is called with multiple SpawnEntry objects (e.g., 3 entries), all child plans generated in the same millisecond receive identical namespaced_name values:

local/subplan-01knfvvv
local/subplan-01knfvvv
local/subplan-01knfvvv

This was confirmed by runtime testing:

result = svc.spawn(parent_plan=plan, config=config, spawn_entries=entries)
names = [str(c.namespaced_name) for c in result.child_plans]
# names = ['local/subplan-01knfvvv', 'local/subplan-01knfvvv', 'local/subplan-01knfvvv']
assert len(names) == len(set(names))  # FAILS: Duplicate names

The plan_id (full ULID) values are unique, but the derived names are not.

Expected Behavior

Each spawned child plan should have a unique namespaced_name. The name should use enough characters from the ULID to guarantee uniqueness, or use a different approach (e.g., using the full ULID, or appending a sequence number).

Steps to Reproduce

from cleveragents.application.services.subplan_service import SubplanService, SpawnEntry
from cleveragents.domain.models.core.decision import Decision, DecisionType, ContextSnapshot
from cleveragents.domain.models.core.plan import ExecutionMode, NamespacedName, Plan, PlanIdentity, SubplanConfig
from unittest.mock import MagicMock

mock_ds = MagicMock()
svc = SubplanService(decision_service=mock_ds)
plan = Plan(
    identity=PlanIdentity(plan_id='01HGZ6FE0AQDYTR4BXVQZ6PN00'),
    namespaced_name=NamespacedName(namespace='local', name='test-plan'),
    description='Test plan',
    action_name='local/test-action',
)
entries = [
    SpawnEntry(
        decision=Decision(
            decision_id=f'01HGZ6FE0AQDYTR4BXVQZ6D0{i}0',
            plan_id='01HGZ6FE0AQDYTR4BXVQZ6PN00',
            decision_type=DecisionType.SUBPLAN_SPAWN,
            sequence_number=i,
            question='Spawn?',
            chosen_option='local/sub-action',
            context_snapshot=ContextSnapshot(relevant_resources=[]),
        ),
        action_name='local/sub-action',
    )
    for i in range(3)
]
config = SubplanConfig(execution_mode=ExecutionMode.SEQUENTIAL)
result = svc.spawn(parent_plan=plan, config=config, spawn_entries=entries)
names = [str(c.namespaced_name) for c in result.child_plans]
print(names)  # ['local/subplan-01knfvvv', 'local/subplan-01knfvvv', 'local/subplan-01knfvvv']

Code Location

src/cleveragents/application/services/subplan_service.py, line 269:

name=f"subplan-{subplan_id[:8]}",

Suggested Fix

Use more characters from the ULID to include the random portion, or use a sequence-based suffix:

name=f"subplan-{subplan_id[:16]}",  # Includes some random bits
# or
name=f"subplan-{subplan_id.lower()[:16]}",

Alternatively, use a counter-based approach to guarantee uniqueness within a spawn batch.

Metadata

  • Branch: fix/subplan-duplicate-names
  • Commit Message: fix(subplan): use unique name suffix when spawning multiple child plans
  • Milestone: Backlog
  • Parent Epic: #368

Subtasks

  • Fix SubplanService.spawn() to generate unique child plan names
  • Add/update unit tests to verify name uniqueness when spawning multiple subplans
  • Run nox to verify all tests pass

Definition of Done

  • Child plan names are unique when multiple subplans are spawned in the same call
  • Unit tests verify uniqueness
  • nox passes
  • All nox stages pass
  • Coverage >= 97%

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.


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

## Background and Context `SubplanService.spawn()` in `application/services/subplan_service.py` generates child plan names using `f"subplan-{subplan_id[:8]}"` (line 269). The `subplan_id` is a full ULID (26 characters), but only the first 8 characters are used for the name. The first 10 characters of a ULID represent the timestamp component, and ULIDs generated within the same millisecond share the same first 8 timestamp characters. ## Current Behavior When `spawn()` is called with multiple `SpawnEntry` objects (e.g., 3 entries), all child plans generated in the same millisecond receive identical `namespaced_name` values: ``` local/subplan-01knfvvv local/subplan-01knfvvv local/subplan-01knfvvv ``` This was confirmed by runtime testing: ```python result = svc.spawn(parent_plan=plan, config=config, spawn_entries=entries) names = [str(c.namespaced_name) for c in result.child_plans] # names = ['local/subplan-01knfvvv', 'local/subplan-01knfvvv', 'local/subplan-01knfvvv'] assert len(names) == len(set(names)) # FAILS: Duplicate names ``` The `plan_id` (full ULID) values are unique, but the derived names are not. ## Expected Behavior Each spawned child plan should have a unique `namespaced_name`. The name should use enough characters from the ULID to guarantee uniqueness, or use a different approach (e.g., using the full ULID, or appending a sequence number). ## Steps to Reproduce ```python from cleveragents.application.services.subplan_service import SubplanService, SpawnEntry from cleveragents.domain.models.core.decision import Decision, DecisionType, ContextSnapshot from cleveragents.domain.models.core.plan import ExecutionMode, NamespacedName, Plan, PlanIdentity, SubplanConfig from unittest.mock import MagicMock mock_ds = MagicMock() svc = SubplanService(decision_service=mock_ds) plan = Plan( identity=PlanIdentity(plan_id='01HGZ6FE0AQDYTR4BXVQZ6PN00'), namespaced_name=NamespacedName(namespace='local', name='test-plan'), description='Test plan', action_name='local/test-action', ) entries = [ SpawnEntry( decision=Decision( decision_id=f'01HGZ6FE0AQDYTR4BXVQZ6D0{i}0', plan_id='01HGZ6FE0AQDYTR4BXVQZ6PN00', decision_type=DecisionType.SUBPLAN_SPAWN, sequence_number=i, question='Spawn?', chosen_option='local/sub-action', context_snapshot=ContextSnapshot(relevant_resources=[]), ), action_name='local/sub-action', ) for i in range(3) ] config = SubplanConfig(execution_mode=ExecutionMode.SEQUENTIAL) result = svc.spawn(parent_plan=plan, config=config, spawn_entries=entries) names = [str(c.namespaced_name) for c in result.child_plans] print(names) # ['local/subplan-01knfvvv', 'local/subplan-01knfvvv', 'local/subplan-01knfvvv'] ``` ## Code Location `src/cleveragents/application/services/subplan_service.py`, line 269: ```python name=f"subplan-{subplan_id[:8]}", ``` ## Suggested Fix Use more characters from the ULID to include the random portion, or use a sequence-based suffix: ```python name=f"subplan-{subplan_id[:16]}", # Includes some random bits # or name=f"subplan-{subplan_id.lower()[:16]}", ``` Alternatively, use a counter-based approach to guarantee uniqueness within a spawn batch. ## Metadata - **Branch**: `fix/subplan-duplicate-names` - **Commit Message**: `fix(subplan): use unique name suffix when spawning multiple child plans` - **Milestone**: Backlog - **Parent Epic**: #368 ## Subtasks - [ ] Fix `SubplanService.spawn()` to generate unique child plan names - [ ] Add/update unit tests to verify name uniqueness when spawning multiple subplans - [ ] Run `nox` to verify all tests pass ## Definition of Done - [ ] Child plan names are unique when multiple subplans are spawned in the same call - [ ] Unit tests verify uniqueness - [ ] `nox` passes - All nox stages pass - Coverage >= 97% > **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. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
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
#368 Epic: Subplans & Parallelism
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3749
No description provided.