Skip to content

Integration: merge into any lane, parent-head simulation, resolver instructions#135

Merged
arul28 merged 4 commits intocursor/multiple-model-prompt-lanes-bb23from
cursor/-bc-ea2b526c-c64f-4f0f-85be-34232e113296-baeb
Apr 5, 2026
Merged

Integration: merge into any lane, parent-head simulation, resolver instructions#135
arul28 merged 4 commits intocursor/multiple-model-prompt-lanes-bb23from
cursor/-bc-ea2b526c-c64f-4f0f-85be-34232e113296-baeb

Conversation

@arul28
Copy link
Copy Markdown
Owner

@arul28 arul28 commented Apr 5, 2026

Summary

Extends the integration workflow so merges can target an existing lane (not only a new integration child), simulation accounts for ongoing work on that lane (merge-tree and sequential preview from its current HEAD), and the AI resolver accepts optional operator instructions appended to the generated prompt.

Follow-up (review feedback)

  • Codex: If mergeIntoLaneId is set, failing to resolve that lane’s HEAD now errors instead of silently simulating from base only.
  • Codex / CodeRabbit: createIntegrationLaneForProposal now runs dirty-worktree checks on source lanes plus the preferred integration lane; optional allowDirtyWorktree for IPC/UI confirmation paths.
  • CodeRabbit: handleApplyMergeIntoTarget updates the new proposal before best-effort delete of the old row; Create PR / re-simulate / delete gated while merge-into apply runs; live simulate resets when liveIntegrationLaneId changes; merge-into picker hides source lanes; copy uses lane terminology; advisory text distinguishes pairwise merge base vs sequential preview.
  • Drift: New merge_into_head_sha column stores the merge-into HEAD at simulation time; adopting a preferred lane logs a warning if HEAD differs.

Changes

  • Schema: integration_proposals.preferred_integration_lane_id, merge_into_head_sha (SQLite migration in kvDb, iOS bootstrap aligned).
  • Types: SimulateIntegrationArgs.mergeIntoLaneId, CreateIntegrationPrArgs.existingIntegrationLaneId, CommitIntegrationArgs.preferredIntegrationLaneId, IntegrationProposal fields, UpdateIntegrationProposalArgs, CreateIntegrationLaneForProposalArgs.allowDirtyWorktree, resolver instruction types.
  • prService, conflict resolver, UI as in prior revision.

Validation

  • npm --prefix apps/desktop run typecheck
  • npm --prefix apps/desktop run test -- --run src/main/services/prs/prService.integrationCommit.test.ts src/main/services/state/kvDb.missionsMigration.test.ts
  • npm --prefix apps/desktop run lint

Notes

  • Pairwise child vs child simulation still uses the proposal base branch as the merge base. Parent/integration-lane conflicts are layered via the merge-into path and sequential preview.
  • Changing merge-into on the Integration tab replaces the proposal row (new id) to avoid stale simulation data.
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features
    • Users can now select an existing integration lane as the preferred merge target instead of creating a new one.
    • Added optional "merge into" lane selection for more accurate conflict detection during proposal simulations.
    • Users can now provide custom instructions to the AI conflict resolver for more tailored conflict resolution.

cursoragent and others added 3 commits April 5, 2026 02:45
- Store preferred_integration_lane_id on integration_proposals
- Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs
- Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
… resolver notes

- createIntegrationPr: optional existingIntegrationLaneId merges into that worktree
- simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD
- createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists
- commitIntegration: dirty-check preferred lane; persist preferred id override
- prepareResolverSession: append operator instructions to prompt.md
- IPC: pass additionalInstructions from aiResolutionStart

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
…uctions

- CreatePrModal: merge-into select, simulation and save proposal preference
- IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head
- PrAiResolverPanel: optional instructions textarea sent as additionalInstructions

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ade Ready Ready Preview, Comment Apr 5, 2026 6:33pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

📝 Walkthrough

Walkthrough

Extended PR and conflict resolution workflows to support additional AI resolver instructions, preferred integration lane selection, and merge-into lane functionality for enhanced conflict visibility during integration proposal simulation. Added corresponding database schema column and UI controls.

Changes

Cohort / File(s) Summary
Conflict Resolution & AI Resolver
conflictService.ts, registerIpc.ts, conflicts.ts
Added support for optional additionalInstructions parameter passed through IPC handler to conflict service, where instructions are trimmed, validated, and appended to the AI resolver prompt with a markdown section header.
Type Definitions
prs.ts
Extended integration PR argument types to include existingIntegrationLaneId, preferredIntegrationLaneId, mergeIntoLaneId, clearIntegrationBinding, and additionalInstructions across multiple workflow operations.
Integration Service Logic
prService.ts
Added database column preferred_integration_lane_id handling; implemented support for adopting existing integration lanes; enhanced conflict simulation with optional merge-into lane to compute conflict visibility across source lanes; updated proposal creation and persistence flows.
Database Schema & Migrations
kvDb.ts, kvDb.missionsMigration.test.ts, DatabaseBootstrap.sql
Added nullable preferred_integration_lane_id column to integration_proposals table with migration support and test validation.
UI: Resolver Instructions & Integration Modal
PrAiResolverPanel.tsx, CreatePrModal.tsx
Added optional resolver instructions textarea to AI resolver panel; extended integration PR modal with merge-into lane selector and validation to prevent selecting source lanes.
UI: Integration Proposal Management
IntegrationTab.tsx
Implemented merge-into lane selector in proposal detail view with apply/re-simulate workflow; added validation to block source lane selection; integrated mergeIntoLaneId and preferredIntegrationLaneId into simulation and persistence flows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • fixing rebasing logic #84: Modifies the conflict/AI resolution surface (shared conflict types, IPC handlers, and conflicts service) which directly overlaps with this PR's resolver instruction and session preparation changes.
  • Codex/ade phase 4 5 #1: Extends the same conflict-resolution code path (conflictService and IPC hooks) that this PR augments with additional instructions support.

Suggested labels

desktop, ios

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main features added: ability to merge into any lane, parent-head simulation logic, and resolver instructions support.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/-bc-ea2b526c-c64f-4f0f-85be-34232e113296-baeb

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.

@arul28 arul28 marked this pull request as ready for review April 5, 2026 15:18
@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented Apr 5, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented Apr 5, 2026

@copilot review

@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented Apr 5, 2026

@codex review

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 5, 2026

@copilot review

Here is a thorough review of the changes in this PR.


Code Review

Schema / Migration ✅

  • kvDb.ts: The try/catch wrapping the ALTER TABLE is idempotent and consistent with all prior migrations in the file. Good.
  • DatabaseBootstrap.sql (iOS): Aligned correctly — the new column is added at the correct position in the sequential bootstrap script, just before queue_landing_state. The iOS bootstrap runs top-to-bottom on a clean DB, so it doesn't need the try/catch guard. ✅
  • Migration test updated to assert the new column is present. ✅

Types (prs.ts, conflicts.ts) ✅

The new fields are correctly optional, documented, and cover all relevant call sites:

  • SimulateIntegrationArgs.mergeIntoLaneId — optional, nullable ✅
  • CreateIntegrationPrArgs.existingIntegrationLaneId — optional, nullable ✅
  • CommitIntegrationArgs.preferredIntegrationLaneId — noted as "override stored preference" ✅
  • IntegrationProposal.preferredIntegrationLaneId — optional, nullable ✅
  • UpdateIntegrationProposalArgs.clearIntegrationBinding — documented with a clear warning about what it does ✅
  • PrAiResolutionStartArgs.additionalInstructions / PrepareResolverSessionArgs.additionalInstructions

prService.ts — Simulation logic ✅

The merge-tree checks for mergeIntoHeadSha use baseSha as the merge base, not mergeIntoHeadSha. This is intentional and correct: pairwise divergence between child lanes still uses the base branch as the common ancestor. Integration-lane conflicts are additive on top, not substitutive.

The sequentialStartSha correctly falls back to baseSha when no integration lane is set, preserving previous behaviour for proposals without a preferred lane.

One minor observation in conflict file merging (line ~3292–3299):

if (!laneFiles.has(filePath)) laneFiles.set(filePath, file);

mergeIntoFilesByLaneId entries are only written if not already present in conflictingFilesByLaneId. This means pairwise/sequential conflict detail (richer, with markers) takes precedence over the merge-into detail. Intentional and sensible.


prService.tscreateIntegrationPr / commitIntegration

  • The createdNewIntegrationLane flag correctly gates cleanup — adopted lanes are not archived on failure. This is a important safety guard. ✅
  • commitIntegration dirty-checks preferredIntegrationLaneId as part of laneIds before trying to adopt it. Correct. ✅
  • createIntegrationLaneForProposal adopts the preferred lane only when no binding exists — avoids overwriting a committed binding. ✅

conflictService.tsprepareResolverSession

The additionalInstructions appended as ## Operator instructions is clean. The markdown section separator (---) ensures it doesn't bleed into the auto-generated context sections.


registerIpc.ts

additionalInstructions is sanitised (trimmed, empty string → null) before being passed to prepareResolverSession. Consistent with how reasoning is handled. ✅


IntegrationTab.tsx

Minor redundancy: handleApplyMergeIntoTarget calls simulateIntegration (which inserts the row with preferred_integration_lane_id already set) and then calls updateProposal with the same value. The second write is a no-op but harmless.

Advisory copy for the integration-lane head message references laneById.get(selectedProposal.preferredIntegrationLaneId)?.name ?? selectedProposal.preferredIntegrationLaneId. The fallback to the raw ID is a good safety net for the edge case where the lane is archived between simulate and display.

mergeIntoLaneSelectOptions filters laneType === "primary", but doesn't filter lanes already in sourceLaneIds. However, there is a runtime guard in handleApplyMergeIntoTarget that catches this, so it's not a gap in correctness — just a UX nicety that could be added later.


CreatePrModal.tsx

The useEffect that clears integrationMergeIntoLaneId when it becomes a source lane is a good guardrail. The aria-label on the select element is a nice accessibility touch. ✅


PrAiResolverPanel.tsx

resolverInstructions resets to "" when contextKey changes (different PR / integration context). This is correct — stale instructions from a previous context shouldn't persist. ✅

showResolverInstructions is only enabled for integration and proposal resolvers (as passed by IntegrationTab). Not exposed globally, which limits blast radius if the feature needs adjustment. ✅


Overall Assessment

The implementation is correct and follows existing patterns throughout. Validation guards (lane-is-source check, lane-not-found, dirty-worktree) are applied consistently at both the IPC/service boundary and the renderer. The migration is idempotent, the iOS bootstrap is aligned, and the UI updates are surgical. No logic errors found.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2044cf8a1a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2933 to +2934
} catch {
mergeIntoHeadSha = null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when merge-into lane HEAD cannot be resolved

When rev-parse for the selected merge-into lane fails, this code silently sets mergeIntoHeadSha to null and continues simulation from baseSha, so the proposal no longer includes merge-into conflicts even though the user explicitly selected that lane. In environments where lane metadata can drift (e.g., branch deleted/renamed outside ADE), this produces falsely clean simulation results instead of surfacing a blocked/error state.

Useful? React with 👍 / 👎.

Comment on lines +4144 to +4148
if (preferredIntegrationLaneId) {
const adopt = laneMap.get(preferredIntegrationLaneId);
if (!adopt) throw new Error(`Preferred integration lane not found: ${preferredIntegrationLaneId}`);
integrationLane = adopt;
} else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce dirty-worktree checks before adopting preferred lane

This path adopts preferredIntegrationLaneId directly and then merges clean steps into that worktree, but there is no dirty-worktree guard in createIntegrationLaneForProposal. Because CreatePrModal and Integration tab both call this function before commit-time checks, selecting an existing lane with local changes can turn “dirty worktree” failures into misleading conflict outcomes and mutate/operate on a lane that should have been blocked up front.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx (1)

1345-1350: ⚠️ Potential issue | 🟡 Minor

Invalidate cached results when the merge-into lane changes.

Adding mergeIntoLaneId here means the live simulation result is now keyed by both the source lanes and the integration lane. The reset path still ignores liveIntegrationLaneId, so a PR that switches to a different integration lane can keep showing the previous preview until the next manual simulate. Please fold the lane id into the invalidation key/deps as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx` around
lines 1345 - 1350, The live simulation cache and invalidation must include the
integration lane ID: when calling window.ade.prs.simulateIntegration you already
pass liveIntegrationLaneId, so update the cache key and any reset/clear logic
that currently keys only by sourceLaneIds to also incorporate
liveIntegrationLaneId (e.g., use a composite key like
`${sourceLaneIds.join(',')}:${liveIntegrationLaneId}`), and add
liveIntegrationLaneId to any dependency arrays (or equality checks) that trigger
re-simulate or reset so switching integration lanes invalidates the previous
preview.
🧹 Nitpick comments (2)
apps/desktop/src/shared/types/prs.ts (1)

430-431: Rename "worktree" to "lane" in this field doc.

This property models ADE lane selection, so keeping the comment on lane terminology will match the renderer and service code.

As per coding guidelines: Use 'lane' terminology for ADE worktrees/branches.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/shared/types/prs.ts` around lines 430 - 431, Update the
JSDoc/comment for the property preferredIntegrationLaneId to replace the word
"worktree" with "lane" so the doc reads "Preferred integration lane when none
exists yet (merge sources here instead of a new lane)." Locate the comment
immediately above the preferredIntegrationLaneId declaration and edit it to use
"lane" terminology to match ADE renderer and service code.
apps/desktop/src/main/services/prs/prService.ts (1)

4144-4154: Consider validating preferred lane HEAD matches simulation expectations.

When adopting a preferredIntegrationLaneId, the lane is used as-is without verifying its current HEAD SHA matches what was used during simulation. If the lane has been modified (commits added, rebased) since the simulation ran, the actual merge results may differ from what the simulation predicted.

This is acceptable since merge failures are caught downstream (lines 4167-4173), but logging a warning when the HEAD differs could help users understand why results don't match expectations.

🔧 Optional: Add HEAD drift detection
     let integrationLane: LaneSummary;
     if (preferredIntegrationLaneId) {
       const adopt = laneMap.get(preferredIntegrationLaneId);
       if (!adopt) throw new Error(`Preferred integration lane not found: ${preferredIntegrationLaneId}`);
       integrationLane = adopt;
+      // Best-effort: warn if lane HEAD may have drifted since simulation
+      try {
+        const currentHead = (await runGit(
+          ["rev-parse", "HEAD"],
+          { cwd: adopt.worktreePath, timeoutMs: 10_000 }
+        )).stdout.trim();
+        logger.info("prs.integration_lane_adopted", {
+          proposalId: args.proposalId,
+          laneId: adopt.id,
+          currentHead,
+        });
+      } catch { /* best-effort */ }
     } else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/services/prs/prService.ts` around lines 4144 - 4154,
When adopting a preferredIntegrationLaneId from laneMap, fetch its current HEAD
SHA and compare it to the SHA used during the simulation (the value stored on
the preflight/simulation context); if they differ log a warning indicating HEAD
drift and include both SHAs and the preferredIntegrationLaneId so users know
simulation vs actual HEAD, then continue using the lane (leave existing
merge-failure handling intact). Locate the adoption branch around
preferredIntegrationLaneId / laneMap.get(...) and integrationLane assignment
(and where preflight/simulation SHAs are stored) and add the HEAD comparison and
warning via the existing logging facility before setting integrationLane or
proceeding to laneService.createChild.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx`:
- Around line 2068-2069: The helper copy in IntegrationTab's descriptive
paragraph uses "integration worktree" which conflicts with ADE's lane
terminology; update the sentence in the <p> inside IntegrationTab to use "lane"
wording (e.g., "Choose an existing lane as the integration lane (for example the
parent prompt lane). Simulation then includes conflicts against that lane's
current HEAD; source lanes still merge in list order.") so it consistently uses
'lane' terminology across the UI.
- Around line 1248-1282: In handleApplyMergeIntoTarget, the current sequence
creates the new proposal (simulateIntegration) then deletes the old proposal
before updating the new one, risking partial state if update fails; change the
flow to mirror handleResimulate by first calling simulateIntegration then
immediately call updateProposal on persisted.proposalId to populate
title/body/draft/integrationLaneName, only after a successful update attempt
perform deleteProposal on the oldId as a best-effort cleanup (catch and log but
do not surface failure), and ensure UI actions that operate on the selected
proposal (Create PR / re-simulate / delete) are disabled while mergeIntoLaneBusy
is true so siblings cannot act on a stale selection.

---

Outside diff comments:
In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx`:
- Around line 1345-1350: The live simulation cache and invalidation must include
the integration lane ID: when calling window.ade.prs.simulateIntegration you
already pass liveIntegrationLaneId, so update the cache key and any reset/clear
logic that currently keys only by sourceLaneIds to also incorporate
liveIntegrationLaneId (e.g., use a composite key like
`${sourceLaneIds.join(',')}:${liveIntegrationLaneId}`), and add
liveIntegrationLaneId to any dependency arrays (or equality checks) that trigger
re-simulate or reset so switching integration lanes invalidates the previous
preview.

---

Nitpick comments:
In `@apps/desktop/src/main/services/prs/prService.ts`:
- Around line 4144-4154: When adopting a preferredIntegrationLaneId from
laneMap, fetch its current HEAD SHA and compare it to the SHA used during the
simulation (the value stored on the preflight/simulation context); if they
differ log a warning indicating HEAD drift and include both SHAs and the
preferredIntegrationLaneId so users know simulation vs actual HEAD, then
continue using the lane (leave existing merge-failure handling intact). Locate
the adoption branch around preferredIntegrationLaneId / laneMap.get(...) and
integrationLane assignment (and where preflight/simulation SHAs are stored) and
add the HEAD comparison and warning via the existing logging facility before
setting integrationLane or proceeding to laneService.createChild.

In `@apps/desktop/src/shared/types/prs.ts`:
- Around line 430-431: Update the JSDoc/comment for the property
preferredIntegrationLaneId to replace the word "worktree" with "lane" so the doc
reads "Preferred integration lane when none exists yet (merge sources here
instead of a new lane)." Locate the comment immediately above the
preferredIntegrationLaneId declaration and edit it to use "lane" terminology to
match ADE renderer and service code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 670c0d54-5ccc-4cf2-931b-d8ce1e60b20f

📥 Commits

Reviewing files that changed from the base of the PR and between da59df4 and 2044cf8.

📒 Files selected for processing (11)
  • apps/desktop/src/main/services/conflicts/conflictService.ts
  • apps/desktop/src/main/services/ipc/registerIpc.ts
  • apps/desktop/src/main/services/prs/prService.ts
  • apps/desktop/src/main/services/state/kvDb.missionsMigration.test.ts
  • apps/desktop/src/main/services/state/kvDb.ts
  • apps/desktop/src/renderer/components/prs/CreatePrModal.tsx
  • apps/desktop/src/renderer/components/prs/shared/PrAiResolverPanel.tsx
  • apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx
  • apps/desktop/src/shared/types/conflicts.ts
  • apps/desktop/src/shared/types/prs.ts
  • apps/ios/ADE/Resources/DatabaseBootstrap.sql

Comment on lines +1248 to +1282
const handleApplyMergeIntoTarget = React.useCallback(async () => {
if (!selectedProposal) return;
const trimmed = mergeIntoLaneDraft.trim();
if (trimmed && selectedProposal.sourceLaneIds.includes(trimmed)) {
setCommitError("Merge-into lane cannot be one of the source lanes.");
return;
}
setMergeIntoLaneBusy(true);
setCommitError(null);
try {
const oldId = selectedProposal.proposalId;
const persisted = await window.ade.prs.simulateIntegration({
sourceLaneIds: selectedProposal.sourceLaneIds,
baseBranch: selectedProposal.baseBranch,
mergeIntoLaneId: trimmed || null,
});
await window.ade.prs.deleteProposal({ proposalId: oldId, deleteIntegrationLane: false });
await window.ade.prs.updateProposal({
proposalId: persisted.proposalId,
preferredIntegrationLaneId: trimmed || null,
...(selectedProposal.title ? { title: selectedProposal.title } : {}),
...(selectedProposal.body !== undefined ? { body: selectedProposal.body } : {}),
...(selectedProposal.draft !== undefined ? { draft: selectedProposal.draft } : {}),
...(selectedProposal.integrationLaneName ? { integrationLaneName: selectedProposal.integrationLaneName } : {}),
});
setResolutionState(null);
await loadProposals();
setSelectedProposalId(persisted.proposalId);
} catch (err: unknown) {
setCommitError(err instanceof Error ? err.message : String(err));
await loadProposals();
} finally {
setMergeIntoLaneBusy(false);
}
}, [loadProposals, mergeIntoLaneDraft, selectedProposal]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make the proposal replacement flow failure-safe.

This swap creates the replacement proposal first, but deletes the current row before the replacement is updated. If either mutation fails, the user can be left with duplicate proposals or a new row missing its saved title/body/draft/lane metadata. While it runs, the Create PR / re-simulate / delete actions also stay enabled against the stale selection. Mirror handleResimulate: update the new row first, treat old-row cleanup as best-effort, and gate sibling proposal actions on mergeIntoLaneBusy.

Possible sequencing fix
      const persisted = await window.ade.prs.simulateIntegration({
        sourceLaneIds: selectedProposal.sourceLaneIds,
        baseBranch: selectedProposal.baseBranch,
        mergeIntoLaneId: trimmed || null,
      });
-     await window.ade.prs.deleteProposal({ proposalId: oldId, deleteIntegrationLane: false });
      await window.ade.prs.updateProposal({
        proposalId: persisted.proposalId,
        preferredIntegrationLaneId: trimmed || null,
        ...(selectedProposal.title ? { title: selectedProposal.title } : {}),
        ...(selectedProposal.body !== undefined ? { body: selectedProposal.body } : {}),
        ...(selectedProposal.draft !== undefined ? { draft: selectedProposal.draft } : {}),
        ...(selectedProposal.integrationLaneName ? { integrationLaneName: selectedProposal.integrationLaneName } : {}),
      });
+     let cleanupWarning: string | null = null;
+     try {
+       await window.ade.prs.deleteProposal({ proposalId: oldId, deleteIntegrationLane: false });
+     } catch (cleanupError) {
+       cleanupWarning = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
+     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx` around
lines 1248 - 1282, In handleApplyMergeIntoTarget, the current sequence creates
the new proposal (simulateIntegration) then deletes the old proposal before
updating the new one, risking partial state if update fails; change the flow to
mirror handleResimulate by first calling simulateIntegration then immediately
call updateProposal on persisted.proposalId to populate
title/body/draft/integrationLaneName, only after a successful update attempt
perform deleteProposal on the oldId as a best-effort cleanup (catch and log but
do not surface failure), and ensure UI actions that operate on the selected
proposal (Create PR / re-simulate / delete) are disabled while mergeIntoLaneBusy
is true so siblings cannot act on a stale selection.

Comment on lines +2068 to +2069
<p className="font-mono" style={{ fontSize: 10, color: "#71717A", marginBottom: 12, lineHeight: "16px" }}>
Choose an existing lane as the integration worktree (for example the parent prompt lane). Simulation then includes conflicts against that lane&apos;s current HEAD; source lanes still merge in list order.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use lane terminology in this helper copy.

"Integration worktree" reads like a different concept from the lane selector directly below it. existing lane keeps the wording consistent across ADE.

As per coding guidelines: Use 'lane' terminology for ADE worktrees/branches.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx` around
lines 2068 - 2069, The helper copy in IntegrationTab's descriptive paragraph
uses "integration worktree" which conflicts with ADE's lane terminology; update
the sentence in the <p> inside IntegrationTab to use "lane" wording (e.g.,
"Choose an existing lane as the integration lane (for example the parent prompt
lane). Simulation then includes conflicts against that lane's current HEAD;
source lanes still merge in list order.") so it consistently uses 'lane'
terminology across the UI.

…roposal swap

- Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex)
- Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane
- createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree
- IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy,
  include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker,
  lane terminology and advisory copy, dirty-worktree confirm for prepare lane
- CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal
- Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base)

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
@arul28 arul28 merged commit 9eb8c73 into cursor/multiple-model-prompt-lanes-bb23 Apr 5, 2026
4 checks passed
@arul28 arul28 deleted the cursor/-bc-ea2b526c-c64f-4f0f-85be-34232e113296-baeb branch April 5, 2026 19:46
arul28 added a commit that referenced this pull request Apr 6, 2026
…structions (#135)

* Add integration proposal preferred lane column and resolver prompt types

- Store preferred_integration_lane_id on integration_proposals
- Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs
- Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Integrate into existing lanes, simulate parent-head conflicts, append resolver notes

- createIntegrationPr: optional existingIntegrationLaneId merges into that worktree
- simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD
- createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists
- commitIntegration: dirty-check preferred lane; persist preferred id override
- prepareResolverSession: append operator instructions to prompt.md
- IPC: pass additionalInstructions from aiResolutionStart

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* UI: merge-into lane picker, re-simulate flow, optional resolver instructions

- CreatePrModal: merge-into select, simulation and save proposal preference
- IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head
- PrAiResolverPanel: optional instructions textarea sent as additionalInstructions

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Address PR review: merge-into HEAD persistence, dirty checks, safer proposal swap

- Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex)
- Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane
- createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree
- IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy,
  include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker,
  lane terminology and advisory copy, dirty-worktree confirm for prepare lane
- CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal
- Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base)

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
arul28 added a commit that referenced this pull request Apr 6, 2026
…structions (#135)

* Add integration proposal preferred lane column and resolver prompt types

- Store preferred_integration_lane_id on integration_proposals
- Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs
- Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Integrate into existing lanes, simulate parent-head conflicts, append resolver notes

- createIntegrationPr: optional existingIntegrationLaneId merges into that worktree
- simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD
- createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists
- commitIntegration: dirty-check preferred lane; persist preferred id override
- prepareResolverSession: append operator instructions to prompt.md
- IPC: pass additionalInstructions from aiResolutionStart

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* UI: merge-into lane picker, re-simulate flow, optional resolver instructions

- CreatePrModal: merge-into select, simulation and save proposal preference
- IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head
- PrAiResolverPanel: optional instructions textarea sent as additionalInstructions

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Address PR review: merge-into HEAD persistence, dirty checks, safer proposal swap

- Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex)
- Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane
- createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree
- IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy,
  include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker,
  lane terminology and advisory copy, dirty-worktree confirm for prepare lane
- CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal
- Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base)

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
arul28 added a commit that referenced this pull request Apr 9, 2026
…structions (#135)

* Add integration proposal preferred lane column and resolver prompt types

- Store preferred_integration_lane_id on integration_proposals
- Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs
- Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Integrate into existing lanes, simulate parent-head conflicts, append resolver notes

- createIntegrationPr: optional existingIntegrationLaneId merges into that worktree
- simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD
- createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists
- commitIntegration: dirty-check preferred lane; persist preferred id override
- prepareResolverSession: append operator instructions to prompt.md
- IPC: pass additionalInstructions from aiResolutionStart

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* UI: merge-into lane picker, re-simulate flow, optional resolver instructions

- CreatePrModal: merge-into select, simulation and save proposal preference
- IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head
- PrAiResolverPanel: optional instructions textarea sent as additionalInstructions

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Address PR review: merge-into HEAD persistence, dirty checks, safer proposal swap

- Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex)
- Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane
- createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree
- IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy,
  include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker,
  lane terminology and advisory copy, dirty-worktree confirm for prepare lane
- CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal
- Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base)

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
arul28 added a commit that referenced this pull request Apr 9, 2026
…structions (#135)

* Add integration proposal preferred lane column and resolver prompt types

- Store preferred_integration_lane_id on integration_proposals
- Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs
- Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Integrate into existing lanes, simulate parent-head conflicts, append resolver notes

- createIntegrationPr: optional existingIntegrationLaneId merges into that worktree
- simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD
- createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists
- commitIntegration: dirty-check preferred lane; persist preferred id override
- prepareResolverSession: append operator instructions to prompt.md
- IPC: pass additionalInstructions from aiResolutionStart

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* UI: merge-into lane picker, re-simulate flow, optional resolver instructions

- CreatePrModal: merge-into select, simulation and save proposal preference
- IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head
- PrAiResolverPanel: optional instructions textarea sent as additionalInstructions

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Address PR review: merge-into HEAD persistence, dirty checks, safer proposal swap

- Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex)
- Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane
- createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree
- IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy,
  include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker,
  lane terminology and advisory copy, dirty-worktree confirm for prepare lane
- CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal
- Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base)

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
arul28 added a commit that referenced this pull request Apr 14, 2026
…structions (#135)

* Add integration proposal preferred lane column and resolver prompt types

- Store preferred_integration_lane_id on integration_proposals
- Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs
- Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Integrate into existing lanes, simulate parent-head conflicts, append resolver notes

- createIntegrationPr: optional existingIntegrationLaneId merges into that worktree
- simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD
- createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists
- commitIntegration: dirty-check preferred lane; persist preferred id override
- prepareResolverSession: append operator instructions to prompt.md
- IPC: pass additionalInstructions from aiResolutionStart

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* UI: merge-into lane picker, re-simulate flow, optional resolver instructions

- CreatePrModal: merge-into select, simulation and save proposal preference
- IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head
- PrAiResolverPanel: optional instructions textarea sent as additionalInstructions

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

* Address PR review: merge-into HEAD persistence, dirty checks, safer proposal swap

- Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex)
- Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane
- createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree
- IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy,
  include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker,
  lane terminology and advisory copy, dirty-worktree confirm for prepare lane
- CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal
- Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base)

Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants