- Add SqliteForeignKeyInterceptor (DbConnectionInterceptor) registered via
OnConfiguring so every IDbContextFactory-created context runs
PRAGMA foreign_keys=ON, not only the MigrateAndConfigure context.
- DefaultListsSeeder: replace TOCTOU read-then-insert with atomic
INSERT … SELECT … WHERE NOT EXISTS — one SQLite writer lock, no race.
- AppSettingsRepository.GetAsync: catch DbUpdateException on the
get-or-create path and re-read so concurrent startup cannot throw.
- Migration 20260609000000_UniqueListName: de-duplicates empty list rows
(startup-race leftovers) then adds a UNIQUE index on lists.name.
- ForeignKeyTests: verifies ON DELETE SET NULL (blocked_by_task_id) is
enforced on a fresh DbContext with no manual PRAGMA call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolved sub-tasks are no longer appended to the prompt. Extracted into a
shared TaskPromptComposer so the UI's description preview can render the same
'what Claude gets' text.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Details island review commands (Approve/Reject/Park/Cancel) invoked the
hub without catching exceptions. After "Merge all" folds the parent out of
WaitingForReview, pressing Approve made the hub throw a HubException, which
escaped the generated AsyncRelayCommand as an unobserved async-void exception
and crashed the app. Wrap the calls in try/catch like the Tasks island does;
the TaskUpdated broadcast reconciles the UI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add MaxTurns to ListRepository.SetConfigAsync upsert branch and
TaskRepository.UpdateAgentSettingsAsync; fix positional CancellationToken
call in ConfigMcpTools. Covered by MaxTurnsRoundTripTests (2 tests).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A test that spawns the actual claude binary shouldn't live in the suite —
dotnet test must never invoke Claude. §1.0 step 3 stays a manual check.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Spawns the actual claude binary and asserts exit code 0, a session id,
non-empty result, and output tokens > 0 (plan-verification §1.0 step 3).
Inert unless CLAUDE_AUTHENTICATED=1, since it needs an authenticated CLI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add error-path + git-backed happy-path tests for the five previously
untested ExternalMcpService tools: GetTaskWorktree, GetTaskDiff,
MergeTask (dry-run + not-Done guard), ListWorktrees, CleanupTaskWorktree.
Git-backed cases skip when git is unavailable.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
If WorktreeAddAsync succeeds but the worktrees-row insert throws, the
worktree was left on disk and branch undeleted with nothing tracking it.
Wrap the insert in try/catch and best-effort remove the worktree+branch
(non-cancellable) before rethrowing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>