Skip to content

Auto-dispatch PR conflict resolution from PR poller - #57

Merged
chihsuan merged 11 commits into
mainfrom
auto/RSM-3739
May 21, 2026
Merged

Auto-dispatch PR conflict resolution from PR poller#57
chihsuan merged 11 commits into
mainfrom
auto/RSM-3739

Conversation

@chihsuan

@chihsuan chihsuan commented May 21, 2026

Copy link
Copy Markdown
Member

Context

PR review polling needs to detect merge conflicts and dispatch agents to resolve them semantically.

TL;DR

Dispatch agent-owned PR merge conflict resolution from the review poller.

Summary

  • Fetch PR mergeability and base/head metadata during review polling.
  • Store conflict context, dedupe by head/base key, and cap repeated dispatches.
  • Inject conflict-resolution instructions and sanitized metadata into the next prompt.
  • Clear conflict state when PRs become clean, close, or merge.

Alternatives

  • Keep conflict handling in CI polling; rejected because mergeability is PR state.
  • Add new config keys; rejected because existing PR review records can store context.

Test Plan

  • make all blocked locally by AF_UNIX socket bind :eperm in app-server socket tests.
  • mix format --check-formatted
  • mix lint
  • mix specs.check
  • mix test prompt safety, prompt builder, PR poller, and GitHub PR tests
  • MIX_HOME=/private/tmp/symphony-mix-home HEX_HOME=/private/tmp/symphony-hex-home mix dialyzer --format short
  • git diff --check origin/main..HEAD

chihsuan added 3 commits May 21, 2026 18:44
Summary:
- Fetch GitHub mergeability and base/head metadata during PR review
  polling.
- Persist conflict context, dedupe by head/base identity, enforce a
  retry cap, and inject conflict instructions into the next prompt.
- Add focused coverage for conflict dispatch, dedupe, escalation,
  cleanup, active-run suppression, prompt text, and GitHub parsing.

Rationale:
- Merge conflicts are PR review state, not CI state, so the PR review
  poller should hand semantic conflict resolution back to the normal
  agent workflow.
- Keeping the conflict key in the existing PR review record avoids a
  new store table or config contract while preventing repeated dispatch
  loops for the same conflict.

Tests:
- mix test test/symphony_elixir/pr_review_poller_test.exs test/symphony_elixir/github_pull_request_test.exs test/symphony_elixir/core_test.exs:2263
- mix specs.check
- mix lint
- git diff --check
- make all (fails in full app-server tests with {:mcp_socket_open_failed, :eperm}; coverage then misses the 100% threshold)
Summary:
- Remove unreachable non-map fallback clauses from PR conflict helpers.
- Cover PR conflict prompt fallback values for string timestamps and
  invalid retry limits.

Rationale:
- Dialyzer can prove PR review conflict helpers only receive maps at these
  call sites, so the defensive catch-all clauses were dead code.
- The added prompt assertions exercise fallback branches that CI coverage
  previously reported as missed.

Tests:
- mix test test/symphony_elixir/core_test.exs:2268 test/symphony_elixir/pr_review_poller_test.exs test/symphony_elixir/github_pull_request_test.exs
- mix specs.check
- MIX_HOME=/private/tmp/rsm-3739-mix-home HEX_HOME=/private/tmp/rsm-3739-hex-home mix dialyzer --format short
- mix format --check-formatted
- mix lint
- git diff --check
- make all (fails locally: app-server MCP socket setup returns {:mcp_socket_open_failed, :eperm})
Summary:
- Let conflict helper functions accept any input shape so Dialyzer no
  longer reports unreachable fallback clauses.
- Cover compact prompt PR conflict instructions and metadata.

Rationale:
- The PR conflict flow normalizes map-like persisted data at the call
  sites, so the helper guards were narrower than the inferred types.
- Compact prompts share the same conflict section as full prompts and
  need direct coverage to keep the 100% coverage gate green.

Tests:
- mix test test/symphony_elixir/pr_review_poller_test.exs test/symphony_elixir/prompt_builder_test.exs test/symphony_elixir/github_pull_request_test.exs test/symphony_elixir/core_test.exs:2263
- mix dialyzer --format short
- mix test.coverage
- mix specs.check
- mix lint
- mix format --check-formatted
- git diff --check
- make all (fails locally: app-server MCP socket setup returns eperm;
  PromptBuilder reports 100% before coverage fails from those test
  failures)
@chihsuan

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR extends Symphony’s PR review polling flow to detect GitHub merge conflicts, persist conflict context (including head/base identity), and auto-dispatch an agent-owned conflict-resolution run by moving the Linear issue back to In Progress while injecting conflict instructions/metadata into the next agent prompt.

Changes:

  • Fetch additional PR mergeability + head/base metadata via gh pr view --json ... and expose it through GitHub.PullRequest.fetch_activity/2.
  • Add merge-conflict detection/deduping/escalation logic to PrReviewPoller, persist conflict context in PR review records, and expose pending_pr_conflict/2 for prompt injection.
  • Inject merge-conflict context/instructions into both full and compact prompts, and wire the injection into AgentRunner.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/symphony_elixir/pr_review_poller.ex Detect merge conflicts from PR activity, store conflict context, dedupe by head/base key, dispatch/escalate, and expose pending_pr_conflict/2.
lib/symphony_elixir/github/pull_request.ex Extend gh pr view fields and normalize mergeability/head/base metadata into activity.
lib/symphony_elixir/prompt_builder.ex Add pr_conflict normalization and append a conflict section (instructions + metadata) to prompts.
lib/symphony_elixir/agent_runner.ex Include pr_conflict in first-turn prompt options and use it in continuation stopping logic.
test/symphony_elixir/pr_review_poller_test.exs Add coverage for conflict dispatch, dedupe, escalation, active-run suppression, and cleanup behavior.
test/symphony_elixir/github_pull_request_test.exs Update expectations for expanded gh pr view --json fields and decoded activity fields.
test/symphony_elixir/prompt_builder_test.exs Assert compact prompt includes conflict instructions and metadata.
test/symphony_elixir/core_test.exs Assert prompt builder injects conflict instructions/metadata and handles partial/missing fields.
SPEC.md Document conflict detection/dispatch behavior in the poller spec.
docs/configuration.md Document merge conflict detection + prompt injection behavior for the PR review poller.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/symphony_elixir/prompt_builder.ex Outdated
@chihsuan

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

Copilot AI and others added 2 commits May 21, 2026 14:12
Co-authored-by: chihsuan <4344253+chihsuan@users.noreply.github.com>
Co-authored-by: chihsuan <4344253+chihsuan@users.noreply.github.com>

Copilot AI commented May 21, 2026

Copy link
Copy Markdown

@copilot resolve the merge conflicts in this pull request

Resolved and pushed in commit 9420a44. I merged origin/main into this branch and fixed the three semantic conflicts in lib/symphony_elixir/github/pull_request.ex, lib/symphony_elixir/pr_review_poller.ex, and test/symphony_elixir/github_pull_request_test.exs.

Summary:
- Add bounded prompt-safety normalization for inline PR conflict fields.
- Apply that normalization before conflict metadata reaches workflow
  templates or compact prompt rendering.
- Cover both render paths with malicious and overlong conflict metadata.

Rationale:
- PR conflict metadata can include human-authored titles and branch names.
  Sanitizing it before rendering keeps conflict prompts bounded and avoids
  confusing control text in untrusted input sections.

Tests:
- mix test test/symphony_elixir/prompt_safety_test.exs test/symphony_elixir/prompt_builder_test.exs test/symphony_elixir/pr_review_poller_test.exs test/symphony_elixir/github_pull_request_test.exs
- mix specs.check
- git diff --check
- MIX_HOME=/private/tmp/symphony-mix-home HEX_HOME=/private/tmp/symphony-hex-home mix dialyzer --format short
- make all (blocked by MCP socket bind returning {:mcp_socket_open_failed,
  :eperm}; coverage then fails below the 100% threshold)

Copilot AI commented May 21, 2026

Copy link
Copy Markdown

@copilot resolve the merge conflicts in this pull request

Resolved by merging latest origin/main into this branch and pushing commit 37a50ed, which clears the PR merge conflicts. No UI changes in this PR, so there is no screenshot to share.

@copilot resolve the merge conflicts in this pull request

Done — I merged latest origin/main into this branch and pushed commit 37a50ed to resolve the merge conflicts. No UI changes in this PR, so there is no screenshot to share.

chihsuan added 2 commits May 21, 2026 22:24
Summary:
- Add the formatter-required blank line in the GitHub PR activity test.
- Wrap long PR review poller branches and a long AppServer test assertion.
- Replace a one-branch cond with if/else in config schema validation.

Rationale:
- The reviewer-reported format and credo failures blocked the gate.
- The additional small style fixes keep the full lint command green without
  changing runtime behavior.

Tests:
- mix format --check-formatted
- mix test test/symphony_elixir/github_pull_request_test.exs test/symphony_elixir/pr_review_poller_test.exs
- mix specs.check
- mix lint
- mix test test/symphony_elixir/app_server_test.exs:1858 failed locally
  before the touched assertion with {:mcp_socket_open_failed, :eperm}
Summary:
- Restore the event-specific assert_received pattern for malformed command
  completion recovery messages.
- Keep the assertion formatter-friendly without binding the first generic
  app-server mailbox message.

Rationale:
- The prior lint rewrite consumed :session_started before the recovery event,
  which regressed the test assertion and failed CI.

Tests:
- mix format --check-formatted test/symphony_elixir/app_server_test.exs
- mix lint
- git diff --check -- test/symphony_elixir/app_server_test.exs
- mix test test/symphony_elixir/app_server_test.exs:1858 blocked locally by
  {:mcp_socket_open_failed, :eperm}
@chihsuan

Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	test/symphony_elixir/app_server_test.exs

Co-authored-by: chihsuan <4344253+chihsuan@users.noreply.github.com>

Copilot AI commented May 21, 2026

Copy link
Copy Markdown

@copilot resolve the merge conflicts in this pull request

Resolved in commit 0b60ad2 by merging latest origin/main into this branch and fixing the remaining merge conflict in test/symphony_elixir/app_server_test.exs. No UI changes in this PR, so screenshot is not applicable.

@chihsuan
chihsuan merged commit ec435a3 into main May 21, 2026
9 checks passed
@chihsuan
chihsuan deleted the auto/RSM-3739 branch May 25, 2026 06:00
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