Skip to content

ADR-312: add resolve-rebase-conflict skill and fixture dry-run harness - #83

Merged
jodavis merged 1 commit into
feature/ADR-296-concurrencyfrom
dev/claude/ADR-312
Jul 23, 2026
Merged

ADR-312: add resolve-rebase-conflict skill and fixture dry-run harness#83
jodavis merged 1 commit into
feature/ADR-296-concurrencyfrom
dev/claude/ADR-312

Conversation

@jodavis-claude

Copy link
Copy Markdown
Collaborator

Work item

ADR-312: Build the resolve-rebase-conflict skill — given a rebase already left in progress with conflicts, it reads the conflicting hunks using the task's brief/spec context, resolves them, stages them (git add), and repeats git rebase --continue until the rebase completes cleanly or it hits a conflict it cannot resolve with confidence, reporting "resolved" or "unresolved", and never pushing itself.

Changes

  • plugins/dev-team/skills/resolve-rebase-conflict/SKILL.md (new) — the skill itself: agent-skill prose (Testable per component-taxonomy, not a pure function) invoked by the Developer agent in the current worktree once rebase_onto() has already left a rebase in progress with conflicts. Steps: (1) confirm a rebase is in progress; (2) enumerate every conflicted file (git status --porcelain=v1); (3) read each conflicted file's <<<<<<</=======/>>>>>>> regions; (4) resolve each region only when the task's brief/spec context makes the final content unambiguous, otherwise stop immediately and report "unresolved"; (5) git add + GIT_EDITOR=true git rebase --continue, looping back to step 2 if the next commit also conflicts; (6) report "resolved" (clean tree, no rebase in progress) or "unresolved" — never runs git push or git rebase --abort itself.
  • plugins/dev-team/fixtures/resolve-rebase-conflict/build_fixture.py (new) — fixture builder for the dry-run harness. Builds one of three named scenarios (single-file, multi-file, unresolvable) into a fresh throwaway git working clone, left mid-rebase with a real conflict already in progress, reusing rebase_mechanic.rebase_onto() against two real diverging branches.
  • plugins/dev-team/fixtures/resolve-rebase-conflict/test_build_fixture.py (new) — 18 pytest tests confirming each scenario builder produces exactly the conflict state it claims to.
  • plugins/dev-team/fixtures/resolve-rebase-conflict/RUN.md (new) — run procedure: fixture contents, invocation model (on-demand, not CI), materialize/run/grade steps for each of the three scenarios.

No production Python files were modified — rebase_mechanic.py and rebase_onto() are untouched, as neither needed changes for this task.

Design decisions

  • Implemented the skill directly rather than dispatching through implement-tdd, per the ADR-319 (harvest-playbook) precedent: implement-tdd's tester/implementer/refactorer loop is built around AAA pytest assertions, which doesn't fit prose that makes judgment calls. Instead followed the same red/green stand-in — author the fixture harness first, then the prose, then grade the prose against the harness.
  • Scenario design: a CHANGELOG.md append-conflict (keep both entries) for single-file/multi-file's shared file, a JSON max_retries value conflict (brief states an explicit final target) for multi-file's second file, and a JSON backoff_multiplier value conflict where the brief states only intent, never a target value, for unresolvable.
  • multi-file's two files conflict from a single commit on each side (not two separate commits), since git auto-merges non-overlapping single-line edits across separate commits during a rebase — both files had to be touched in the same commit on both branches to guarantee a simultaneous conflict.

Testing completed

  • plugins/dev-team/fixtures/resolve-rebase-conflict/test_build_fixture.py — all 18 pytest tests pass, confirming each fixture scenario builder produces the exact conflict state (files, rebase-in-progress state, expected outcome, task-brief content) it claims to.
  • Dry-ran the finished skill against all three scenarios using a fresh subagent per scenario, given only the SKILL.md text, the materialized worktree, and the scenario's task-brief text. All three passed: single-file and multi-file merged correctly and reported "resolved" with a clean tree; unresolvable made no edits and reported "unresolved", explicitly citing the missing target value as the reason it stopped rather than guessing.
  • No E2E scenarios: this task has no Wrapper/Orchestrator component and no new externally-observable entry point — every component in scope is Testable, so verification followed the fixture-scenario harness instead.

…rness

resolve-rebase-conflict is agent-skill prose (Testable per component-taxonomy,
not a pure function): given a rebase already left in progress with conflicts
and the task's own brief/spec context, it reads each conflicted file's hunks,
resolves only what the context makes unambiguous, stages them, and drives
git rebase --continue to completion. Reports "resolved" or "unresolved";
never runs git push or git rebase --abort itself (the caller,
dev-team:watch-pr, does both as appropriate).

Verification follows the taxonomy's "whatever mechanism actually fits" for
prose Testable components (same precedent as ADR-319's harvest-playbook): a
scripted fixture-scenario harness at
plugins/dev-team/fixtures/resolve-rebase-conflict/ builds three real git
repos with a genuine rebase conflict already in progress (via
rebase_mechanic.rebase_onto(), following test_rebase_mechanic.py's
bare-origin-plus-clone construction pattern):

- single-file: one CHANGELOG.md hunk, resolvable from task context
- multi-file: CHANGELOG.md + a JSON settings file conflict together (same
  commit), both resolvable from task context
- unresolvable: a numeric setting both branches changed to different,
  equally-plausible values with no stated target — must decline to guess

build_fixture.py builds each scenario; test_build_fixture.py (18 tests, all
passing) confirms each one produces exactly the conflict it claims to.
RUN.md documents the on-demand (non-CI) run/grade procedure for the
judgment-shaped part of this check.

Dry-ran the finished skill against all three scenarios via a fresh subagent
blind to this authoring context: single-file and multi-file both correctly
merged both sides' content and reported "resolved" with a clean working
tree; unresolvable correctly stopped without editing anything and reported
"unresolved", citing the missing target value as the reason it couldn't
proceed.

No production Python file changes needed — rebase_mechanic.py is untouched
per the task brief.
@github-actions

Copy link
Copy Markdown

build-and-test: Python test results

Status: ✅ Passed

Test log

@jodavis-claude jodavis-claude left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed against the ADR-312 task brief and _spec_ConcurrentDevelopment.md (lines 503-526, 881-899). All five exit criteria are met:

  • SKILL.md implements the read-hunks / resolve-from-context / stage / git rebase --continue loop, stopping and reporting "unresolved" without partial edits when confidence is lacking (steps 1-6).
  • Never runs git push or git rebase --abort itself — explicitly deferred to the caller.
  • The three-scenario fixture harness (build_fixture.py, test_build_fixture.py, RUN.md) matches the spec's objective bar (single-file/single-hunk, multi-file, and a genuinely-unresolvable case), modeled closely on fixtures/playbook-harvesting and test_rebase_mechanic.py's real-git-repo construction pattern.
  • Ran test_build_fixture.py locally: all 18 tests pass.
  • The prose correctly classifies as Testable agent-skill-prose per component-taxonomy, and the direct-implementation-plus-dry-run-harness approach (bypassing implement-tdd) follows the ADR-319 precedent as flagged in the brief's own known-ambiguity note.

No Priority 1-4 issues found. One minor style suggestion posted inline. Also noting (non-blocking): _run_git is now duplicated with near-identical bodies across rebase_mechanic.py, test_rebase_mechanic.py, and this PR's build_fixture.py/test_build_fixture.py — all test/fixture-infra code so not required by component-taxonomy, but could be worth consolidating into a shared test-helper module if a fourth copy shows up.

Approving.

Comment thread plugins/dev-team/fixtures/resolve-rebase-conflict/build_fixture.py
@jodavis-claude
jodavis-claude marked this pull request as ready for review July 23, 2026 06:12
@jodavis-claude
jodavis-claude requested a review from jodavis July 23, 2026 06:13
@jodavis
jodavis merged commit 310b92a into feature/ADR-296-concurrency Jul 23, 2026
3 checks passed
@jodavis
jodavis deleted the dev/claude/ADR-312 branch July 23, 2026 12:53
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