resolve-merge-conflicts

Goal-aware resolution of rebase conflicts when merging a conflict-resolution worktree back into the integration branch. Analyzes the intent of each side of a conflict, resolves it in-place when confid

SKILL.md

GitHub

Resolve Merge Conflicts Skill

Arguments (positional)

  • {worktree_path} — absolute path to the existing worktree (must exist; rebase was aborted cleanly)
  • {plan_path} — absolute path to the implementation plan ({{AUTOSKILLIT_TEMP}}/make-plan/…_plan_….md, relative to the current working directory)
  • {base_branch} — the integration branch to rebase onto (e.g. integration/run-N)

Critical Constraints

NEVER:

  • Run the full test suite — that is the pipeline test step's responsibility; tests already passed before merge_to_integration was attempted
  • Attempt partial resolution when any conflict file is LOW confidence — abort and escalate instead
  • Leave unresolved conflict markers (<<<<<<<, =======, >>>>>>>) in any file
  • Loop back to the calling pipeline step — emit output tokens and exit cleanly
  • Exceed 3 rebase continuation rounds — abort and escalate if exceeded

ALWAYS:

  • Run git rebase --abort before emitting escalation_required=true
  • Emit both escalation_required=true and escalation_reason= when escalating
  • Emit worktree_path= and branch_name= on successful resolution
  • Run pre-commit run --all-files after a successful rebase before emitting output tokens
  • Validate all three positional arguments before touching git state
  • Write conflict_resolution_report_*.md to {{AUTOSKILLIT_TEMP}}/resolve-merge-conflicts/ and emit conflict_report_path= after successful conflict resolution

When to Use

  • Called by queue-ejection, direct-merge, immediate-merge, and CI-conflict paths when merge_worktree fails with failed_step=rebase and state=worktree_intact_rebase_aborted
  • Called by the rebase_conflict_fix step in implementation.yaml, implementation-groups.yaml, and remediation.yaml when merge_worktree returns failed_step == 'rebase'
  • The worktree must still be intact (rebase aborted cleanly, no partial state)

Workflow

Step 0 — Validate inputs

Parse three positional path arguments (space-separated). Fail with a clear error message if any is missing or invalid:

ERROR: resolve-merge-conflicts requires three arguments:
  worktree_path  — absolute path to the existing worktree
  plan_path      — absolute path to the implementation plan
  base_branch    — integration branch to rebase onto

Validation checks:

  1. Verify worktree_path directory exists and is a git worktree:
    git -C {worktree_path} rev-parse --git-dir
    
  2. Verify plan_path file exists (readable Markdown).
  3. Resolve effective remote:
    # Resolve effective remote: prefer 'upstream' (clone isolation contract) over 'origin'.
    # In pipelines that use clone_repo(), 'origin' is a stale file:// URL and 'upstream'
    # holds the real GitHub remote. In direct checkout repos, only 'origin' exists.
    REMOTE=$(git -C {worktree_path} remote get-url upstream >/dev/null 2>&1 \
             && echo upstream \
             || echo origin)
    
  4. Verify base_branch is reachable:
    git -C {worktree_path} rev-parse --verify $REMOTE/{base_branch}
    
    If remote ref is not found, run git -C {worktree_path} fetch $REMOTE {base_branch} first.

Step 1 — Load conflict context

Read plan_path to extract:

  • What the original PR conflict was about (look for ## Context, ## PR Summary, ## Conflict Analysis sections)
  • What the implementation plan prescribed (look for ## Implementation Steps)
  • Which files were expected to be modified (look for ## PR Changes Inventory, Category A, Category B, Category C sections)

Run commit log queries to understand the divergence:

# What commits exist in the worktree that are not on the integration branch
git -C {worktree_path} log --oneline $REMOTE/{base_branch}..HEAD

# What commits the integration branch received since the worktree was created
git -C {worktree_path} fetch $REMOTE
git -C {worktree_path} log --oneline HEAD..$REMOTE/{base_branch}

Step 2 — Re-attempt rebase to surface conflicts

git -C {worktree_path} rebase $REMOTE/{base_branch}

On success (clean rebase): The integration branch advanced in a non-conflicting way since the last attempt. Proceed to Step 5a for manifest validation before emitting output tokens.

On conflict: Proceed to Step 3.

Step 3 — Analyze each conflicting file with goal awareness

For each file listed by git -C {worktree_path} diff --name-only --diff-filter=U:

3.1 — Read the conflict diff

Read the full file content including conflict markers (<<<<<<<, =======, >>>>>>>) to understand the specific lines in tension.

3.2 — Determine intent of ours (worktree side)

  • Consult the plan's ## Implementation Steps section
  • Run git -C {worktree_path} log --oneline -5 -- {file} to see recent commits on this file
  • Infer the functional intent: what behavior was being added or changed?

3.3 — Determine intent of theirs (integration branch side)

  • Run git -C {worktree_path} log --oneline $REMOTE/{base_branch} -5 -- {file} to see recent integration-branch commits touching this file
  • Retrieve integration-branch file content:
    git -C {worktree_path} show $REMOTE/{base_branch}:{file}
    
  • Infer the functional intent: what behavior was being added or changed?

3.4 — Classify the conflict

Assign one of three conflict categories:

  • Category 1 — Textual overlap, compatible goals: Both sides achieve the same functional outcome with different text (e.g., both added the same import, both updated the same docstring, or both reformatted the same block). Resolution: keep the better expression or combine them (e.g., union of imports).

  • Category 2 — Same file, different concerns: Two independent features changed the same file. The changes address different functions, classes, or sections with no semantic interference. Resolution: interlace both sets of changes, ensuring correct ordering (sorted imports, proper placement of new functions/methods).

  • Category 3 — Architectural tension: Both sides made structural decisions that cannot coexist without choosing one over the other or restructuring. Examples: conflicting class hierarchies, incompatible API signatures, contradictory type definitions.

3.5 — Assign a confidence level

Confidence Criteria
HIGH Category 1 or 2 conflict where the intent of both sides is clear from plan + git log
MEDIUM Category 2 conflict where one side's intent has moderate ambiguity
LOW Category 3 conflict; or any conflict where intent cannot be determined from available context; or the conflicting file is outside the scope recorded in the plan's PR Changes Inventory

Step 4 — Confidence gate

Maintain a resolution_log: As you resolve each file, record a log entry with: file (path), category (1/2/3), confidence (HIGH/MEDIUM), strategy (ours/theirs/combined), and justification (one sentence). Accumulate all entries across all rebase continuation rounds. This list is consumed in Step 6 to write the decision report.

If any conflict file is rated LOW:

Run git rebase --abort immediately:

git -C {worktree_path} rebase --abort

Emit escalation output tokens and exit:

escalation_required = true
escalation_reason = <brief human-readable explanation: which file(s), which category, why confidence was LOW>

Do NOT attempt partial resolution. Partial resolution with remaining LOW-confidence conflicts produces incorrect merges that are harder to debug than a clean abort.

Escalation criteria — these ALWAYS cause LOW confidence and trigger abort:

  1. Any conflicting file is Category 3 (architectural tension)
  2. The intent of either side cannot be determined from the plan + git log
  3. rebase --continue triggers more than 3 additional conflict rounds
  4. The conflict involves files outside the scope recorded in the plan's PR Changes Inventory

If all conflict files are HIGH or MEDIUM:

For each conflicting file, proceed to resolution (Step 4.1).

4.1 — Resolve conflict markers

Edit each file directly to resolve all conflict markers. No unresolved <<<<<<<, =======, or >>>>>>> markers may remain after editing.

Resolution strategy by category:

  • Category 1 (textual overlap): Prefer the implementation that is more precise or idiomatic. If genuinely equivalent, keep both if combinable (e.g., union of imports). For non-plan-critical sections, prefer the integration branch's version.

  • Category 2 (different concerns): Ensure both sets of changes are present and correctly ordered (e.g., imports sorted, new functions placed at the appropriate location in the file).

After resolving each file:

git -C {worktree_path} add {file}

4.2 — Continue the rebase

After all files for this round are resolved and staged:

GIT_EDITOR=true git -C {worktree_path} rebase --continue

(GIT_EDITOR=true skips the interactive commit message prompt.)

If rebase --continue surfaces a new conflict round: Repeat Step 3 analysis for the new conflicts. Track the number of continuation rounds. If the total exceeds 3, abort and escalate:

git -C {worktree_path} rebase --abort
escalation_required = true
escalation_reason = Rebase required more than 3 continuation rounds — conflict complexity exceeds automated resolution threshold.

Step 5 — Post-rebase hygiene

After a successful rebase --continue (no more conflict rounds):

cd {worktree_path} && pre-commit run --all-files

If pre-commit fails, apply all auto-fixable hooks in a single pass before re-running:

  1. ruff format / ruff check: These hooks auto-apply fixes when they run; check for modified files after the failure.

  2. check-version-consistency: If this hook fails, run:

    python3 scripts/sync_versions.py
    git -C {worktree_path} add -u
    
  3. uv-lock-check: If this hook fails, run:

    uv lock
    git -C {worktree_path} add -u
    

After applying all applicable fixes, re-stage any remaining modified files with git -C {worktree_path} add -u and re-run pre-commit run --all-files.

If pre-commit run --all-files still fails after this second pass, the remaining failure is from a non-auto-fixable hook (e.g., mypy, gitleaks, doc-counts). Escalate immediately — do NOT loop:

escalation_required = true
escalation_reason = pre-commit failed after applying all auto-fixes (ruff, sync_versions, uv lock). Remaining failure from non-fixable hook requires manual remediation: <hook name and output summary>

Do NOT run the full test suite. Testing is handled by the pipeline's test step, which already ran and passed before merge_to_integration was first attempted. Running tests here would be redundant and is explicitly prohibited.

Step 5a — Language-aware manifest validation

After pre-commit run --all-files succeeds, detect the project language and run a fast manifest validity check. This catches semantically broken merges (e.g., duplicate dependency keys in Cargo.toml) that produce no conflict markers and are not caught by pre-commit hooks.

Detection and validation commands (run the first matching check):

Detected by Command
Cargo.toml present cargo metadata --no-deps --format-version 1 >/dev/null
package.json present node -e "JSON.parse(require('fs').readFileSync('package.json'))"
uv.lock present uv lock --check
pyproject.toml present (no uv.lock) python3 -c "import tomllib; tomllib.load(open('pyproject.toml','rb'))"

Run in the worktree root:

cd {worktree_path}

If no manifest files are detected: skip this step and proceed to Step 5b.

If the check fails: do NOT attempt to fix the manifest. The rebase produced a semantically invalid result. Escalate immediately:

git -C {worktree_path} rebase --abort
escalation_required = true
escalation_reason = Post-rebase manifest validation failed: <error output summary>. The rebase produced a semantically invalid manifest (e.g., duplicate dependency key). Manual inspection required.

If the check passes: proceed to Step 5b.

Step 5b — Duplicate key scan in cleanly-merged structured files

Scan manifest files for duplicate keys. Both branches may have independently added the same dependency entry; git merges these without conflict markers but the result is semantically invalid.

Files to scan (if present in {worktree_path}):

  • Cargo.toml — scan [dependencies], [dev-dependencies], [build-dependencies] sections
  • pyproject.toml — scan [project.dependencies], [tool.uv.dev-dependencies]
  • package.json — scan all top-level keys

TOML duplicate detection (for each TOML manifest file):

python3 -c "
import re, sys
text = open(sys.argv[1]).read()
in_dep_section = False
counts = {}
for line in text.splitlines():
    if re.match(r'^\s*\[(dependencies|dev-dependencies|build-dependencies)\]', line):
        in_dep_section = True
        continue
    if re.match(r'^\s*\[', line):
        in_dep_section = False
    if in_dep_section:
        m = re.match(r'^\s*([a-zA-Z0-9_-]+)\s*[=\.]', line)
        if m:
            k = m.group(1)
            counts[k] = counts.get(k, 0) + 1
dups = {k: v for k, v in counts.items() if v > 1}
if dups:
    print('DUPLICATE_KEYS:', dups)
    sys.exit(1)
" Cargo.toml

JSON duplicate detection (for package.json):

python3 -c "
import json, sys
class _Dup(Exception): pass
def check(pairs):
    seen = {}
    for k, v in pairs:
        if k in seen:
            raise _Dup(f'duplicate key: {k!r}')
        seen[k] = v
    return seen
json.loads(open('package.json').read(), object_pairs_hook=check)
" 2>&1

If duplicates are found: escalate immediately:

git -C {worktree_path} rebase --abort
escalation_required = true
escalation_reason = Duplicate key detected in <file>: key '<key>' appears multiple times in section '[<section>]'. This is a semantically invalid clean merge — both branches independently added the same dependency.

If no duplicates are found (or no manifest files are present): proceed to Step 6.

Step 6 — Write Conflict Resolution Report

Create the directory and write the conflict resolution report:

mkdir -p {worktree_path}/{{AUTOSKILLIT_TEMP}}/resolve-merge-conflicts

Write the report to:

{worktree_path}/{{AUTOSKILLIT_TEMP}}/resolve-merge-conflicts/conflict_resolution_report_{YYYY-MM-DD_HHMMSS}.md

Report format:

# Merge Conflict Resolution Report

**Worktree:** {worktree_path}
**Base Branch:** {base_branch}
**Timestamp:** {ISO-8601 timestamp, e.g. 2026-03-14T21:09:00Z}
**Files Conflicting:** {total number of files that had conflicts across all rebase rounds}
**Files Resolved:** {number of files successfully resolved}

## Per-File Resolution Decisions

| File | Category | Confidence | Strategy | Justification |
|------|----------|------------|----------|---------------|
| {file_path} | {1/2/3} | {HIGH/MEDIUM} | {ours/theirs/combined} | {one-sentence justification} |

One row per file from resolution_log. The table MUST be a standard GFM pipe table so downstream tools can extract rows programmatically by splitting on |.

After writing, capture the absolute path to this file as conflict_report_file_path for use in Step 7.

If no conflicts were encountered (clean rebase in Step 2, or Step 2 succeeded immediately): Skip this step — emit worktree_path= and branch_name= only (no conflict_report_path).

Step 7 — Emit output tokens

IMPORTANT: Emit the structured output tokens as literal plain text with no markdown formatting on the token names. Do not wrap token names in **bold**, *italic*, or any other markdown. The adjudicator performs a regex match on the exact token name — decorators cause match failure.

worktree_path = {worktree_path}
branch_name = {current_branch}
conflict_report_path = {conflict_report_file_path}

Where {current_branch} is the output of:

git -C {worktree_path} branch --show-current

Omit conflict_report_path= line entirely when the rebase was clean (no conflicts occurred — resolution_log is empty).

Output contract

Token Type When emitted
worktree_path= directory_path On successful resolution (confidence gate passed)
branch_name= string On successful resolution
conflict_report_path= file_path On successful resolution when at least one conflict was resolved
escalation_required=true string literal 'true' (lowercase) When confidence is LOW or rebase rounds exceed 3
escalation_reason= string When confidence is LOW — explains which file and why

Error handling

  • Validation failures: Emit clear error message and abort before touching git state
  • rebase --continue failure (not a conflict): Abort with git -C {worktree_path} rebase --abort and escalate
  • pre-commit failure: Apply all auto-fixable hooks in order — ruff format/check (auto-applied by hooks), check-version-consistency (run python3 scripts/sync_versions.py && git add -u), uv-lock-check (run uv lock && git add -u) — re-stage, then re-run. If pre-commit still fails after this pass, escalate with escalation_required=true; non-fixable hooks (mypy, gitleaks, doc-counts) require manual remediation.
  • Unexpected git state: Run git -C {worktree_path} rebase --abort before exiting