Skip to content

feat(runtime): deterministic conflict path for subagent merges - #323

Merged
OBenner merged 2 commits into
developfrom
feat/subagent-conflict-resolution
Jun 10, 2026
Merged

feat(runtime): deterministic conflict path for subagent merges#323
OBenner merged 2 commits into
developfrom
feat/subagent-conflict-resolution

Conversation

@OBenner

@OBenner OBenner commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Context — Phase B / PR-4 of "mutating subagents → safe"

Stacked on #322 (parent-merge executor). Merge order: #322 first, then I'll retarget this PR to develop before you merge it — to avoid the #321 mishap where a stacked PR merged into an orphaned base.

Conflicts stop being a dead end — and stay deterministic: false positives auto-apply, real ones block finish until the parent resolves explicitly. No AI merging anywhere on this path (semantic AutoMerger strategies can be layered behind bold later).

What changes

1. Real-conflict refinement. The merge plan flags children by declared write-scope overlap; the executor now treats a child as conflicted only when its changeset's actual paths intersect another declared-conflicted child's actual paths. Overlapping scopes with disjoint edits — the common false positive — apply deterministically like any other child.

2. Finish-blocking conflict checkpoint. Real conflicts surface as conflicted_unresolved (now with conflict_paths) and register as pending on the parent session. Finish is vetoed — stop_reason=unresolved_subagent_conflicts, recoverable — until every pending conflict is resolved. Same rails as unresolved_partial_failure.

3. Explicit resolution actionresolve_subagent_conflict {result_id, resolution}:

  • apply merges that child's changeset onto the current workspace through the same baseline-verified transactional executor (recorded as subagent_merge:<id> — still rolls back as one unit). If a sibling already changed the file, the baseline check fails honestly: reconcile (e.g. rollback_transaction the sibling) and retry, or discard.
  • discard drops the changeset.
  • Validation errors list the pending ids; the action is mutating (blocked inside open batches), schema'd, and both prompt templates teach the rule.

Tests (4 new, 392 passed across the surface)

  • Declared-overlap + disjoint actual edits → both auto-apply (no conflict).
  • Finishing with pending conflicts → terminates recoverably, nothing lands on the workspace, session_state.stop_reason == unresolved_subagent_conflicts.
  • apply edit-a + discard edit-b → exactly edit-a's content lands (transaction id asserted), finish unblocked.
  • Resolve-action input validation (unknown id / bad resolution → pending list returned).

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@OBenner, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 14 minutes and 42 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: eb3fef1c-a378-462c-bbf3-03deea25c43b

📥 Commits

Reviewing files that changed from the base of the PR and between 65d10f6 and 36b734a.

📒 Files selected for processing (3)
  • apps/backend/agents/runtime/adapters/generic_edit.py
  • apps/backend/agents/runtime/local_actions.py
  • tests/test_agent_runtime.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/subagent-conflict-resolution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@OBenner
OBenner force-pushed the feat/subagent-conflict-resolution branch 2 times, most recently from d35c416 to bdced72 Compare June 10, 2026 08:16
OBenner and others added 2 commits June 10, 2026 12:27
Phase B / PR-4 of moving mutating parallel subagents toward `safe`
(stacked on #322's parent-merge executor). Conflicts stop being a dead
end: false positives auto-apply, real ones block finish until the parent
resolves them explicitly. No AI merging anywhere on this path.

- Real-conflict refinement: the merge plan flags children by DECLARED
  write-scope overlap; the executor now treats a child as conflicted only
  when its changeset's ACTUAL paths intersect another declared-conflicted
  child's actual paths. Overlapping scopes with disjoint edits — the
  common false positive — apply deterministically like any other child.
- Real conflicts surface as conflicted_unresolved (now with
  conflict_paths) and are registered as pending on the parent session.
  Finish is vetoed (stop_reason=unresolved_subagent_conflicts, recoverable)
  until every pending conflict is resolved.
- New local action resolve_subagent_conflict {result_id, resolution}:
  'apply' merges that child's changeset onto the CURRENT workspace through
  the same baseline-verified transactional executor (recorded as
  subagent_merge:<id>, so it still rolls back as one unit; a sibling that
  already changed the file makes the baseline check fail — reconcile and
  retry, or discard); 'discard' drops the changeset. Validation errors
  list the pending ids. The action is mutating (blocked inside open
  batches) and schema'd; both prompt templates teach the rule.

Tests: declared-overlap/disjoint-edit auto-apply; finishing with pending
conflicts terminates recoverably with nothing applied; apply+discard
resolutions land exactly the chosen child's content and unblock finish
(transaction id asserted); resolve-action input validation. 392 passed
across the affected surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>
The resolve_subagent_conflict apply path now reports
mutation_snapshot_ids / mutated_paths / affected_paths like an applied
run_subagents merge, so transaction summaries record the parent-side
mutation and later failures in the same turn become partial_failure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>
@OBenner
OBenner force-pushed the feat/subagent-conflict-resolution branch from bdced72 to 36b734a Compare June 10, 2026 08:27
@OBenner
OBenner changed the base branch from feat/subagent-parent-merge-develop to develop June 10, 2026 08:27
@github-actions github-actions Bot added size/XL and removed size/L labels Jun 10, 2026
@sonarqubecloud

Copy link
Copy Markdown

@OBenner
OBenner merged commit 7726338 into develop Jun 10, 2026
3 checks passed
OBenner added a commit that referenced this pull request Jun 10, 2026
Phase D / PR-7 — the final step of "mutating subagents -> safe" (stacked
on the PR-6 gate requirement). The protocol is no longer scaffolded:

- children are write-scope confined with runtime enforcement (#319),
- they stage mutations and export changesets without touching the shared
  workspace (#320),
- the parent applies each child transactionally with per-child rollback
  and baseline verification (#322),
- real conflicts are never auto-applied — they block finish until the
  parent resolves explicitly (#323),
- the whole mechanism is covered by the deterministic
  subagent_merge_probe (PR-5) which the promotion gate now requires
  (PR-6).

With that evidence chain in place, AutonomyLevel.SAFE now defaults
mutating_subagents_enabled=True. bold's remaining distinction is skipping
the evidence gate. The explicit AUTO_CODE_MUTATING_SUBAGENTS=false
override still opts out (covered by a new test), per ADR-006 precedence.

ADR-006's level table updated. The .env.example and UI level descriptions
live on the still-open #309/#318 branches and are updated there.

Tests: safe-level expectations flipped (autonomy level + direct-API
runtime policy grant); explicit env opt-out covered. 694 passed across
the affected surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>
OBenner added a commit that referenced this pull request Jun 10, 2026
Phase D / PR-7 — the final step of "mutating subagents -> safe" (stacked
on the PR-6 gate requirement). The protocol is no longer scaffolded:

- children are write-scope confined with runtime enforcement (#319),
- they stage mutations and export changesets without touching the shared
  workspace (#320),
- the parent applies each child transactionally with per-child rollback
  and baseline verification (#322),
- real conflicts are never auto-applied — they block finish until the
  parent resolves explicitly (#323),
- the whole mechanism is covered by the deterministic
  subagent_merge_probe (PR-5) which the promotion gate now requires
  (PR-6).

With that evidence chain in place, AutonomyLevel.SAFE now defaults
mutating_subagents_enabled=True. bold's remaining distinction is skipping
the evidence gate. The explicit AUTO_CODE_MUTATING_SUBAGENTS=false
override still opts out (covered by a new test), per ADR-006 precedence.

ADR-006's level table updated. The .env.example and UI level descriptions
live on the still-open #309/#318 branches and are updated there.

Tests: safe-level expectations flipped (autonomy level + direct-API
runtime policy grant); explicit env opt-out covered. 694 passed across
the affected surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>
OBenner added a commit that referenced this pull request Jun 10, 2026
…326)

* chore: retrigger CI after base retarget to develop

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>

* feat(autonomy): enable mutating parallel subagents at the safe level

Phase D / PR-7 — the final step of "mutating subagents -> safe" (stacked
on the PR-6 gate requirement). The protocol is no longer scaffolded:

- children are write-scope confined with runtime enforcement (#319),
- they stage mutations and export changesets without touching the shared
  workspace (#320),
- the parent applies each child transactionally with per-child rollback
  and baseline verification (#322),
- real conflicts are never auto-applied — they block finish until the
  parent resolves explicitly (#323),
- the whole mechanism is covered by the deterministic
  subagent_merge_probe (PR-5) which the promotion gate now requires
  (PR-6).

With that evidence chain in place, AutonomyLevel.SAFE now defaults
mutating_subagents_enabled=True. bold's remaining distinction is skipping
the evidence gate. The explicit AUTO_CODE_MUTATING_SUBAGENTS=false
override still opts out (covered by a new test), per ADR-006 precedence.

ADR-006's level table updated. The .env.example and UI level descriptions
live on the still-open #309/#318 branches and are updated there.

Tests: safe-level expectations flipped (autonomy level + direct-API
runtime policy grant); explicit env opt-out covered. 694 passed across
the affected surface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>

* chore: retrigger CI after base retarget to develop

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>

* chore: retrigger CI on develop base

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>

---------

Signed-off-by: Oleg Miagkov <mrobenner@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant