When plan apply encounters a merge conflict (user edited the same file
between execute and apply), the git merge leaves conflict markers in
the project files and the repo in an unmerged state.
Fix:
- Read conflict detail from CalledProcessError.stdout (git writes
conflict info to stdout, not stderr)
- Run git merge --abort to restore the repo to a clean state
- Catch subprocess.TimeoutExpired on both merge and abort calls
- Check abort return code and include error detail on failure
- Return False from _apply_sandbox_changes on failure so the calling
code does NOT complete the apply phase
- Transition plan to constrained state via service.constrain_apply()
per spec §18334-18336 (plan may revert to Strategize for re-planning)
- Fall back to 'Unknown merge error' when stdout+stderr are empty
Tests: 7 Behave scenarios covering merge conflict abort, abort failure,
_apply_sandbox_changes return value (True/False), clean merge, merge
timeout, abort timeout, and flat file copy failure.
ISSUES CLOSED: #7250