UAT: Merge conflicts from GIT_THREE_WAY strategy never surfaced to user — _apply_subplan_results_to_plan() ignores merge_result.conflict_files #6077

Open
opened 2026-04-09 14:25:54 +00:00 by HAL9000 · 0 comments
Owner

Bug Report

Feature Area: Three-Way Merge (v3.3.0 Deliverable #6)
Spec Reference: §Merge Strategies — Conflict Resolution
Severity: Critical — blocks v3.3.0 milestone acceptance


What Was Tested

v3.3.0 Deliverable #6: "Merge conflicts surfaced to user for resolution — Conflicting changes produce CONFLICT markers; user prompted"

Tested by tracing the full execution path from SubplanExecutionService.execute_all() through PlanExecutor._apply_subplan_results_to_plan() to the CLI agents plan execute output.


Expected Behavior (from spec)

Per §Merge Strategies — Conflict Resolution and v3.3.0 deliverable #6:

Conflicting changes produce CONFLICT markers; user prompted

When two subplans produce conflicting edits to the same file and the GIT_THREE_WAY strategy is used, the system should:

  1. Detect the conflict (conflict markers in merged content)
  2. Surface the conflict to the user (e.g., print which files have conflicts, prompt for resolution)
  3. Block agents plan apply until conflicts are resolved

Actual Behavior

The merge_result is computed but never inspected in the plan executor.

Code Path

  1. SubplanExecutionService.execute_all() correctly computes merge_result (a SubplanMergeResult with conflict_files populated when conflicts exist):

    # subplan_execution_service.py:234
    merge_result = self._merge_service.merge(base_files, successful_outputs)
    
  2. The result is stored in SubplanExecutionResult.merge_result.

  3. PlanExecutor._apply_subplan_results_to_plan() (plan_executor.py:522–560) never reads exec_result.merge_result:

    def _apply_subplan_results_to_plan(self, plan, spawn_result, exec_result):
        if exec_result is None:
            plan.subplan_statuses = list(spawn_result.spawned_statuses)
            return
        plan.subplan_statuses = list(exec_result.statuses)
        if not exec_result.all_succeeded:
            failed = exec_result.failed_subplan_ids
            existing = dict(plan.error_details or {})
            existing["failed_subplan_ids"] = ",".join(failed)
            existing["subplan_execution_failed"] = "true"
            plan.error_details = existing
        # ← merge_result.conflict_files is NEVER checked here
    
  4. The CLI agents plan execute output (plan.py:2122–2137) shows no conflict information.

Result

When two subplans produce conflicting edits to the same file:

  • The merged content contains <<<<<<< / ======= / >>>>>>> conflict markers
  • The plan proceeds to execute/complete state as if nothing is wrong
  • agents plan apply will apply the conflict-marker-laden content to the real filesystem
  • The user is never informed that conflicts exist

Steps to Reproduce

from cleveragents.application.services.subplan_merge_service import SubplanMergeService
from cleveragents.domain.models.core.plan import SubplanMergeStrategy

svc = SubplanMergeService(SubplanMergeStrategy.GIT_THREE_WAY)
result = svc.merge(
    base_files={"file.py": "x = 1\n"},
    subplan_outputs=[
        ("sp1", {"file.py": "x = 'alpha'\n"}),
        ("sp2", {"file.py": "x = 'beta'\n"}),
    ]
)
print(result.conflict_files)   # ['file.py']
print(result.success)          # False
# But PlanExecutor never checks this result

Code Locations

  • src/cleveragents/application/services/plan_executor.py:522–560_apply_subplan_results_to_plan() — missing conflict check
  • src/cleveragents/application/services/plan_executor.py:883–884 — call site where exec_result is obtained but merge_result discarded
  • src/cleveragents/application/services/subplan_execution_service.py:230–244merge_result correctly computed but not propagated
  • src/cleveragents/cli/commands/plan.py:2122–2137 — execute output — no conflict display

Fix Required

_apply_subplan_results_to_plan() must:

  1. Check exec_result.merge_result for conflict_files
  2. Store conflict information in plan.error_details (e.g., "merge_conflict_files": "file1.py,file2.py")
  3. Set plan state to a conflict-pending state (or at minimum prevent apply when conflicts exist)

The CLI agents plan execute output must display conflict information when merge_result.conflict_files is non-empty, prompting the user to resolve conflicts before applying.


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

## Bug Report **Feature Area**: Three-Way Merge (v3.3.0 Deliverable #6) **Spec Reference**: §Merge Strategies — Conflict Resolution **Severity**: Critical — blocks v3.3.0 milestone acceptance --- ## What Was Tested v3.3.0 Deliverable #6: "Merge conflicts surfaced to user for resolution — Conflicting changes produce `CONFLICT` markers; user prompted" Tested by tracing the full execution path from `SubplanExecutionService.execute_all()` through `PlanExecutor._apply_subplan_results_to_plan()` to the CLI `agents plan execute` output. --- ## Expected Behavior (from spec) Per §Merge Strategies — Conflict Resolution and v3.3.0 deliverable #6: > Conflicting changes produce `CONFLICT` markers; user prompted When two subplans produce conflicting edits to the same file and the `GIT_THREE_WAY` strategy is used, the system should: 1. Detect the conflict (conflict markers in merged content) 2. Surface the conflict to the user (e.g., print which files have conflicts, prompt for resolution) 3. Block `agents plan apply` until conflicts are resolved --- ## Actual Behavior **The `merge_result` is computed but never inspected in the plan executor.** ### Code Path 1. `SubplanExecutionService.execute_all()` correctly computes `merge_result` (a `SubplanMergeResult` with `conflict_files` populated when conflicts exist): ```python # subplan_execution_service.py:234 merge_result = self._merge_service.merge(base_files, successful_outputs) ``` 2. The result is stored in `SubplanExecutionResult.merge_result`. 3. **`PlanExecutor._apply_subplan_results_to_plan()` (plan_executor.py:522–560) never reads `exec_result.merge_result`:** ```python def _apply_subplan_results_to_plan(self, plan, spawn_result, exec_result): if exec_result is None: plan.subplan_statuses = list(spawn_result.spawned_statuses) return plan.subplan_statuses = list(exec_result.statuses) if not exec_result.all_succeeded: failed = exec_result.failed_subplan_ids existing = dict(plan.error_details or {}) existing["failed_subplan_ids"] = ",".join(failed) existing["subplan_execution_failed"] = "true" plan.error_details = existing # ← merge_result.conflict_files is NEVER checked here ``` 4. The CLI `agents plan execute` output (plan.py:2122–2137) shows no conflict information. ### Result When two subplans produce conflicting edits to the same file: - The merged content contains `<<<<<<< / ======= / >>>>>>>` conflict markers - The plan proceeds to `execute/complete` state as if nothing is wrong - `agents plan apply` will apply the conflict-marker-laden content to the real filesystem - The user is never informed that conflicts exist --- ## Steps to Reproduce ```python from cleveragents.application.services.subplan_merge_service import SubplanMergeService from cleveragents.domain.models.core.plan import SubplanMergeStrategy svc = SubplanMergeService(SubplanMergeStrategy.GIT_THREE_WAY) result = svc.merge( base_files={"file.py": "x = 1\n"}, subplan_outputs=[ ("sp1", {"file.py": "x = 'alpha'\n"}), ("sp2", {"file.py": "x = 'beta'\n"}), ] ) print(result.conflict_files) # ['file.py'] print(result.success) # False # But PlanExecutor never checks this result ``` --- ## Code Locations - `src/cleveragents/application/services/plan_executor.py:522–560` — `_apply_subplan_results_to_plan()` — missing conflict check - `src/cleveragents/application/services/plan_executor.py:883–884` — call site where `exec_result` is obtained but `merge_result` discarded - `src/cleveragents/application/services/subplan_execution_service.py:230–244` — `merge_result` correctly computed but not propagated - `src/cleveragents/cli/commands/plan.py:2122–2137` — execute output — no conflict display --- ## Fix Required `_apply_subplan_results_to_plan()` must: 1. Check `exec_result.merge_result` for `conflict_files` 2. Store conflict information in `plan.error_details` (e.g., `"merge_conflict_files": "file1.py,file2.py"`) 3. Set plan state to a conflict-pending state (or at minimum prevent `apply` when conflicts exist) The CLI `agents plan execute` output must display conflict information when `merge_result.conflict_files` is non-empty, prompting the user to resolve conflicts before applying. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.3.0 milestone 2026-04-09 15:05:42 +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#6077
No description provided.