# Seed: psyche-sync-setup UX pass — error formatting, doctor partial-state, recovery docs

**Source:** https://paste.rs/47EE5 (captured 2026-05-28)
**Severity:** LOW–MEDIUM — operator-experience defects, no data loss
**Surface:** v1.11.21 (current live)
**Diagnosed in:** `.planning/debug/sync-setup-data-loss.md`
**Depends on:** Phase 35.2 (data-loss + bootstrap-determinism land first)

## The Problem

Four operator-experience defects across the `psyche-sync-setup` surface, identified during root-cause investigation for the data-loss bug (Phase 35.2). Bundled here because:
- They share the same skill / binary surface.
- They become coherent only after 35.2's per-ref dispatcher output exists (Issue 3 in particular).
- They are individually too small for a standalone phase.

## The Fixes

### Fix 1 (Issue 4): Display formatting for SyncError surface
- `src/owl/psyche_sync_setup.rs:70` — flip `eprintln!("sync setup failed: {:?}", e)` to `{}`.
- Verify `SyncError` Display impl at `src/common/sync.rs:400-413` covers all variants the user can hit (currently bypassed by `{:?}`).
- Removes literal Rust struct syntax from user-facing error output (`GitFailed(Nonzero { stderr: "..." })` → human-readable string).

### Fix 2 (Issue 6): Doctor partial-state detection
- `src/owl/doctor.rs::check_sync_status:1130-1145` currently keys solely off `SyncState`. When `accept_flow` succeeds at push but fails at `write_sync_settings` (Step 6, `sync.rs:597`), state stays `Unset` while the remote is fully seeded — doctor falsely reports "sync: not configured".
- Add probe: when `state == Unset`, check `seed/.git/config` for an `origin` remote AND `git ls-remote origin` succeeds. If yes, surface a Warn row labeled "partial setup" pointing the operator at recovery.
- Optional refinement: persist `accept_flow_attempt_ts` in `SyncSettings` pre-push so doctor can distinguish "never attempted" from "attempted but write failed".

### Fix 3 (Issue 5): Document exit code 1
- `plugin/spt/skills/psyche-sync-setup/SKILL.md` — exit-code section lists 0/2/3/4/5; add bullet for 1 ("generic `accept_flow` failure — see stderr; see Issue 3 recovery").

### Fix 4 (Issue 3): Recovery path for exit-1
- Phase 35.2's per-ref dispatcher output obsoletes the `git update-ref`-against-bare-repo workaround for most cases.
- Document the residual recovery path in SKILL.md (or a sibling doc): what to do when reconciliation surfaces an unresolvable divergence (operator inspection of `seed/`, manual `rebase` decision, escape hatch to `--disable` and re-setup).

## Deployment Notes

- Single coordinated rollout via standard GSD workflow (`/gsd-plan-phase`)
- Atomic commits per fix subsection for independent revertability
- Test surface: doctor partial-state fixture (push succeeds, settings write fails); error-format snapshot test for `SyncError` Display path
- Skill docs verification — exit-code completeness check

## Out of Scope (handled by Phase 35.2)
- Data-loss reconciliation logic in `accept_flow`
- Deterministic bootstrap in `ensure_seed`
- Per-ref push semantics

This bundle = surface polish only. Behavior changes confined to error formatting, doctor reporting, and documentation.
