Skip to content

Fix: graceful handling of StartAsync failures after PR #118#119

Merged
PureWeen merged 17 commits intomainfrom
fix/initialization-error-handling
Feb 16, 2026
Merged

Fix: graceful handling of StartAsync failures after PR #118#119
PureWeen merged 17 commits intomainfrom
fix/initialization-error-handling

Conversation

@PureWeen
Copy link
Owner

Problem

After PR #118, users with Persistent mode saved in settings but no running server get stuck with "⚠ Service not initialized. Call InitializeAsync first." because:

  1. Persistent server auto-start fails (no copilot binary found)
  2. Falls back to Embedded mode
  3. _client.StartAsync() throws (no system copilot installed)
  4. IsInitialized stays false — user is stuck forever

Fix

  • Wrap StartAsync in try/catch in both InitializeAsync and ReconnectAsync
  • On failure: dispose the broken client, set _client = null, set NeedsConfiguration = true
  • UI shows settings screen so user can fix their configuration

Test

  • Added StartAsync_WithUnreachableServer_Throws test proving the SDK throws on unreachable servers (validates the premise of the fix)
  • All 301 tests pass

PureWeen and others added 4 commits February 16, 2026 09:51
… return early to avoid later 'Service not initialized'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When StartAsync fails (e.g., persistent server down + no system copilot binary),
the catch blocks now dispose the failed CopilotClient and set _client = null.
This prevents a stale broken client reference that would cause NullReferenceException
on subsequent operations, and ensures the 'Service not initialized' guard checks
work correctly. Also fixes comment indentation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Validates the premise of the InitializeAsync/ReconnectAsync try/catch fix:
CopilotClient.StartAsync() throws when connecting to a non-existent server,
confirming the error handling path is defending against a real failure mode.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n tests

- Extract IChatDatabase, IServerManager, IWsBridgeClient, IDemoService interfaces
- Concrete classes implement their respective interfaces
- CopilotService constructor accepts interfaces (internal ctor for test injection)
- DI registration forwards interfaces to concrete singletons
- Add TestStubs.cs with stub implementations for all interfaces
- Add CopilotServiceInitializationTests.cs with 15 integration tests covering:
  - Pre-initialization guard checks (CreateSession/ResumeSession throw)
  - Demo mode initialization and session creation
  - Embedded mode failure → NeedsConfiguration
  - Persistent mode failure → NeedsConfiguration
  - Mode transitions (Demo → Embedded)
  - OnStateChanged event firing
  - Session cleanup on reconnect

All 316 tests pass. MAUI build succeeds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen force-pushed the fix/initialization-error-handling branch from 4ce0d5d to 5ada2f3 Compare February 16, 2026 16:11
PureWeen and others added 13 commits February 16, 2026 10:45
…stubs

- Add Debug log message in ReconnectAsync catch block to match InitializeAsync pattern
- Add #pragma warning disable/restore CS0067 around stub classes with unused events

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Root cause: SaveActiveSessionsToDisk() overwrites active-sessions.json with
only the currently in-memory sessions. During mode switches, sessions that
fail to restore (or haven't been restored yet) were permanently lost from
the file. If the app was killed mid-restore, the same data loss occurred.

Fix: SaveActiveSessionsToDisk now merges — it reads the existing file and
preserves entries whose session directory still exists on disk, even if
they aren't currently loaded in memory. This makes the operation safe to
call at any point during startup, restore, or mode switching.

Additional changes:
- Skip SaveActiveSessionsToDisk during restore (IsRestoring guard) to
  avoid unnecessary disk I/O per session
- Skip SessionStartEvent save during restore for same reason
- Track explicitly closed session IDs so merge doesn't re-add them
- Add LoadOrganization + ReconcileOrganization in ReconnectAsync (was
  missing vs InitializeAsync)
- Add detailed debug logging in RestorePreviousSessionsAsync
- Add 7 mode-switch integration tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- SetMode() in Settings.razor now calls settings.Save() immediately so the
  user's mode choice persists even if the app is killed before clicking
  Save & Reconnect (fixes mode reverting to Embedded on restart)
- Add FallbackNotice property to CopilotService — when persistent server
  can't start and we fall back to Embedded, a dismissable warning banner
  is shown on the Dashboard with a link to Settings
- Add 'Report Bug' button in the sidebar footer that expands inline to
  collect a description and auto-attach debug info (mode, session count,
  platform, crash log tail), then submits via gh CLI to PureWeen/PolyPilot
- Remove duplicate UiState/ActiveSessionEntry classes from test project
  (now compiled in via Compile Include from CopilotService.cs)
- Add tests for FallbackNotice, ClearFallbackNotice, mode persistence

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 7 new unit tests: CliSource default, switching, independence from
  mode, serialization round-trip, mode switch preserving CliSource,
  ResolveBundledCliPath safety, and unique scenario IDs validation
- Add 3 new UI scenarios: CLI source switch persistence, mode persists
  without Save & Reconnect, bug report button visibility
- Add scenario cross-reference tests for new scenarios
- Update copilot-instructions.md:
  - Fix default mode (Persistent, not Embedded) for desktop
  - Document mode switching & merge-based session persistence
  - Document test safety rules (never call Save/Load, use Demo mode)
  - Add new test files to coverage section

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Report Bug: creates a GitHub issue via gh CLI with debug info attached.
Fix/Feature: creates a worktree on a new branch, writes a prompt file
with the bug description + debug info + coding conventions, then
launches copilot CLI in a new Terminal.app window pointed at the
worktree. The prompt instructs copilot to fix the issue, add tests
and scenarios, then create a PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ng issues

The osascript -e '...' approach with UseShellExecute mangled the quotes.
Now writes both the shell script and AppleScript to temp files, which
osascript reads directly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
osascript-spawned Terminal inherits the MAUI app's sandbox restrictions,
causing 'Permission denied' errors for the copilot CLI. Using 'open -a Terminal'
launches Terminal.app as a fully independent process with no sandbox.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Without --yolo, copilot CLI tries to prompt for directory/tool permissions
and fails with 'Permission denied and could not request permission from user'
when launched non-interactively in a new worktree.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Shows a yellow hint bar below the mode cards when the user switches
between Embedded/Persistent, with a Reconnect Now button. Hint
disappears after successful reconnect.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds --resume flag so copilot stays interactive after processing the
initial prompt. User can follow up, provide more context, or guide
the fix directly in the terminal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
-p is non-interactive and exits after completion. -i starts interactive
mode, executes the prompt, then keeps the session open for follow-up
conversation in the terminal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen merged commit a37bcf9 into main Feb 16, 2026
@PureWeen PureWeen deleted the fix/initialization-error-handling branch February 22, 2026 00:15
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.

1 participant