UAT: Child plans spawned by SubplanService do not inherit parent's reconciled invariant view — spec requires propagation without re-reconciliation #5117

Open
opened 2026-04-09 01:05:51 +00:00 by HAL9000 · 1 comment
Owner

Bug Report

Feature Area: Validation and Invariants — Invariant Propagation to Child Plans
Tested By: UAT worker (uat-pool-1), feature area: Validation and Invariants
Severity: Medium — child plans re-run invariant reconciliation instead of inheriting the parent's resolved view


What Was Tested

Code-level analysis of child plan spawning in:

  • src/cleveragents/application/services/subplan_service.py
  • src/cleveragents/application/services/plan_lifecycle_service.py

Expected Behavior (from spec)

The spec (§Invariant System, line 19751) states:

Child plan inheritance: When a top-level plan spawns child plans, the parent's effective invariant view (already reconciled) is passed down to each child plan. Child plans do not re-run reconciliation — they inherit the parent's resolved view.

This means:

  1. When a parent plan spawns child plans, the parent's already-reconciled InvariantSet should be copied to each child plan.
  2. The InvariantReconciliationActor should NOT be invoked for child plans — they use the parent's resolved view directly.

Actual Behavior

SubplanService.spawn (subplan_service.py, lines 260–283)

When child plans are created, the Plan constructor is called without the parent's invariants:

child_plan: Plan = Plan(
    identity=PlanIdentity(
        plan_id=subplan_id,
        parent_plan_id=parent_id,
        root_plan_id=root_id,
    ),
    ...
    project_links=list(parent_plan.project_links),
    # ← invariants=parent_plan.invariants is MISSING
    # ← invariant_actor=parent_plan.invariant_actor is MISSING
)

Child plans are created with invariants=[] (the default), meaning they start with no invariants.

PlanLifecycleService._run_invariant_reconciliation

The reconciliation method does not check whether a plan is a child plan. When a child plan enters the Strategize phase, _run_invariant_reconciliation is called and the InvariantReconciliationActor runs fresh reconciliation — collecting invariants from global, project, and action scopes and re-resolving conflicts.

This means child plans:

  1. Do NOT inherit the parent's resolved invariant view
  2. DO re-run reconciliation (violating the spec)
  3. May produce a different effective invariant set than the parent (if invariants were added/removed between parent and child reconciliation)

Impact

  1. Spec compliance: The spec explicitly requires child plans to inherit the parent's resolved view without re-reconciliation.
  2. Consistency: If invariants change between parent and child reconciliation (e.g., a global invariant is added/removed), child plans may operate under different constraints than the parent intended.
  3. Performance: Unnecessary reconciliation work is done for each child plan.
  4. Auditability: The spec's model ensures child plans' invariant_enforced decisions trace back to the parent's reconciliation. With re-reconciliation, the audit trail is fragmented.

Code Locations

  • src/cleveragents/application/services/subplan_service.py:
    • Lines 260–283: Plan constructor call — missing invariants=parent_plan.invariants and invariant_actor=parent_plan.invariant_actor
  • src/cleveragents/application/services/plan_lifecycle_service.py:
    • _run_invariant_reconciliation — no check for child plan status

Fix Required

  1. In SubplanService.spawn, pass the parent's invariants and invariant_actor to child plans:

    child_plan: Plan = Plan(
        ...
        invariants=list(parent_plan.invariants),  # Inherit parent's invariants
        invariant_actor=parent_plan.invariant_actor,  # Inherit actor reference
    )
    
  2. In PlanLifecycleService._run_invariant_reconciliation, skip reconciliation for child plans (those with a non-None parent_plan_id):

    # Skip reconciliation for child plans — they inherit parent's resolved view
    if plan.identity.parent_plan_id is not None:
        return
    

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

## Bug Report **Feature Area**: Validation and Invariants — Invariant Propagation to Child Plans **Tested By**: UAT worker (uat-pool-1), feature area: Validation and Invariants **Severity**: Medium — child plans re-run invariant reconciliation instead of inheriting the parent's resolved view --- ## What Was Tested Code-level analysis of child plan spawning in: - `src/cleveragents/application/services/subplan_service.py` - `src/cleveragents/application/services/plan_lifecycle_service.py` ## Expected Behavior (from spec) The spec (§Invariant System, line 19751) states: > **Child plan inheritance**: When a top-level plan spawns child plans, the parent's effective invariant view (already reconciled) is passed down to each child plan. **Child plans do not re-run reconciliation** — they inherit the parent's resolved view. This means: 1. When a parent plan spawns child plans, the parent's already-reconciled `InvariantSet` should be copied to each child plan. 2. The `InvariantReconciliationActor` should NOT be invoked for child plans — they use the parent's resolved view directly. ## Actual Behavior ### `SubplanService.spawn` (`subplan_service.py`, lines 260–283) When child plans are created, the `Plan` constructor is called **without** the parent's invariants: ```python child_plan: Plan = Plan( identity=PlanIdentity( plan_id=subplan_id, parent_plan_id=parent_id, root_plan_id=root_id, ), ... project_links=list(parent_plan.project_links), # ← invariants=parent_plan.invariants is MISSING # ← invariant_actor=parent_plan.invariant_actor is MISSING ) ``` Child plans are created with `invariants=[]` (the default), meaning they start with no invariants. ### `PlanLifecycleService._run_invariant_reconciliation` The reconciliation method does not check whether a plan is a child plan. When a child plan enters the Strategize phase, `_run_invariant_reconciliation` is called and the `InvariantReconciliationActor` runs fresh reconciliation — collecting invariants from global, project, and action scopes and re-resolving conflicts. This means child plans: 1. Do NOT inherit the parent's resolved invariant view 2. DO re-run reconciliation (violating the spec) 3. May produce a different effective invariant set than the parent (if invariants were added/removed between parent and child reconciliation) ## Impact 1. **Spec compliance**: The spec explicitly requires child plans to inherit the parent's resolved view without re-reconciliation. 2. **Consistency**: If invariants change between parent and child reconciliation (e.g., a global invariant is added/removed), child plans may operate under different constraints than the parent intended. 3. **Performance**: Unnecessary reconciliation work is done for each child plan. 4. **Auditability**: The spec's model ensures child plans' `invariant_enforced` decisions trace back to the parent's reconciliation. With re-reconciliation, the audit trail is fragmented. ## Code Locations - `src/cleveragents/application/services/subplan_service.py`: - Lines 260–283: `Plan` constructor call — missing `invariants=parent_plan.invariants` and `invariant_actor=parent_plan.invariant_actor` - `src/cleveragents/application/services/plan_lifecycle_service.py`: - `_run_invariant_reconciliation` — no check for child plan status ## Fix Required 1. In `SubplanService.spawn`, pass the parent's invariants and invariant_actor to child plans: ```python child_plan: Plan = Plan( ... invariants=list(parent_plan.invariants), # Inherit parent's invariants invariant_actor=parent_plan.invariant_actor, # Inherit actor reference ) ``` 2. In `PlanLifecycleService._run_invariant_reconciliation`, skip reconciliation for child plans (those with a non-None `parent_plan_id`): ```python # Skip reconciliation for child plans — they inherit parent's resolved view if plan.identity.parent_plan_id is not None: return ``` --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.2.0 milestone 2026-04-09 01:10:58 +00:00
Author
Owner

Issue triaged by project owner: Verified as valid spec compliance bug. Priority: Medium. Milestone: v3.2.0.


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

Issue triaged by project owner: Verified as valid spec compliance bug. Priority: Medium. Milestone: v3.2.0. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner
HAL9000 modified the milestone from v3.2.0 to v3.3.0 2026-04-09 01:11:49 +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.

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