feat(runtime): export mutating-subagent changes as staged changesets#320
Conversation
Phase A / PR-2 of moving mutating parallel subagents toward `safe` (follows #319's write-scope enforcement). A transactional_write child no longer needs to touch the shared workspace at all: its mutations are auto-staged and exported as a changeset the parent will apply transactionally (Phase B). - GenericEditRuntimeSession(changeset_export=True): mutations auto-stage into the runtime-owned __changeset__ batch (existing staged-batch mechanics: materialize-per-action + restore, so the real workspace stays at baseline between actions and after finish). Model-issued begin/commit/abort batch is rejected — staging is runtime-owned. At a clean finish the staged pre/postimages are finalized into a changeset payload (first preimage + last postimage per path, exportability via the existing materializability predicate) returned on AgentRunResult.changeset; the open-batch finish veto now applies only to model-managed batches. Error/recovery finishes export nothing. - Orchestrator: mutating children must be changeset-exporting (the confinement check refuses directly-writing sessions); children run against execution requirements (generic_edit for mutating tasks) since task.requirements is the parent-side policy gate, not what the child session physically does; every child gets a per-child artifact namespace (artifacts/subagents/<task-id>/) so a runtime child never clobbers the parent's — or a sibling's — generic_edit trace/checkpoint artifacts. RuntimeSubagentResult.changeset is persisted in the per-child artifact, and the merge plan now records changeset_result_ids / missing_changeset_result_ids for the Phase B executor. - Production wiring (agents/coder.py): the subagent session factory builds a confined changeset-exporting generic_edit child for transactional_write tasks (write_scope_guard from the task), keeping analysis_only for read-only children. Tests: changeset export leaves the workspace untouched (edit + create paths, pre/postimages asserted); model batch control rejected without poisoning staging; an end-to-end orchestrator run with a REAL confined generic_edit child (changeset in result + per-child artifact, child runtime artifacts namespaced, merge plan updated); confined-but- directly-writing child refused. 382 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>
|
Warning Review limit reached
More reviews will be available in 3 minutes and 51 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 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
…sets (#321) Phase B / PR-3 of moving mutating parallel subagents toward `safe` (stacked on #320's changeset export). The merge plan is no longer just descriptive: after a run_subagents run whose plan requires a parent merge, the parent now APPLIES each child's exported changeset transactionally. - execute_subagent_changeset_merge: each mutating child is one transaction boundary. Its changeset is scope-revalidated (defense-in-depth against a tampered payload), baseline-verified (every entry's preimage must still match the live workspace via the existing drift comparator — an unverifiable baseline refuses the merge just like real drift), then applied as a unit. A mid-apply failure restores that child's captured baseline in reverse order; siblings are unaffected. Conflicted children are NEVER auto-applied — they surface as conflicted_unresolved for explicit resolution (deterministic AutoMerger routing lands in PR-4). - Each applied child is recorded as a parent mutation snapshot with transaction id subagent_merge:<child-id>, so the parent's existing rollback_transaction tool can undo exactly one child's merge. - run_subagents now reports merge_plan + merge_execution in its action data; the action only stays ok when every appliable changeset applied (applied/noop). Mutating delegation inside an open model-managed batch is refused up front (mutating_subagents_in_open_batch) before any child spawns. Tests: end-to-end parent run (real confined changeset child; file lands on the shared workspace via the parent; merge_execution recorded with the per-child transaction id), baseline drift refused with workspace intact, mid-apply failure rolled back (first entry restored), applied child undone via rollback_transaction, conflicted children kept unapplied, and delegation refused inside an open parent batch. Signed-off-by: Oleg Miagkov <mrobenner@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sets (#322) * feat(runtime): execute the transactional parent merge of child changesets Phase B / PR-3 of moving mutating parallel subagents toward `safe` (stacked on #320's changeset export). The merge plan is no longer just descriptive: after a run_subagents run whose plan requires a parent merge, the parent now APPLIES each child's exported changeset transactionally. - execute_subagent_changeset_merge: each mutating child is one transaction boundary. Its changeset is scope-revalidated (defense-in-depth against a tampered payload), baseline-verified (every entry's preimage must still match the live workspace via the existing drift comparator — an unverifiable baseline refuses the merge just like real drift), then applied as a unit. A mid-apply failure restores that child's captured baseline in reverse order; siblings are unaffected. Conflicted children are NEVER auto-applied — they surface as conflicted_unresolved for explicit resolution (deterministic AutoMerger routing lands in PR-4). - Each applied child is recorded as a parent mutation snapshot with transaction id subagent_merge:<child-id>, so the parent's existing rollback_transaction tool can undo exactly one child's merge. - run_subagents now reports merge_plan + merge_execution in its action data; the action only stays ok when every appliable changeset applied (applied/noop). Mutating delegation inside an open model-managed batch is refused up front (mutating_subagents_in_open_batch) before any child spawns. Tests: end-to-end parent run (real confined changeset child; file lands on the shared workspace via the parent; merge_execution recorded with the per-child transaction id), baseline drift refused with workspace intact, mid-apply failure rolled back (first entry restored), applied child undone via rollback_transaction, conflicted children kept unapplied, and delegation refused inside an open parent batch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Oleg Miagkov <mrobenner@gmail.com> * fix(runtime): harden subagent merge per PR-322 review + Windows CI Addresses all 5 CodeRabbit findings and the Windows test failure: - Changesets are untrusted input at the parent boundary: the declared write_scope must be non-empty and normalizable (else scope_violation with reason missing_or_invalid_write_scope), and every entry's declared path must equal its preimage AND postimage paths (else invalid_changeset_path) — the postimage path is what actually gets written, so path mismatches could otherwise escape revalidation. - subagent_merge snapshots now carry workspace_guard: checkpoint integrity validation treats it as mandatory, so a recoverable stop after a subagent_merge rollback no longer fails resume validation. - run_subagents result data now surfaces mutation_snapshot_ids, mutated_paths, and affected_paths from applied outcomes (each applied outcome carries its mutation_snapshot_id), so transaction summaries record parent-side merge mutations and a later failing action in the same turn yields partial_failure with a recovery plan instead of plain failed. - Windows CI: the rollback test hand-crafted a preimage with byte counts that broke under CRLF newline translation; it now captures the real preimage via build_generic_edit_file_preimage. - New tests per review: baseline_unverifiable refusal; partial merge keeps the applied sibling while the failing child rolls back; malformed changesets (path mismatch, scope-less) rejected with nothing applied. 311 passed across agent_runtime / runtime_capabilities / runtime_modes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Oleg Miagkov <mrobenner@gmail.com> * fix(tests): guard collection access before indexing merge snapshots SonarCloud reliability gate flagged the unguarded snapshots[0] access; assert the expected lengths before indexing. 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>
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>
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>
…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>



Context — Phase A / PR-2 of "mutating subagents → safe"
Follows #319 (write-scope enforcement). With this PR a
transactional_writechild never touches the shared workspace: its mutations are auto-staged and exported as a changeset that the parent will apply transactionally in Phase B (PR-3).What changes
1. Changeset-exporting sessions —
GenericEditRuntimeSession(changeset_export=True):__changeset__batch, reusing the proven staged-batch mechanics (materialize-per-action + restore) — the real workspace stays at baseline between actions and after finish.begin/commit/abort_batchis rejected (staging is runtime-owned), so the only staging path is the implicit batch.AgentRunResult.changeset. The open-batch finish veto now applies only to model-managed batches. Error/recovery exits export nothing.2. Orchestrator hardening (
subagents.py):changeset_exportrequired for mutating tasks).generic_edit()for mutating tasks):task.requirementsis the parent-side policy gate (incl. the policy-grantedsubagentscapability), not what the child session physically does — without this split, every real mutating child would fail the child-side capability re-check.spec_dir = artifacts/subagents/<task-id>/, so a runtime child can never clobber the parent's (or a sibling's)generic_edit_trace.json/ recovery checkpoint. This closes a latent recovery-correctness hazard: previously a parent crash after a generic_edit child finished could resume from the child's checkpoint.RuntimeSubagentResult.changesetpersists in the per-child artifact; the merge plan recordschangeset_result_ids/missing_changeset_result_idsfor the Phase B executor.3. Production wiring (
agents/coder.py): the subagent session factory builds a confined changeset-exportinggeneric_editchild fortransactional_writetasks (write_scope_guardfrom the task); read-only children stayanalysis_only.What this PR intentionally does NOT do
No merge-plan execution (Phase B / PR-3), no conflict resolution (PR-4), no probes/evidence (Phase C), no
safeflip (Phase D).read_onlychildren and non-changeset sessions are unchanged.Tests (4 new + 2 updated, 382 passed across the affected surface)
artifacts/subagents/edit-a/, parent artifacts untouched, merge plan updated.🤖 Generated with Claude Code