transit verdict Ready to push PR #192 commits 8 files 120 touched lines +1,202 / -313 head 1dbff75

Pre-push review: Transit PR #192

Fresh review of git diff origin/main...HEAD at exact head 1dbff7549501c275b0554755fa6f383dcb3256f7. The prior verdict was Needs fixes; this pass independently rechecked those fixes and the complete migration.

At a glance

  • Scope: 120 files, dominated by 98 Swift test files; no Transit/Transit/ production source changed.
  • Prior finding resolved: the narrow SwiftLint regex was replaced by an executable, lexical and structural ownership validator wired into both make lint and make lint-fix.
  • Guard coverage: accepted owner-carrying patterns pass; raw factories, removed helpers, direct/inferred construction, aliases, conditional/delegated/cleared retention, interpolation, and invalid support structure are rejected.
  • Lifetime proof: the local fixture leaves scope, its weak container remains alive, the escaped context saves, and a fresh context from the retained container fetches the saved model.
  • Validation: make lint, git diff --check, and all 1,565 macOS unit tests passed. The full iOS scheme recorded 1,125 passes with all six failures in UI tests; dedicated UI execution reproduced 18 passes and the same six failures amid Xcode no debugger version errors.

Verdict

Ready to push

No current correctness, ownership, migration, quality, or documentation finding remains. The executable ownership guard closes the previous enforcement gap and the complete unit/lint validation passes. The six reproducible UI failures are isolated to the unchanged UI suite and coincide with Xcode missing-debugger-store errors; they are recorded below as a non-branch caveat.

Author's PR description

Shown verbatim — the markdown the author wrote, unmodified.

Arjen Schwarz · 2026-08-01
## Summary
- replace the context-only `TestModelContainer.newContext()` API with a fixture that owns both `ModelContainer` and `ModelContext`
- migrate 207 context-acquisition call sites across 92 test/helper files and consolidate the bespoke task-entity, task-creation-result, and report helpers
- add a fixture lifetime regression and update repository guidance/reporting

## Root cause
Test helpers returned only `ModelContext` while their locally created `ModelContainer` was released at helper return. Later SwiftData model access could therefore hit an invalid backing store and crash nondeterministically with `SIGTRAP`/`EXC_BREAKPOINT`.

## Validation
- `make test-quick PIPE_PRETTY=` — passed
- `make lint` — passed
- static search — zero `newContext()`, `makeReportTestContext()`, local-container-to-context returns, or context-only helper declarations
- `make test PIPE_PRETTY=` — iOS unit tests completed successfully; the scheme then entered UI tests, where unrelated `testClearAll` and `testEditViewPreservesTaskMilestone` failures occurred before the runner hung retrying launches with `DebuggerLLDB.DebuggerVersionStore.StoreError` / `no debugger version`

See `specs/bugfixes/test-contexts-drop-swiftdata-containers/report.md` for the investigation and migration details.

Commits

Three-level explanation

What changed

Tests used to ask a helper for only a SwiftData context. That could discard the container backing the context too early. Tests now keep a TestModelContainer fixture that owns both objects, and the repository automatically rejects future context-only helpers.

Why it matters

This removes nondeterministic test crashes caused by invalid SwiftData lifetime rather than changing app behavior. The migration is test-only.

Completeness

The old factories are absent, test call sites use the owning fixture, documentation describes the lifetime rule, and a regression test proves escaped-context use remains valid.

Architecture

TestModelContainer centralizes schema/configuration construction, exposes both container and context, and retains every backing container in a private static array. Helpers that need to return contexts carry an owner or retain the fixture.

Enforcement

The Python validator masks comments and string bodies without losing interpolation code, then applies lexical and structural checks. A shell fixture harness verifies safe and unsafe examples before scanning the repository, and Makefile lint targets depend on it.

Trade-off

Static retention is intentionally unbounded for the lifetime of the test process. That uses some memory but makes SwiftData backing-store lifetime deterministic across helper boundaries and parallel test shapes.

Deep dive

The regression protects the exact ownership failure mode: fixture scope ends, a weak container witness remains non-nil, writes occur through the escaped context, and an independently-created context against the retained container observes persisted state. This tests backing-container viability, not merely context object liveness.

Guard invariants

The support-file validator requires one centralized ModelContainer constructor directly inside an initializer, ordered top-level assignments to self.container and self.context, one private static retention declaration, and one unconditional append. Repository scanning prohibits aliases, inferred and explicit direct construction, context-only factories, and removed fixture APIs.

Architecture impact

No production module or user-facing API changes. The broad diff is mechanical ownership plumbing plus test-support policy. The retained array is @MainActor-isolated through the fixture, matching SwiftData test setup usage.

Important changes — detailed

TestModelContainer becomes the single owning fixture

Transit/TransitTests/TestModelContainer.swift

Why it matters. This is the correctness boundary that prevents contexts from outliving their backing SwiftData container.

What to look at. TestModelContainer initializers and retainedContainers

Takeaway. Return or retain an owner whenever an API exposes a dependent SwiftData context.
Rationale. Centralized construction plus process-lifetime retention makes test backing-store lifetime explicit and deterministic.

Executable validator replaces the narrow lint regex

scripts/validate_test_model_container_ownership.py

Why it matters. The previous rule could miss aliases, inferred constructors, interpolation, and structurally unsafe retention changes.

What to look at. mask_swift_noncode, repository rules, and support-file structural validation

Takeaway. Position-preserving lexical masking can make repository policy checks robust without pretending regex is a full parser.
Rationale. The ownership policy spans lexical and ordered structural invariants that SwiftLint custom regex cannot express.

Ownership fixtures exercise accepted and unsafe forms

tests/validation/test_model_container_ownership_guard.sh

Why it matters. The guard itself is now regression-tested against bypasses and false positives before it scans real sources.

What to look at. accepted/unsafe fixture loop and repository scan

Takeaway. Policy validators should ship with both positive and adversarial fixtures.
Rationale. Executable examples make future validator hardening reviewable and prevent silent narrowing.

Makefile lint gates ownership safety

Makefile

Why it matters. A correct validator is only useful if standard local and CI workflows run it.

What to look at. lint, lint-fix, and test-model-container-ownership-guard targets

Takeaway. Attach repository-specific invariants to existing developer entry points instead of relying on manual checks.
Rationale. Both regular and auto-fix lint flows must reject unsafe fixture ownership.

Lifetime regression tests post-scope persistence

Transit/TransitTests/TestModelContainerLifetimeTests.swift

Why it matters. It proves the actual failure mode rather than only asserting that an object reference exists.

What to look at. makeEscapedContext and escapedContextKeepsBackingContainerAvailableForItsFullUse

Takeaway. Lifetime regressions should exercise the dependent resource after owner scope exits and verify state through a fresh consumer.
Rationale. Weak observation plus save/refetch catches both premature deallocation and unusable backing storage.

Reports helper and guidance document ownership

docs/agent-notes/reports.md

Why it matters. The previous documentation encouraged a context-only helper shape that could recreate the bug.

What to look at. makeReportTestContainer guidance

Takeaway. Document lifetime contracts at helper call sites, not only in the central fixture.
Rationale. Report tests use shared helper patterns, so their guidance must explicitly preserve the owner.

Key decisions

Retain test containers for the test-process lifetime. A private static array trades bounded test-process memory for deterministic backing-store lifetime. The validator prohibits conditional, delegated, or clearable retention.
Validate semantics with executable fixtures. The guard combines comment/string masking, interpolation preservation, repository pattern checks, and ordered support-file structure checks, then tests those semantics with accepted and adversarial source fixtures.
Keep application behavior untouched. The migration changes test support, tests, repository validation, and documentation only; there are no production source changes. (inferred — not stated by the author.)

Per-file diffs

Click to expand.

CHANGELOG.md Modified +2 / -0
diff --git a/CHANGELOG.md b/CHANGELOG.mdindex b958c3b..7870fe7 100644--- a/CHANGELOG.md+++ b/CHANGELOG.md@@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).  ### Fixed +- SwiftData test fixtures now retain their backing `ModelContainer` for the full test lifetime (T-2003). `TestModelContainer` is a container-owning fixture instead of a bare-context factory, 207 context-acquisition call sites across 92 test files were migrated, and bespoke context helpers in task-entity, task-creation-result, and report tests now delegate to the shared fixture. An escaped-context lifetime regression plus an executable ownership guard with positive/negative fixtures prevent raw container/context factories from recurring.+ - Cross-device milestone name conflicts no longer make name-based operations target an arbitrary record (T-1938). `MilestoneService.findByName` now throws on multiple project-scoped matches; all MCP and App Intent callers report the ambiguity (`AMBIGUOUS_MILESTONE` for intents). Launch/foreground/connectivity maintenance deterministically keeps the oldest milestone name and renames other UUID-distinct records with UUID-derived suffixes, preserving records and task assignments. Cross-context tests simulate CloudKit imports and verify ambiguity reporting, reconciliation, idempotence, and data preservation. - Task mutation surfaces no longer hide duplicate task display IDs behind a not-found error (T-1837). `TaskService.findByDisplayID` already threw `duplicateDisplayID` when several tasks share a `permanentDisplayId` (possible under CloudKit, which cannot enforce uniqueness), but MCP `update_task_status` / `update_task` / `add_comment`, `UpdateStatusIntent`, `IntentHelpers.resolveTask`, and the visual `AddCommentIntent` all collapsed it into `TASK_NOT_FOUND` / "Provide either displayId or taskId", so operators could not tell missing data from store corruption needing display-ID maintenance. Duplicates now report `INTERNAL_ERROR` with the hint `Duplicate task identifier for displayId N` (App Intents — matching the milestone paths and the T-1097 `QueryTasksIntent` fix) or an `isError` result reading `Duplicate task identifier detected for displayId N` (MCP — matching the milestone tools). MCP `query_tasks` uses the same wording instead of leaking `Lookup failed: duplicateDisplayID`. No new error code was introduced. The three MCP call sites now share `resolveTaskArgument`, `UpdateStatusIntent` routes through `IntentHelpers.resolveTask` instead of its own copy of the mapping, and `VisualIntentError` gains a `duplicateIdentifier` case (code `INTERNAL_ERROR`). Regression coverage in `DuplicateTaskDisplayIDIntentTests` and `MCPDuplicateTaskDisplayIDTests`. - The MCP `add_comment` handler now distinguishes a missing required field from a present-but-non-string one for `content` and `authorName` (T-1579). Previously `guard let value = args[key] as? String, !value.isEmpty` collapsed numbers, booleans, arrays, and null into `Missing required argument: content` / `Missing required argument: authorName`, misleading callers into thinking they omitted a field they actually supplied with the wrong type. A present non-string value now returns the field-specific `content must be a string` / `authorName must be a string` before any task resolution or comment creation, matching the hardened pattern used by `update_task_status` after T-1205. Extracted a `requiredString(_:key:)` helper to keep `handleAddComment` within the cyclomatic-complexity limit. Regression coverage added in `MCPAddCommentTypeValidationTests` (numeric/boolean/array/null `content` and `authorName`).
CLAUDE.md Modified +3 / -2
diff --git a/CLAUDE.md b/CLAUDE.mdindex 90dd7a2..ed5cbea 100644--- a/CLAUDE.md+++ b/CLAUDE.md@@ -195,8 +195,9 @@ Services follow a consistent pattern: mutate in memory, then `save()`, rolling b ## Test Infrastructure  - **Swift Testing** framework (not XCTest) for unit tests-- **TestModelContainer** singleton (`TransitTests/TestModelContainer.swift`) — shared in-memory container with `cloudKitDatabase: .none` and explicit `Schema` including all five models. All three properties (schema, in-memory, no CloudKit) are required to avoid conflicts.-- Each test gets a fresh `ModelContext` via `TestModelContainer.newContext()`+- **TestModelContainer** fixture (`TransitTests/TestModelContainer.swift`) — creates an isolated in-memory container with `cloudKitDatabase: .none` and an explicit `Schema` including all five models. All three properties (schema, in-memory, no CloudKit) are required to avoid conflicts.+- Each test constructs `let testContainer = try TestModelContainer()` and derives `testContainer.context`; helpers that create SwiftData storage should return or store the owning fixture rather than only a context/service+- Custom-schema and multi-context tests use `TestModelContainer(schema:configurations:)`; direct `ModelContainer` construction and raw container/context factories in test sources are rejected by the ownership guard run from `make lint` - SwiftData test suites must use `@Suite(.serialized)` to prevent concurrent access issues - UI tests use `TRANSIT_UI_TEST_SCENARIO` environment variable (`empty` or `board`) for deterministic seeded data - MCP tool handler tests use `MCPTestHelpers.swift` for common setup patterns
Makefile Modified +6 / -2
diff --git a/Makefile b/Makefileindex fc56bf9..892dff6 100644--- a/Makefile+++ b/Makefile@@ -57,12 +57,16 @@ help: # reproducible across interactive, CI, and sandboxed runs. SWIFTLINT_CACHE = .swiftlint-cache +.PHONY: test-model-container-ownership-guard+test-model-container-ownership-guard:+	bash tests/validation/test_model_container_ownership_guard.sh+ .PHONY: lint-lint:+lint: test-model-container-ownership-guard 	swiftlint lint --strict --cache-path $(SWIFTLINT_CACHE)  .PHONY: lint-fix-lint-fix:+lint-fix: test-model-container-ownership-guard 	swiftlint lint --fix --strict --cache-path $(SWIFTLINT_CACHE)  # Building
Transit/TransitTests/ActionButtonSaveErrorTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/ActionButtonSaveErrorTests.swift b/Transit/TransitTests/ActionButtonSaveErrorTests.swiftindex d56071c..c2a7717 100644--- a/Transit/TransitTests/ActionButtonSaveErrorTests.swift+++ b/Transit/TransitTests/ActionButtonSaveErrorTests.swift@@ -17,7 +17,8 @@ struct ActionButtonSaveErrorTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/AddCommentIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/AddCommentIntentTests.swift b/Transit/TransitTests/AddCommentIntentTests.swiftindex 2a159ed..efd56aa 100644--- a/Transit/TransitTests/AddCommentIntentTests.swift+++ b/Transit/TransitTests/AddCommentIntentTests.swift@@ -13,7 +13,8 @@ struct AddCommentIntentTests {     }      private func makeServices() throws -> TestServices {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return TestServices(
Transit/TransitTests/AddTaskIntentIntegrationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/AddTaskIntentIntegrationTests.swift b/Transit/TransitTests/AddTaskIntentIntegrationTests.swiftindex a103f46..6ab74a9 100644--- a/Transit/TransitTests/AddTaskIntentIntegrationTests.swift+++ b/Transit/TransitTests/AddTaskIntentIntegrationTests.swift@@ -12,7 +12,8 @@ struct AddTaskIntentIntegrationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/AddTaskIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/AddTaskIntentTests.swift b/Transit/TransitTests/AddTaskIntentTests.swiftindex 37052ee..36a65a0 100644--- a/Transit/TransitTests/AddTaskIntentTests.swift+++ b/Transit/TransitTests/AddTaskIntentTests.swift@@ -12,7 +12,8 @@ struct AddTaskIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/AddTaskSheetResetTests.swift Modified +6 / -3
diff --git a/Transit/TransitTests/AddTaskSheetResetTests.swift b/Transit/TransitTests/AddTaskSheetResetTests.swiftindex 3619504..ca53b51 100644--- a/Transit/TransitTests/AddTaskSheetResetTests.swift+++ b/Transit/TransitTests/AddTaskSheetResetTests.swift@@ -31,7 +31,8 @@ struct AddTaskSheetResetTests {      @Test("Default project picks the first project when none selected")     func defaultProjectPicksFirstWhenNil() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let alpha = makeProject(name: "Alpha", in: context)         let beta = makeProject(name: "Beta", in: context)         let projects = [alpha, beta]@@ -42,7 +43,8 @@ struct AddTaskSheetResetTests {      @Test("Default project keeps current selection when it still exists")     func defaultProjectKeepsCurrentWhenValid() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let alpha = makeProject(name: "Alpha", in: context)         let beta = makeProject(name: "Beta", in: context)         let projects = [alpha, beta]@@ -53,7 +55,8 @@ struct AddTaskSheetResetTests {      @Test("Default project falls back to first when current project no longer exists")     func defaultProjectFallsBackWhenCurrentMissing() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let alpha = makeProject(name: "Alpha", in: context)         let projects = [alpha] 
Transit/TransitTests/AddTaskSheetSaveErrorTests.swift Modified +4 / -2
diff --git a/Transit/TransitTests/AddTaskSheetSaveErrorTests.swift b/Transit/TransitTests/AddTaskSheetSaveErrorTests.swiftindex 61d44e8..ee04537 100644--- a/Transit/TransitTests/AddTaskSheetSaveErrorTests.swift+++ b/Transit/TransitTests/AddTaskSheetSaveErrorTests.swift@@ -28,7 +28,8 @@ struct AddTaskSheetSaveErrorTests {     }      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)@@ -36,7 +37,8 @@ struct AddTaskSheetSaveErrorTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         return Services(
Transit/TransitTests/BackwardCompatibilityFormatTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/BackwardCompatibilityFormatTests.swift b/Transit/TransitTests/BackwardCompatibilityFormatTests.swiftindex 9549364..3fccdaf 100644--- a/Transit/TransitTests/BackwardCompatibilityFormatTests.swift+++ b/Transit/TransitTests/BackwardCompatibilityFormatTests.swift@@ -19,7 +19,8 @@ struct BackwardCompatibilityFormatTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/BackwardCompatibilityTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/BackwardCompatibilityTests.swift b/Transit/TransitTests/BackwardCompatibilityTests.swiftindex f39d42d..2139071 100644--- a/Transit/TransitTests/BackwardCompatibilityTests.swift+++ b/Transit/TransitTests/BackwardCompatibilityTests.swift@@ -19,7 +19,8 @@ struct BackwardCompatibilityTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/BoolAsIntIdRejectionTests.swift Modified +1 / -1
diff --git a/Transit/TransitTests/BoolAsIntIdRejectionTests.swift b/Transit/TransitTests/BoolAsIntIdRejectionTests.swiftindex aadd611..68f81c7 100644--- a/Transit/TransitTests/BoolAsIntIdRejectionTests.swift+++ b/Transit/TransitTests/BoolAsIntIdRejectionTests.swift@@ -24,7 +24,7 @@ struct BoolAsIntIdRejectionTests {     }      private func makeIntentServices() throws -> IntentServices {-        let context = try TestModelContainer.newContext()+        let context = try TestModelContainer().context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         return IntentServices(
Transit/TransitTests/CancelledCreateTests.swift Modified +4 / -2
diff --git a/Transit/TransitTests/CancelledCreateTests.swift b/Transit/TransitTests/CancelledCreateTests.swiftindex 822174c..c827071 100644--- a/Transit/TransitTests/CancelledCreateTests.swift+++ b/Transit/TransitTests/CancelledCreateTests.swift@@ -93,7 +93,8 @@ struct CancelledCreateTests {     /// A task create that is cancelled while queued behind a gate-holding create     /// must throw `CancellationError` and must NOT persist any (provisional) task.     @Test func cancelledTaskCreateDoesNotPersistProvisionalRecord() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = GatedCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)@@ -139,7 +140,8 @@ struct CancelledCreateTests {     /// A milestone create that is cancelled while queued behind a gate-holding     /// create must throw `CancellationError` and must NOT persist any record.     @Test func cancelledMilestoneCreateDoesNotPersistProvisionalRecord() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = GatedCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/CommentServiceTests.swift Modified +5 / -4
diff --git a/Transit/TransitTests/CommentServiceTests.swift b/Transit/TransitTests/CommentServiceTests.swiftindex f5cb4a6..7060c32 100644--- a/Transit/TransitTests/CommentServiceTests.swift+++ b/Transit/TransitTests/CommentServiceTests.swift@@ -9,7 +9,8 @@ struct CommentServiceTests {     // MARK: - Helpers      private func makeService() throws -> (CommentService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let service = CommentService(modelContext: context)         return (service, context)     }@@ -192,13 +193,13 @@ struct CommentServiceTests {             isStoredInMemoryOnly: true,             cloudKitDatabase: .none         )-        let container = try ModelContainer(for: schema, configurations: [config])+        let testContainer = try TestModelContainer(schema: schema, configurations: [config])          // "mainContext" — analogous to the @Query context in the view layer-        let mainContext = container.mainContext+        let mainContext = testContainer.container.mainContext          // "serviceContext" — analogous to the separate ModelContext the service uses-        let serviceContext = ModelContext(container)+        let serviceContext = ModelContext(testContainer.container)         let service = CommentService(modelContext: serviceContext)          // Create a task in mainContext (simulating @Query producing the task)
Transit/TransitTests/ConcurrentDisplayIDCreationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/ConcurrentDisplayIDCreationTests.swift b/Transit/TransitTests/ConcurrentDisplayIDCreationTests.swiftindex d5dacba..e37afbf 100644--- a/Transit/TransitTests/ConcurrentDisplayIDCreationTests.swift+++ b/Transit/TransitTests/ConcurrentDisplayIDCreationTests.swift@@ -78,7 +78,8 @@ struct ConcurrentDisplayIDCreationTests {     /// allocator so the two never share `issuedID` state. Each test exercises only     /// one entity type, so the allocators are independent in practice.     private func makeServices(makeStore: () -> DisplayIDAllocator.CounterStore) throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: makeStore())         let milestoneAllocator = DisplayIDAllocator(store: makeStore())         return Services(
Transit/TransitTests/ConcurrentMilestoneNameUniquenessTests.swift Modified +6 / -3
diff --git a/Transit/TransitTests/ConcurrentMilestoneNameUniquenessTests.swift b/Transit/TransitTests/ConcurrentMilestoneNameUniquenessTests.swiftindex a3b3478..29af254 100644--- a/Transit/TransitTests/ConcurrentMilestoneNameUniquenessTests.swift+++ b/Transit/TransitTests/ConcurrentMilestoneNameUniquenessTests.swift@@ -121,7 +121,8 @@ struct ConcurrentMilestoneNameUniquenessTests {     /// holder is parked in allocation, so the check is already stale by the time the     /// contender resumes — it must re-check before inserting.     @Test func interleavedCreatesWithSameNameRejectTheSecond() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = GatedCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)@@ -161,7 +162,8 @@ struct ConcurrentMilestoneNameUniquenessTests {     /// The re-check must not over-reject: two overlapping creates with *different*     /// names in the same project both belong in the store.     @Test func interleavedCreatesWithDifferentNamesBothSucceed() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = GatedCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)@@ -194,7 +196,8 @@ struct ConcurrentMilestoneNameUniquenessTests {     /// project-scoped: the same name in two different projects is legal even when the     /// creates interleave.     @Test func interleavedCreatesWithSameNameInDifferentProjectsBothSucceed() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = GatedCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/ConcurrentPromotionTests.swift Modified +12 / -6
diff --git a/Transit/TransitTests/ConcurrentPromotionTests.swift b/Transit/TransitTests/ConcurrentPromotionTests.swiftindex 1edbbe0..3f3cb0a 100644--- a/Transit/TransitTests/ConcurrentPromotionTests.swift+++ b/Transit/TransitTests/ConcurrentPromotionTests.swift@@ -29,7 +29,8 @@ struct ConcurrentPromotionTests {         // suspension point inside promoteProvisionalTasks, which is not worth         // the production-code complexity. The guard is tested indirectly via         // the GuardResetsAfterFailure/Completion tests below.-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 10)         let allocator = DisplayIDAllocator(store: store, retryLimit: 3) @@ -55,7 +56,8 @@ struct ConcurrentPromotionTests {     @Test func taskPromotionGuardResetsAfterCompletion() async throws {         // After a completed promotion, the guard must reset so new         // provisional tasks created later can be promoted.-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, retryLimit: 3) @@ -87,7 +89,8 @@ struct ConcurrentPromotionTests {     @Test func taskPromotionGuardResetsAfterFailure() async throws {         // After a failed promotion (save error), the guard must reset so a         // subsequent call can retry.-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, retryLimit: 3) @@ -118,7 +121,8 @@ struct ConcurrentPromotionTests {         // Verifies that a second sequential promotion call does not allocate         // duplicate IDs. See taskPromotionSecondCallIsNoOp for the rationale         // on why this does not exercise the guard directly.-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 20)         let allocator = DisplayIDAllocator(store: store, retryLimit: 3)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)@@ -142,7 +146,8 @@ struct ConcurrentPromotionTests {     }      @Test func milestonePromotionGuardResetsAfterCompletion() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, retryLimit: 3)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)@@ -170,7 +175,8 @@ struct ConcurrentPromotionTests {     }      @Test func milestonePromotionGuardResetsAfterFailure() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, retryLimit: 3)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/CreateMilestoneIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/CreateMilestoneIntentTests.swift b/Transit/TransitTests/CreateMilestoneIntentTests.swiftindex d188f90..da6e536 100644--- a/Transit/TransitTests/CreateMilestoneIntentTests.swift+++ b/Transit/TransitTests/CreateMilestoneIntentTests.swift@@ -15,7 +15,8 @@ struct CreateMilestoneIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/CreateTaskIntentMilestoneTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/CreateTaskIntentMilestoneTests.swift b/Transit/TransitTests/CreateTaskIntentMilestoneTests.swiftindex 033e424..463dbbe 100644--- a/Transit/TransitTests/CreateTaskIntentMilestoneTests.swift+++ b/Transit/TransitTests/CreateTaskIntentMilestoneTests.swift@@ -17,7 +17,8 @@ struct CreateTaskIntentMilestoneTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskStore = InMemoryCounterStore()         let taskAllocator = DisplayIDAllocator(store: taskStore)         let milestoneStore = InMemoryCounterStore()
Transit/TransitTests/CreateTaskIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/CreateTaskIntentTests.swift b/Transit/TransitTests/CreateTaskIntentTests.swiftindex d20b5e9..718f04b 100644--- a/Transit/TransitTests/CreateTaskIntentTests.swift+++ b/Transit/TransitTests/CreateTaskIntentTests.swift@@ -18,7 +18,8 @@ struct CreateTaskIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/DataMaintenanceResultCollisionTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DataMaintenanceResultCollisionTests.swift b/Transit/TransitTests/DataMaintenanceResultCollisionTests.swiftindex 8ac9932..f9490c9 100644--- a/Transit/TransitTests/DataMaintenanceResultCollisionTests.swift+++ b/Transit/TransitTests/DataMaintenanceResultCollisionTests.swift@@ -20,7 +20,8 @@ struct DataMaintenanceResultCollisionTests {     }      private func makeEnv() throws -> TestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore(initialNextDisplayID: 1))         let milestoneAllocator = DisplayIDAllocator(             store: InMemoryCounterStore(initialNextDisplayID: 1)
Transit/TransitTests/DeleteMilestoneIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DeleteMilestoneIntentTests.swift b/Transit/TransitTests/DeleteMilestoneIntentTests.swiftindex 2d74925..251138e 100644--- a/Transit/TransitTests/DeleteMilestoneIntentTests.swift+++ b/Transit/TransitTests/DeleteMilestoneIntentTests.swift@@ -15,7 +15,8 @@ struct DeleteMilestoneIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/DisplayIDMaintenanceIntentsTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DisplayIDMaintenanceIntentsTests.swift b/Transit/TransitTests/DisplayIDMaintenanceIntentsTests.swiftindex 9084743..35ef56b 100644--- a/Transit/TransitTests/DisplayIDMaintenanceIntentsTests.swift+++ b/Transit/TransitTests/DisplayIDMaintenanceIntentsTests.swift@@ -22,7 +22,8 @@ struct DisplayIDMaintenanceIntentsTests {      /// Builds a maintenance service backed by an isolated in-memory context.     private func makeIntentEnv() throws -> IntentEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let commentService = CommentService(modelContext: context)
Transit/TransitTests/DisplayIDMaintenanceServiceReassignTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DisplayIDMaintenanceServiceReassignTests.swift b/Transit/TransitTests/DisplayIDMaintenanceServiceReassignTests.swiftindex 3098349..87a79c4 100644--- a/Transit/TransitTests/DisplayIDMaintenanceServiceReassignTests.swift+++ b/Transit/TransitTests/DisplayIDMaintenanceServiceReassignTests.swift@@ -24,7 +24,8 @@ struct DisplayIDMaintenanceServiceReassignTests {         milestoneCounterStart: Int = 1,         clock: @escaping () -> Date = { Date(timeIntervalSince1970: 1_700_000_000) }     ) throws -> TestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskStore = InMemoryCounterStore(initialNextDisplayID: taskCounterStart)         let milestoneStore = InMemoryCounterStore(initialNextDisplayID: milestoneCounterStart)         let taskAllocator = DisplayIDAllocator(store: taskStore)
Transit/TransitTests/DisplayIDMaintenanceServiceScanTests.swift Modified +20 / -10
diff --git a/Transit/TransitTests/DisplayIDMaintenanceServiceScanTests.swift b/Transit/TransitTests/DisplayIDMaintenanceServiceScanTests.swiftindex 0cd8123..b4b3592 100644--- a/Transit/TransitTests/DisplayIDMaintenanceServiceScanTests.swift+++ b/Transit/TransitTests/DisplayIDMaintenanceServiceScanTests.swift@@ -54,7 +54,8 @@ struct DisplayIDMaintenanceServiceScanTests {     // MARK: - Tests      @Test func emptyContextReturnsEmptyGroups() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let service = makeService(context: context)          let report = try service.scanDuplicates()@@ -63,7 +64,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func twoTasksSharingDisplayIdReportedOnce() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         _ = makeTask(in: context, project: project, name: "A", displayId: 5,                      creationDate: Date(timeIntervalSince1970: 1000))@@ -81,7 +83,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func twoMilestonesSharingDisplayIdReportedOnce() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         _ = makeMilestone(in: context, project: project, name: "M-Old", displayId: 3,                           creationDate: Date(timeIntervalSince1970: 1000))@@ -99,7 +102,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func provisionalRecordsExcluded() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         _ = makeTask(in: context, project: project, name: "A", displayId: nil)         _ = makeTask(in: context, project: project, name: "B", displayId: nil)@@ -115,7 +119,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func taskAndMilestoneSharingIntegerIsNotADuplicate() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         _ = makeTask(in: context, project: project, name: "T-5", displayId: 5)         _ = makeMilestone(in: context, project: project, name: "M-5", displayId: 5)@@ -128,7 +133,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func oldestCreationDateWins() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let oldId = UUID()         let newId = UUID()@@ -151,7 +157,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func uuidAscendingTiebreakerWhenCreationDateEqual() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let date = Date(timeIntervalSince1970: 1000)         let uuidA = UUID(uuidString: "00000000-0000-0000-0000-000000000001")!@@ -171,7 +178,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func projectNilYieldsNoProjectLiteral() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let orphan1 = makeTask(in: context, project: project, name: "Orphan1", displayId: 11)         let orphan2 = makeTask(in: context, project: project, name: "Orphan2", displayId: 11)@@ -190,7 +198,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func groupsOrderedByAscendingDisplayId() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         _ = makeTask(in: context, project: project, name: "A1", displayId: 7)         _ = makeTask(in: context, project: project, name: "A2", displayId: 7)@@ -208,7 +217,8 @@ struct DisplayIDMaintenanceServiceScanTests {     }      @Test func winnerFirstOrderingPreservedAcrossManyLosers() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let winnerId = UUID()         _ = makeTask(in: context, project: project, name: "Loser1", displayId: 4,
Transit/TransitTests/DisplayIDMaintenanceStaleCounterTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DisplayIDMaintenanceStaleCounterTests.swift b/Transit/TransitTests/DisplayIDMaintenanceStaleCounterTests.swiftindex 65ce032..ddfacef 100644--- a/Transit/TransitTests/DisplayIDMaintenanceStaleCounterTests.swift+++ b/Transit/TransitTests/DisplayIDMaintenanceStaleCounterTests.swift@@ -62,7 +62,8 @@ struct DisplayIDMaintenanceStaleCounterTests {         taskStore: any DisplayIDAllocator.CounterStore,         milestoneStore: any DisplayIDAllocator.CounterStore     ) throws -> TestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let service = DisplayIDMaintenanceService(             modelContext: context,             taskAllocator: DisplayIDAllocator(store: taskStore),
Transit/TransitTests/DragDropStatusTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DragDropStatusTests.swift b/Transit/TransitTests/DragDropStatusTests.swiftindex 8b07d11..5a181a4 100644--- a/Transit/TransitTests/DragDropStatusTests.swift+++ b/Transit/TransitTests/DragDropStatusTests.swift@@ -21,7 +21,8 @@ struct DragDropStatusTests {     private func makeServiceAndTask(         status: TaskStatus     ) throws -> (service: TaskService, task: TransitTask) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/DuplicateTaskDisplayIDIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/DuplicateTaskDisplayIDIntentTests.swift b/Transit/TransitTests/DuplicateTaskDisplayIDIntentTests.swiftindex 511c908..38d34c0 100644--- a/Transit/TransitTests/DuplicateTaskDisplayIDIntentTests.swift+++ b/Transit/TransitTests/DuplicateTaskDisplayIDIntentTests.swift@@ -24,7 +24,8 @@ struct DuplicateTaskDisplayIDIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         return Services(
Transit/TransitTests/EffectivePriorityInvariantTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/EffectivePriorityInvariantTests.swift b/Transit/TransitTests/EffectivePriorityInvariantTests.swiftindex c63a077..c071df0 100644--- a/Transit/TransitTests/EffectivePriorityInvariantTests.swift+++ b/Transit/TransitTests/EffectivePriorityInvariantTests.swift@@ -31,7 +31,8 @@ struct EffectivePriorityInvariantTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/FallbackOutcomeFixture.swift Modified +5 / -1
diff --git a/Transit/TransitTests/FallbackOutcomeFixture.swift b/Transit/TransitTests/FallbackOutcomeFixture.swiftindex e9f3cfc..418c98d 100644--- a/Transit/TransitTests/FallbackOutcomeFixture.swift+++ b/Transit/TransitTests/FallbackOutcomeFixture.swift@@ -44,7 +44,11 @@ enum FallbackOutcomeFixture {             schema: schema, configuration: config         ) { innerSchema, innerConfig in             if failPrimaryStore { throw InjectedFailure.primaryCreationFailed }-            return try ModelContainer(for: innerSchema, configurations: [innerConfig])+            let testContainer = try TestModelContainer(+                schema: innerSchema,+                configurations: [innerConfig]+            )+            return testContainer.container         }     } }
Transit/TransitTests/FallbackStorageIntentRejectionTests.swift Modified +3 / -1
diff --git a/Transit/TransitTests/FallbackStorageIntentRejectionTests.swift b/Transit/TransitTests/FallbackStorageIntentRejectionTests.swiftindex 81a3a38..80dea58 100644--- a/Transit/TransitTests/FallbackStorageIntentRejectionTests.swift+++ b/Transit/TransitTests/FallbackStorageIntentRejectionTests.swift@@ -36,7 +36,9 @@ struct FallbackStorageIntentRejectionTests {             ? FallbackOutcomeFixture.degraded             : FallbackOutcomeFixture.makeHealthy() -        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()++        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let commentService = CommentService(modelContext: context)
Transit/TransitTests/FetchFailureInvariantTests.swift Modified +18 / -9
diff --git a/Transit/TransitTests/FetchFailureInvariantTests.swift b/Transit/TransitTests/FetchFailureInvariantTests.swiftindex 1083fb5..7051ff3 100644--- a/Transit/TransitTests/FetchFailureInvariantTests.swift+++ b/Transit/TransitTests/FetchFailureInvariantTests.swift@@ -37,7 +37,8 @@ struct FetchFailureInvariantTests {     // MARK: - T-1614: project name uniqueness      @Test func projectCreateWithUnreadableStoreDoesNotCommitDuplicateName() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let working = ProjectService(modelContext: context)         try working.createProject(name: "Transit", description: "", gitRepo: nil, colorHex: "#FF0000") @@ -54,7 +55,8 @@ struct FetchFailureInvariantTests {     }      @Test func projectRenameWithUnreadableStoreDoesNotCommitDuplicateName() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let working = ProjectService(modelContext: context)         try working.createProject(name: "Transit", description: "", gitRepo: nil, colorHex: "#FF0000")         let orbit = try working.createProject(name: "Orbit", description: "", gitRepo: nil, colorHex: "#00FF00")@@ -73,7 +75,8 @@ struct FetchFailureInvariantTests {     // MARK: - T-1614: milestone name uniqueness      @Test func milestoneCreateWithUnreadableStoreDoesNotCommitDuplicateName() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let allocator = DisplayIDAllocator(store: InMemoryCounterStore())         let project = try ProjectService(modelContext: context)             .createProject(name: "Transit", description: "", gitRepo: nil, colorHex: "#FF0000")@@ -94,7 +97,8 @@ struct FetchFailureInvariantTests {     }      @Test func milestoneRenameWithUnreadableStoreDoesNotCommitDuplicateName() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let allocator = DisplayIDAllocator(store: InMemoryCounterStore())         let project = try ProjectService(modelContext: context)             .createProject(name: "Transit", description: "", gitRepo: nil, colorHex: "#FF0000")@@ -131,7 +135,8 @@ struct FetchFailureInvariantTests {     }      @Test func taskCreateWithUnreadableStoreDoesNotReissueCommittedDisplayID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try seedTaskHoldingID5(in: context)         let allocator = DisplayIDAllocator(store: InMemoryCounterStore(initialNextDisplayID: 5)) @@ -153,7 +158,8 @@ struct FetchFailureInvariantTests {     }      @Test func taskCreateWithReadableStoreStillSkipsPastTheInUseID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try seedTaskHoldingID5(in: context)         let allocator = DisplayIDAllocator(store: InMemoryCounterStore(initialNextDisplayID: 5)) @@ -167,7 +173,8 @@ struct FetchFailureInvariantTests {     }      @Test func milestonePromotionWithUnreadableStoreDoesNotReissueCommittedDisplayID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try ProjectService(modelContext: context)             .createProject(name: "Transit", description: "", gitRepo: nil, colorHex: "#FF0000")         let committed = Milestone(name: "v1.0", description: nil, project: project, displayID: .permanent(5))@@ -193,7 +200,8 @@ struct FetchFailureInvariantTests {     }      @Test func taskPromotionWithUnreadableStoreDoesNotReissueCommittedDisplayID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try seedTaskHoldingID5(in: context)         let provisional = TransitTask(             name: "Pending", description: nil, type: .bug, project: project, displayID: .provisional@@ -218,7 +226,8 @@ struct FetchFailureInvariantTests {     }      @Test func taskPromotionWithReadableStoreStillPromotesPastTheInUseID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try seedTaskHoldingID5(in: context)         let provisional = TransitTask(             name: "Pending", description: nil, type: .bug, project: project, displayID: .provisional
Transit/TransitTests/FindTasksIntentIntegrationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/FindTasksIntentIntegrationTests.swift b/Transit/TransitTests/FindTasksIntentIntegrationTests.swiftindex 35bc7ab..5d8806b 100644--- a/Transit/TransitTests/FindTasksIntentIntegrationTests.swift+++ b/Transit/TransitTests/FindTasksIntentIntegrationTests.swift@@ -20,7 +20,8 @@ struct FindTasksIntentIntegrationTests {     }      private func makeEnv() throws -> TestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return TestEnv(
Transit/TransitTests/FindTasksIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/FindTasksIntentTests.swift b/Transit/TransitTests/FindTasksIntentTests.swiftindex 7280e15..f7f7def 100644--- a/Transit/TransitTests/FindTasksIntentTests.swift+++ b/Transit/TransitTests/FindTasksIntentTests.swift@@ -45,7 +45,8 @@ struct FindTasksIntentTests {     }      private func makeEnv() throws -> TestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return TestEnv(
Transit/TransitTests/GenerateReportIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/GenerateReportIntentTests.swift b/Transit/TransitTests/GenerateReportIntentTests.swiftindex b14a9b2..73d07f1 100644--- a/Transit/TransitTests/GenerateReportIntentTests.swift+++ b/Transit/TransitTests/GenerateReportIntentTests.swift@@ -14,7 +14,8 @@ struct GenerateReportIntentTests {     }      private func makeEnv() throws -> TestEnv {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let store = InMemoryCounterStore()         return TestEnv(             context: ctx,
Transit/TransitTests/IntegrationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/IntegrationTests.swift b/Transit/TransitTests/IntegrationTests.swiftindex f434c97..5784ba5 100644--- a/Transit/TransitTests/IntegrationTests.swift+++ b/Transit/TransitTests/IntegrationTests.swift@@ -17,7 +17,8 @@ struct IntentDashboardIntegrationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/IntentCompatibilityAndDiscoverabilityTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/IntentCompatibilityAndDiscoverabilityTests.swift b/Transit/TransitTests/IntentCompatibilityAndDiscoverabilityTests.swiftindex b51f454..1190a8c 100644--- a/Transit/TransitTests/IntentCompatibilityAndDiscoverabilityTests.swift+++ b/Transit/TransitTests/IntentCompatibilityAndDiscoverabilityTests.swift@@ -14,7 +14,8 @@ struct IntentCompatibilityTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/IntentCreateNonStringProjectTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/IntentCreateNonStringProjectTests.swift b/Transit/TransitTests/IntentCreateNonStringProjectTests.swiftindex dc471d3..1e00fe2 100644--- a/Transit/TransitTests/IntentCreateNonStringProjectTests.swift+++ b/Transit/TransitTests/IntentCreateNonStringProjectTests.swift@@ -25,7 +25,8 @@ struct IntentCreateNonStringProjectTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/IntentEndToEndTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/IntentEndToEndTests.swift b/Transit/TransitTests/IntentEndToEndTests.swiftindex 7d938aa..e82c96a 100644--- a/Transit/TransitTests/IntentEndToEndTests.swift+++ b/Transit/TransitTests/IntentEndToEndTests.swift@@ -19,7 +19,8 @@ struct IntentEndToEndTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/IntentHelpersTaskUpdateResponseDictTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/IntentHelpersTaskUpdateResponseDictTests.swift b/Transit/TransitTests/IntentHelpersTaskUpdateResponseDictTests.swiftindex 1cc01a8..87513e5 100644--- a/Transit/TransitTests/IntentHelpersTaskUpdateResponseDictTests.swift+++ b/Transit/TransitTests/IntentHelpersTaskUpdateResponseDictTests.swift@@ -18,7 +18,8 @@ struct IntentHelpersTaskUpdateResponseDictTests {     }      private func makeFixture(includeProject: Bool = true) throws -> Fixture {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = Project(             name: "Test Project", description: "A test project", gitRepo: nil, colorHex: "#FF0000"         )
Transit/TransitTests/IntentNonStringDescriptionTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/IntentNonStringDescriptionTests.swift b/Transit/TransitTests/IntentNonStringDescriptionTests.swiftindex 7033a2e..d1a053f 100644--- a/Transit/TransitTests/IntentNonStringDescriptionTests.swift+++ b/Transit/TransitTests/IntentNonStringDescriptionTests.swift@@ -22,7 +22,8 @@ struct IntentNonStringDescriptionTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/MCPFallbackStorageRejectionTests.swift Modified +3 / -1
diff --git a/Transit/TransitTests/MCPFallbackStorageRejectionTests.swift b/Transit/TransitTests/MCPFallbackStorageRejectionTests.swiftindex 1634097..5fee034 100644--- a/Transit/TransitTests/MCPFallbackStorageRejectionTests.swift+++ b/Transit/TransitTests/MCPFallbackStorageRejectionTests.swift@@ -29,7 +29,9 @@ struct MCPFallbackStorageRejectionTests {             ? FallbackOutcomeFixture.degraded             : FallbackOutcomeFixture.makeHealthy() -        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()++        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let commentService = CommentService(modelContext: context)
Transit/TransitTests/MCPTestHelpers.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MCPTestHelpers.swift b/Transit/TransitTests/MCPTestHelpers.swiftindex 5137019..d8f1fd5 100644--- a/Transit/TransitTests/MCPTestHelpers.swift+++ b/Transit/TransitTests/MCPTestHelpers.swift@@ -19,7 +19,8 @@ struct MCPTestEnv { enum MCPTestHelpers {      static func makeEnv() throws -> MCPTestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskStore = InMemoryCounterStore()         let taskAllocator = DisplayIDAllocator(store: taskStore)         let taskService = TaskService(modelContext: context, displayIDAllocator: taskAllocator)
Transit/TransitTests/MilestoneCrossDeviceUniquenessTests.swift Modified +6 / -5
diff --git a/Transit/TransitTests/MilestoneCrossDeviceUniquenessTests.swift b/Transit/TransitTests/MilestoneCrossDeviceUniquenessTests.swiftindex d744cd2..ed83a50 100644--- a/Transit/TransitTests/MilestoneCrossDeviceUniquenessTests.swift+++ b/Transit/TransitTests/MilestoneCrossDeviceUniquenessTests.swift@@ -12,7 +12,7 @@ import Testing struct MilestoneCrossDeviceUniquenessTests {      private struct Environment {-        let container: ModelContainer+        let testContainer: TestModelContainer         let projectID: UUID         let firstMilestoneID: UUID         let secondMilestoneID: UUID@@ -35,7 +35,8 @@ struct MilestoneCrossDeviceUniquenessTests {     }      private func makeSyncedDuplicateEnvironment() throws -> Environment {-        let container = try TestModelContainer.newContainer()+        let testContainer = try TestModelContainer()+        let container = testContainer.container          let firstDevice = ModelContext(container)         let project = Project(@@ -78,7 +79,7 @@ struct MilestoneCrossDeviceUniquenessTests {         try secondDevice.save()          return Environment(-            container: container,+            testContainer: testContainer,             projectID: project.id,             firstMilestoneID: first.id,             secondMilestoneID: second.id@@ -97,7 +98,7 @@ struct MilestoneCrossDeviceUniquenessTests {      @Test func nameLookupDoesNotChooseAnArbitrarySyncedDuplicate() throws {         let environment = try makeSyncedDuplicateEnvironment()-        let receivingDevice = ModelContext(environment.container)+        let receivingDevice = ModelContext(environment.testContainer.container)         let service = makeService(in: receivingDevice)         let projectID = environment.projectID         let descriptor = FetchDescriptor<Project>(predicate: #Predicate { $0.id == projectID })@@ -110,7 +111,7 @@ struct MilestoneCrossDeviceUniquenessTests {      @Test func postSyncMaintenanceReconcilesNamesWithoutDeletingRecords() async throws {         let environment = try makeSyncedDuplicateEnvironment()-        let receivingDevice = ModelContext(environment.container)+        let receivingDevice = ModelContext(environment.testContainer.container)         let service = makeService(in: receivingDevice)          // App launch, foregrounding, and connectivity restoration already invoke this
Transit/TransitTests/MilestoneDisplayNameTests.swift Modified +6 / -4
diff --git a/Transit/TransitTests/MilestoneDisplayNameTests.swift b/Transit/TransitTests/MilestoneDisplayNameTests.swiftindex 512327f..efdcbf4 100644--- a/Transit/TransitTests/MilestoneDisplayNameTests.swift+++ b/Transit/TransitTests/MilestoneDisplayNameTests.swift@@ -6,8 +6,8 @@ import Testing @MainActor @Suite(.serialized) struct MilestoneDisplayNameTests { -    private func makeContext() throws -> ModelContext {-        try TestModelContainer.newContext()+    private func makeTestContainer() throws -> TestModelContainer {+        try TestModelContainer()     }      private func makeProject(in context: ModelContext, name: String) -> Project {@@ -20,7 +20,8 @@ struct MilestoneDisplayNameTests {      @Test("displayName includes project name when project exists")     func displayNameWithProject() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context, name: "Prism")         let milestone = Milestone(name: "Beta 1", project: project, displayID: .permanent(1))         context.insert(milestone)@@ -30,7 +31,8 @@ struct MilestoneDisplayNameTests {      @Test("displayName falls back to milestone name when project is nil")     func displayNameWithoutProject() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context, name: "Temp")         let milestone = Milestone(name: "Beta 1", project: project, displayID: .permanent(2))         context.insert(milestone)
Transit/TransitTests/MilestoneEditConcurrentUpdateTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MilestoneEditConcurrentUpdateTests.swift b/Transit/TransitTests/MilestoneEditConcurrentUpdateTests.swiftindex 6a324b4..5f99022 100644--- a/Transit/TransitTests/MilestoneEditConcurrentUpdateTests.swift+++ b/Transit/TransitTests/MilestoneEditConcurrentUpdateTests.swift@@ -15,7 +15,8 @@ struct MilestoneEditTestEnv {     let project: Project      static func make() throws -> MilestoneEditTestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let milestoneService = MilestoneService(             modelContext: context,             displayIDAllocator: DisplayIDAllocator(store: InMemoryCounterStore())
Transit/TransitTests/MilestoneFilterMenuTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MilestoneFilterMenuTests.swift b/Transit/TransitTests/MilestoneFilterMenuTests.swiftindex db84d0a..09b4588 100644--- a/Transit/TransitTests/MilestoneFilterMenuTests.swift+++ b/Transit/TransitTests/MilestoneFilterMenuTests.swift@@ -23,7 +23,8 @@ struct MilestoneFilterMenuTests {     }      @Test func availableMilestonesScopedToSelectedProjects() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let allocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneService = MilestoneService(modelContext: context, displayIDAllocator: allocator) 
Transit/TransitTests/MilestoneRenameTypeValidationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MilestoneRenameTypeValidationTests.swift b/Transit/TransitTests/MilestoneRenameTypeValidationTests.swiftindex 648a0f7..22316a7 100644--- a/Transit/TransitTests/MilestoneRenameTypeValidationTests.swift+++ b/Transit/TransitTests/MilestoneRenameTypeValidationTests.swift@@ -19,7 +19,8 @@ struct MilestoneRenameTypeValidationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/MilestoneServiceLookupTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MilestoneServiceLookupTests.swift b/Transit/TransitTests/MilestoneServiceLookupTests.swiftindex 6f781c9..8b6ea85 100644--- a/Transit/TransitTests/MilestoneServiceLookupTests.swift+++ b/Transit/TransitTests/MilestoneServiceLookupTests.swift@@ -9,7 +9,8 @@ struct MilestoneServiceLookupTests {     // MARK: - Helpers      private func makeService() throws -> (MilestoneService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/MilestoneServiceSameStatusTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MilestoneServiceSameStatusTests.swift b/Transit/TransitTests/MilestoneServiceSameStatusTests.swiftindex 9ec6d94..bac1972 100644--- a/Transit/TransitTests/MilestoneServiceSameStatusTests.swift+++ b/Transit/TransitTests/MilestoneServiceSameStatusTests.swift@@ -11,7 +11,8 @@ import Testing struct MilestoneServiceSameStatusTests {      private func makeService() throws -> (MilestoneService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/MilestoneServiceTests.swift Modified +4 / -2
diff --git a/Transit/TransitTests/MilestoneServiceTests.swift b/Transit/TransitTests/MilestoneServiceTests.swiftindex 956d425..020a8e9 100644--- a/Transit/TransitTests/MilestoneServiceTests.swift+++ b/Transit/TransitTests/MilestoneServiceTests.swift@@ -9,7 +9,8 @@ struct MilestoneServiceTests {     // MARK: - Helpers      private func makeService() throws -> (MilestoneService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)@@ -92,7 +93,8 @@ struct MilestoneServiceTests {     }      @Test func createMilestoneWithProvisionalIDOnAllocatorFailure() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         await store.enqueueSaveOutcomes([.failure(DisplayIDAllocator.Error.retriesExhausted)])         let allocator = DisplayIDAllocator(store: store, retryLimit: 1)
Transit/TransitTests/MilestoneStatusTypeValidationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/MilestoneStatusTypeValidationTests.swift b/Transit/TransitTests/MilestoneStatusTypeValidationTests.swiftindex 1ffab09..8a879f6 100644--- a/Transit/TransitTests/MilestoneStatusTypeValidationTests.swift+++ b/Transit/TransitTests/MilestoneStatusTypeValidationTests.swift@@ -19,7 +19,8 @@ struct MilestoneStatusTypeValidationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/ModelContextSaveHelpersTests.swift Modified +14 / -7
diff --git a/Transit/TransitTests/ModelContextSaveHelpersTests.swift b/Transit/TransitTests/ModelContextSaveHelpersTests.swiftindex deb8d68..7d8a40b 100644--- a/Transit/TransitTests/ModelContextSaveHelpersTests.swift+++ b/Transit/TransitTests/ModelContextSaveHelpersTests.swift@@ -26,7 +26,8 @@ struct ModelContextSaveHelpersTests {     // MARK: - saveOrRollback      @Test func saveOrRollbackPersistsMutation() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)          try context.saveOrRollback { project.name = "Renamed" }@@ -36,7 +37,8 @@ struct ModelContextSaveHelpersTests {     }      @Test func saveOrRollbackRevertsContextWhenMutationThrows() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)          #expect(throws: SaveFailure.self) {@@ -50,7 +52,8 @@ struct ModelContextSaveHelpersTests {     }      @Test func saveOrRollbackWithSaveFalseAppliesMutationWithoutPersisting() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)          try context.saveOrRollback(save: false) { project.name = "Renamed" }@@ -62,7 +65,8 @@ struct ModelContextSaveHelpersTests {     }      @Test func saveOrRollbackWithSaveFalseStillRevertsWhenMutationThrows() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)          #expect(throws: SaveFailure.self) {@@ -78,7 +82,8 @@ struct ModelContextSaveHelpersTests {     // MARK: - insertOrDelete      @Test func insertOrDeletePersistsModelOnSuccess() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .permanent(1)) @@ -89,7 +94,8 @@ struct ModelContextSaveHelpersTests {     }      @Test func insertOrDeleteRemovesInsertedModelOnSaveFailure() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)         let task = TransitTask(name: "Ghost", type: .feature, project: project, displayID: .permanent(1)) @@ -107,7 +113,8 @@ struct ModelContextSaveHelpersTests {     /// inserted model, *not* by rolling the context back. A rollback here would     /// also discard the user's unrelated unsaved edits on the shared main context.     @Test func insertOrDeleteFailurePreservesUnrelatedUnsavedEdits() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = try makePersistedProject(in: context)         let task = TransitTask(name: "Ghost", type: .feature, project: project, displayID: .permanent(1)) 
Transit/TransitTests/NonIntegerMilestoneDisplayIdTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/NonIntegerMilestoneDisplayIdTests.swift b/Transit/TransitTests/NonIntegerMilestoneDisplayIdTests.swiftindex 0819d1b..f790e5b 100644--- a/Transit/TransitTests/NonIntegerMilestoneDisplayIdTests.swift+++ b/Transit/TransitTests/NonIntegerMilestoneDisplayIdTests.swift@@ -19,7 +19,8 @@ struct NonIntegerMilestoneDisplayIdTests {     }      private func makeIntentServices() throws -> IntentServices {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         return IntentServices(
Transit/TransitTests/NonStringMilestoneArgTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/NonStringMilestoneArgTests.swift b/Transit/TransitTests/NonStringMilestoneArgTests.swiftindex 3ad108c..701a5d2 100644--- a/Transit/TransitTests/NonStringMilestoneArgTests.swift+++ b/Transit/TransitTests/NonStringMilestoneArgTests.swift@@ -21,7 +21,8 @@ struct NonStringMilestoneArgTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         let milestoneAllocator = DisplayIDAllocator(store: InMemoryCounterStore())         return Services(
Transit/TransitTests/NumericDisplayIdParsingTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/NumericDisplayIdParsingTests.swift b/Transit/TransitTests/NumericDisplayIdParsingTests.swiftindex 4535693..3e7d486 100644--- a/Transit/TransitTests/NumericDisplayIdParsingTests.swift+++ b/Transit/TransitTests/NumericDisplayIdParsingTests.swift@@ -14,7 +14,8 @@ struct NumericDisplayIdParsingTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/ProjectEditConcurrentUpdateTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/ProjectEditConcurrentUpdateTests.swift b/Transit/TransitTests/ProjectEditConcurrentUpdateTests.swiftindex 8bfbca7..6db0e33 100644--- a/Transit/TransitTests/ProjectEditConcurrentUpdateTests.swift+++ b/Transit/TransitTests/ProjectEditConcurrentUpdateTests.swift@@ -14,7 +14,8 @@ struct ProjectEditTestEnv {     let applier: ProjectEditApplier      static func make() throws -> ProjectEditTestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let projectService = ProjectService(modelContext: context)         return ProjectEditTestEnv(             context: context,
Transit/TransitTests/ProjectEditSaveErrorTests.swift Modified +10 / -6
diff --git a/Transit/TransitTests/ProjectEditSaveErrorTests.swift b/Transit/TransitTests/ProjectEditSaveErrorTests.swiftindex ec08713..502f232 100644--- a/Transit/TransitTests/ProjectEditSaveErrorTests.swift+++ b/Transit/TransitTests/ProjectEditSaveErrorTests.swift@@ -15,8 +15,8 @@ struct ProjectEditSaveErrorTests {      // MARK: - Helpers -    private func makeContext() throws -> ModelContext {-        try TestModelContainer.newContext()+    private func makeTestContainer() throws -> TestModelContainer {+        try TestModelContainer()     }      private func makeProject(@@ -36,7 +36,8 @@ struct ProjectEditSaveErrorTests {     // MARK: - Rollback restores project properties after failed save      @Test func rollbackRevertsNameChangeOnProject() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         try context.save() @@ -50,7 +51,8 @@ struct ProjectEditSaveErrorTests {     }      @Test func rollbackRevertsDescriptionChangeOnProject() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         try context.save() @@ -62,7 +64,8 @@ struct ProjectEditSaveErrorTests {     }      @Test func rollbackRevertsAllPropertyChangesOnProject() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         try context.save() @@ -86,7 +89,8 @@ struct ProjectEditSaveErrorTests {     }      @Test func rollbackRevertsGitRepoRemoval() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         try context.save() 
Transit/TransitTests/ProjectEntityTests.swift Modified +7 / -12
diff --git a/Transit/TransitTests/ProjectEntityTests.swift b/Transit/TransitTests/ProjectEntityTests.swiftindex ef71c9a..1b5548b 100644--- a/Transit/TransitTests/ProjectEntityTests.swift+++ b/Transit/TransitTests/ProjectEntityTests.swift@@ -5,24 +5,19 @@ import Testing  @MainActor @Suite(.serialized) struct ProjectEntityTests {+    @MainActor     private struct TestEnv {-        let context: ModelContext+        let testContainer: TestModelContainer         let projectService: ProjectService++        var context: ModelContext { testContainer.context }     }      private func makeEnv() throws -> TestEnv {-        let schema = Schema([Project.self, TransitTask.self, Milestone.self])-        let config = ModelConfiguration(-            "ProjectEntityTests-\(UUID().uuidString)",-            schema: schema,-            isStoredInMemoryOnly: true,-            cloudKitDatabase: .none-        )-        let container = try ModelContainer(for: schema, configurations: [config])-        let context = ModelContext(container)+        let testContainer = try TestModelContainer()         return TestEnv(-            context: context,-            projectService: ProjectService(modelContext: context)+            testContainer: testContainer,+            projectService: ProjectService(modelContext: testContainer.context)         )     } 
Transit/TransitTests/ProjectServiceTests.swift Modified +1 / -1
diff --git a/Transit/TransitTests/ProjectServiceTests.swift b/Transit/TransitTests/ProjectServiceTests.swiftindex a8633c5..a3b0fa9 100644--- a/Transit/TransitTests/ProjectServiceTests.swift+++ b/Transit/TransitTests/ProjectServiceTests.swift@@ -9,7 +9,7 @@ struct ProjectServiceTests {     // MARK: - Helpers      private func makeService() throws -> (ProjectService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let context = try TestModelContainer().context         let service = ProjectService(modelContext: context)         return (service, context)     }
Transit/TransitTests/ProjectServiceUpdateTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/ProjectServiceUpdateTests.swift b/Transit/TransitTests/ProjectServiceUpdateTests.swiftindex 7849e1b..af0a8b3 100644--- a/Transit/TransitTests/ProjectServiceUpdateTests.swift+++ b/Transit/TransitTests/ProjectServiceUpdateTests.swift@@ -14,7 +14,8 @@ struct ProjectServiceUpdateTests {     // MARK: - Helpers      private func makeService() throws -> (ProjectService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let service = ProjectService(modelContext: context)         return (service, context)     }
Transit/TransitTests/PromotionRollbackTests.swift Modified +8 / -4
diff --git a/Transit/TransitTests/PromotionRollbackTests.swift b/Transit/TransitTests/PromotionRollbackTests.swiftindex 0bee02e..4d591cb 100644--- a/Transit/TransitTests/PromotionRollbackTests.swift+++ b/Transit/TransitTests/PromotionRollbackTests.swift@@ -14,7 +14,8 @@ import Testing struct PromotionRollbackTests {      @Test func promoteProvisionalTasksFailedSavePreservesUnrelatedUnsavedEdits() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 100)         let allocator = DisplayIDAllocator(store: store, retryLimit: 1) @@ -42,7 +43,8 @@ struct PromotionRollbackTests {     }      @Test func promoteProvisionalMilestonesFailedSavePreservesUnrelatedUnsavedEdits() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 50)         let allocator = DisplayIDAllocator(store: store, retryLimit: 1)         let milestoneService = MilestoneService(modelContext: context, displayIDAllocator: allocator)@@ -66,7 +68,8 @@ struct PromotionRollbackTests {     }      @Test func promoteProvisionalTasksStopsOnAllocatorFailure() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 100)         await store.enqueueSaveOutcomes([             .success,@@ -96,7 +99,8 @@ struct PromotionRollbackTests {     }      @Test func promoteProvisionalMilestonesStopsOnAllocatorFailure() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore(initialNextDisplayID: 50)         await store.enqueueSaveOutcomes([             .success,
Transit/TransitTests/QueryAndDisplayIDIntegrationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryAndDisplayIDIntegrationTests.swift b/Transit/TransitTests/QueryAndDisplayIDIntegrationTests.swiftindex 5f285f4..1b726f0 100644--- a/Transit/TransitTests/QueryAndDisplayIDIntegrationTests.swift+++ b/Transit/TransitTests/QueryAndDisplayIDIntegrationTests.swift@@ -17,7 +17,8 @@ struct QueryAndDisplayIDIntegrationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/QueryIntentEnumValidationTests.swift Modified +4 / -2
diff --git a/Transit/TransitTests/QueryIntentEnumValidationTests.swift b/Transit/TransitTests/QueryIntentEnumValidationTests.swiftindex bd54fe4..46f3abc 100644--- a/Transit/TransitTests/QueryIntentEnumValidationTests.swift+++ b/Transit/TransitTests/QueryIntentEnumValidationTests.swift@@ -24,7 +24,8 @@ struct QueryIntentEnumValidationTests {     }      private func makeTaskServices() throws -> TaskServices {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return TaskServices(@@ -36,7 +37,8 @@ struct QueryIntentEnumValidationTests {     }      private func makeMilestoneServices() throws -> MilestoneServices {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return MilestoneServices(
Transit/TransitTests/QueryIntentFetchFailureTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryIntentFetchFailureTests.swift b/Transit/TransitTests/QueryIntentFetchFailureTests.swiftindex ef17814..5351441 100644--- a/Transit/TransitTests/QueryIntentFetchFailureTests.swift+++ b/Transit/TransitTests/QueryIntentFetchFailureTests.swift@@ -33,7 +33,8 @@ struct QueryIntentFetchFailureTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let allocator = DisplayIDAllocator(store: InMemoryCounterStore())         return Services(             task: TaskService(modelContext: context, displayIDAllocator: allocator),
Transit/TransitTests/QueryMilestonesIntentSearchTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryMilestonesIntentSearchTests.swift b/Transit/TransitTests/QueryMilestonesIntentSearchTests.swiftindex a5bfac9..5d48cd0 100644--- a/Transit/TransitTests/QueryMilestonesIntentSearchTests.swift+++ b/Transit/TransitTests/QueryMilestonesIntentSearchTests.swift@@ -16,7 +16,8 @@ struct QueryMilestonesIntentSearchTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/QueryMilestonesIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryMilestonesIntentTests.swift b/Transit/TransitTests/QueryMilestonesIntentTests.swiftindex eedd1da..7045b01 100644--- a/Transit/TransitTests/QueryMilestonesIntentTests.swift+++ b/Transit/TransitTests/QueryMilestonesIntentTests.swift@@ -17,7 +17,8 @@ struct QueryMilestonesIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/QueryTasksIntentDateFilterTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryTasksIntentDateFilterTests.swift b/Transit/TransitTests/QueryTasksIntentDateFilterTests.swiftindex 7840599..f911994 100644--- a/Transit/TransitTests/QueryTasksIntentDateFilterTests.swift+++ b/Transit/TransitTests/QueryTasksIntentDateFilterTests.swift@@ -14,7 +14,8 @@ struct QueryTasksIntentDateFilterTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/QueryTasksIntentMilestoneTests.swift Modified +14 / -8
diff --git a/Transit/TransitTests/QueryTasksIntentMilestoneTests.swift b/Transit/TransitTests/QueryTasksIntentMilestoneTests.swiftindex 4795f46..3e2bfb5 100644--- a/Transit/TransitTests/QueryTasksIntentMilestoneTests.swift+++ b/Transit/TransitTests/QueryTasksIntentMilestoneTests.swift@@ -9,8 +9,8 @@ struct QueryTasksIntentMilestoneTests {      // MARK: - Helpers -    private func makeContext() throws -> ModelContext {-        try TestModelContainer.newContext()+    private func makeTestContainer() throws -> TestModelContainer {+        try TestModelContainer()     }      @discardableResult@@ -57,7 +57,8 @@ struct QueryTasksIntentMilestoneTests {     // MARK: - Milestone Filter      @Test func filterByMilestoneDisplayId() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let milestone = makeMilestone(in: context, name: "v1.0", project: project, displayId: 1)         makeTask(in: context, name: "In milestone", project: project, milestone: milestone, displayId: 10)@@ -80,7 +81,8 @@ struct QueryTasksIntentMilestoneTests {     }      @Test func filterByMilestoneName() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let milestone = makeMilestone(in: context, name: "v1.0", project: project, displayId: 1)         makeTask(in: context, name: "In milestone", project: project, milestone: milestone, displayId: 10)@@ -103,7 +105,8 @@ struct QueryTasksIntentMilestoneTests {     }      @Test func taskResponseIncludesMilestoneInfo() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let milestone = makeMilestone(in: context, name: "v1.0", project: project, displayId: 1)         makeTask(in: context, name: "Task", project: project, milestone: milestone, displayId: 10)@@ -127,7 +130,8 @@ struct QueryTasksIntentMilestoneTests {     }      @Test func taskWithoutMilestoneOmitsMilestoneField() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         makeTask(in: context, name: "Task", project: project, displayId: 10) @@ -155,7 +159,8 @@ struct QueryTasksIntentMilestoneTests {     /// `MCPToolHandler.handleQueryTasks` behavior, which already routes through     /// `MilestoneService.findByDisplayID` and surfaces `INTERNAL_ERROR` on duplicates.     @Test func filterByMilestoneDisplayIdRejectsDuplicates() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let milestoneA = makeMilestone(in: context, name: "v1.0", project: project, displayId: 7)         let milestoneB = makeMilestone(in: context, name: "v1.0-alt", project: project, displayId: 7)@@ -185,7 +190,8 @@ struct QueryTasksIntentMilestoneTests {     /// must return an empty array (consistent with other lookup paths that treat unknown     /// display IDs as "no results").     @Test func filterByMilestoneDisplayIdReturnsEmptyWhenUnknown() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let milestone = makeMilestone(in: context, name: "v1.0", project: project, displayId: 1)         makeTask(in: context, name: "In milestone", project: project, milestone: milestone, displayId: 10)
Transit/TransitTests/QueryTasksIntentNullFilterTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryTasksIntentNullFilterTests.swift b/Transit/TransitTests/QueryTasksIntentNullFilterTests.swiftindex 6d0bb81..7f9cfb2 100644--- a/Transit/TransitTests/QueryTasksIntentNullFilterTests.swift+++ b/Transit/TransitTests/QueryTasksIntentNullFilterTests.swift@@ -17,7 +17,8 @@ struct QueryTasksIntentNullFilterTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/QueryTasksIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/QueryTasksIntentTests.swift b/Transit/TransitTests/QueryTasksIntentTests.swiftindex a41340b..83b4637 100644--- a/Transit/TransitTests/QueryTasksIntentTests.swift+++ b/Transit/TransitTests/QueryTasksIntentTests.swift@@ -18,7 +18,8 @@ struct QueryTasksIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/ReportLogicDateRangeTests.swift Modified +22 / -11
diff --git a/Transit/TransitTests/ReportLogicDateRangeTests.swift b/Transit/TransitTests/ReportLogicDateRangeTests.swiftindex 43f1dcb..16c69f5 100644--- a/Transit/TransitTests/ReportLogicDateRangeTests.swift+++ b/Transit/TransitTests/ReportLogicDateRangeTests.swift@@ -9,7 +9,8 @@ struct ReportLogicDateRangeTests {      @Test("Today filter includes only tasks completed today")     func todayFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -31,7 +32,8 @@ struct ReportLogicDateRangeTests {      @Test("Yesterday filter includes only tasks completed yesterday")     func yesterdayFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -52,7 +54,8 @@ struct ReportLogicDateRangeTests {      @Test("This week filter includes tasks from current week")     func thisWeekFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -74,7 +77,8 @@ struct ReportLogicDateRangeTests {      @Test("Last week filter includes tasks from previous week")     func lastWeekFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -96,7 +100,8 @@ struct ReportLogicDateRangeTests {      @Test("This month filter includes tasks from current month")     func thisMonthFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -118,7 +123,8 @@ struct ReportLogicDateRangeTests {      @Test("Last month filter includes tasks from previous month")     func lastMonthFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -142,7 +148,8 @@ struct ReportLogicDateRangeTests {      @Test("This year filter includes tasks from current year")     func thisYearFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -164,7 +171,8 @@ struct ReportLogicDateRangeTests {      @Test("Last year filter includes tasks from previous year")     func lastYearFilter() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -190,7 +198,8 @@ struct ReportLogicDateRangeTests {      @Test("Yesterday boundary: start included, start of today excluded")     func yesterdayBoundary() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -221,7 +230,8 @@ struct ReportLogicDateRangeTests {      @Test("Last week boundary: start included, this week start excluded")     func lastWeekBoundary() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let calendar = Calendar.current         let project = makeTestProject(name: "Project", context: ctx)@@ -246,7 +256,8 @@ struct ReportLogicDateRangeTests {      @Test("Empty result when no tasks match the date range")     func emptyResultForMismatchedRange() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) 
Transit/TransitTests/ReportLogicTestHelpers.swift Modified +2 / -10
diff --git a/Transit/TransitTests/ReportLogicTestHelpers.swift b/Transit/TransitTests/ReportLogicTestHelpers.swiftindex 93f71d0..44b7cf5 100644--- a/Transit/TransitTests/ReportLogicTestHelpers.swift+++ b/Transit/TransitTests/ReportLogicTestHelpers.swift@@ -3,16 +3,8 @@ import SwiftData @testable import Transit  @MainActor-func makeReportTestContext() throws -> ModelContext {-    let schema = Schema([Project.self, TransitTask.self, Comment.self, Milestone.self])-    let config = ModelConfiguration(-        "ReportLogicTests-\(UUID().uuidString)",-        schema: schema,-        isStoredInMemoryOnly: true,-        cloudKitDatabase: .none-    )-    let container = try ModelContainer(for: schema, configurations: [config])-    return ModelContext(container)+func makeReportTestContainer() throws -> TestModelContainer {+    try TestModelContainer() }  /// Creates a task, inserts it into the context, and transitions it to a terminal status.
Transit/TransitTests/ReportLogicTests.swift Modified +30 / -15
diff --git a/Transit/TransitTests/ReportLogicTests.swift b/Transit/TransitTests/ReportLogicTests.swiftindex c5b01d1..cbfc8b0 100644--- a/Transit/TransitTests/ReportLogicTests.swift+++ b/Transit/TransitTests/ReportLogicTests.swift@@ -11,7 +11,8 @@ struct ReportLogicGroupingTests {      @Test("Tasks are grouped by project")     func tasksGroupedByProject() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let projA = makeTestProject(name: "Alpha", context: ctx)         let projB = makeTestProject(name: "Beta", context: ctx)@@ -31,7 +32,8 @@ struct ReportLogicGroupingTests {      @Test("Projects sorted alphabetically case-insensitive")     func projectsSortedCaseInsensitive() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let projZ = makeTestProject(name: "Zebra", context: ctx)         let projA = makeTestProject(name: "alpha", context: ctx)@@ -51,7 +53,8 @@ struct ReportLogicGroupingTests {      @Test("Tasks sorted by completionDate ascending")     func tasksSortedByCompletionDate() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -78,7 +81,8 @@ struct ReportLogicGroupingTests {      @Test("Tasks with nil completionDate sort by lastStatusChangeDate among peers")     func tasksSortedByEffectiveDateMixed() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -115,7 +119,8 @@ struct ReportLogicGroupingTests {      @Test("Tasks with same completionDate sorted by permanentDisplayId, nil last")     func tasksSortedByDisplayIdTiebreak() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -142,7 +147,8 @@ struct ReportLogicGroupingTests {      @Test("UUID tiebreaker when completionDate and displayId match")     func tasksSortedByUUIDFallback() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -171,7 +177,8 @@ struct ReportLogicFilterTests {      @Test("Only terminal tasks (done/abandoned) are included")     func onlyTerminalTasksIncluded() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -196,7 +203,8 @@ struct ReportLogicFilterTests {      @Test("Terminal tasks with nil completionDate fall back to lastStatusChangeDate")     func nilCompletionDateFallsBackToLastStatusChangeDate() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -218,7 +226,8 @@ struct ReportLogicFilterTests {      @Test("Terminal tasks with nil completionDate use lastStatusChangeDate for date range filtering")     func nilCompletionDateUsesLastStatusChangeDateForRange() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -237,7 +246,8 @@ struct ReportLogicFilterTests {      @Test("Terminal task with nil completionDate gets lastStatusChangeDate as completionDate in report")     func nilCompletionDateReportTaskUsesLastStatusChangeDate() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -255,7 +265,8 @@ struct ReportLogicFilterTests {      @Test("Orphan tasks with nil project are excluded")     func orphanTasksExcluded() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -275,7 +286,8 @@ struct ReportLogicFilterTests {      @Test("Summary counts correct for done and abandoned")     func summaryCounts() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -294,7 +306,8 @@ struct ReportLogicFilterTests {      @Test("Abandoned tasks marked as isAbandoned in ReportTask")     func abandonedTaskIdentification() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -319,7 +332,8 @@ struct ReportLogicFilterTests {      @Test("Provisional displayId uses DisplayID.formatted")     func provisionalDisplayId() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -337,7 +351,8 @@ struct ReportLogicFilterTests {      @Test("Permanent displayId uses DisplayID.formatted")     func permanentDisplayId() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) 
Transit/TransitTests/ReportMilestoneSummaryTests.swift Modified +6 / -3
diff --git a/Transit/TransitTests/ReportMilestoneSummaryTests.swift b/Transit/TransitTests/ReportMilestoneSummaryTests.swiftindex b4ec9dd..477a294 100644--- a/Transit/TransitTests/ReportMilestoneSummaryTests.swift+++ b/Transit/TransitTests/ReportMilestoneSummaryTests.swift@@ -18,7 +18,8 @@ struct ReportMilestoneSummaryTests {      @Test("Milestone-only project group reports milestone done count, not zero")     func milestoneOnlyGroupReportsMilestoneDone() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "MilestoneOnly", context: ctx) @@ -39,7 +40,8 @@ struct ReportMilestoneSummaryTests {      @Test("Abandoned milestone counted in abandonedMilestoneCount")     func abandonedMilestoneCounted() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -62,7 +64,8 @@ struct ReportMilestoneSummaryTests {      @Test("Top-level totals include milestone counts")     func topLevelTotalsIncludeMilestones() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) 
Transit/TransitTests/ReportMilestoneTests.swift Modified +20 / -10
diff --git a/Transit/TransitTests/ReportMilestoneTests.swift b/Transit/TransitTests/ReportMilestoneTests.swiftindex 41d905f..2a00568 100644--- a/Transit/TransitTests/ReportMilestoneTests.swift+++ b/Transit/TransitTests/ReportMilestoneTests.swift@@ -13,7 +13,8 @@ struct ReportMilestoneTests {      @Test("Completed milestones included in report grouped by project")     func completedMilestonesIncluded() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Alpha", context: ctx) @@ -38,7 +39,8 @@ struct ReportMilestoneTests {      @Test("Abandoned milestones marked as isAbandoned")     func abandonedMilestonesMarked() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -59,7 +61,8 @@ struct ReportMilestoneTests {      @Test("Open milestones excluded from report")     func openMilestonesExcluded() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -78,7 +81,8 @@ struct ReportMilestoneTests {      @Test("Milestones without completionDate fall back to lastStatusChangeDate")     func milestonesWithoutCompletionDateFallBack() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -100,7 +104,8 @@ struct ReportMilestoneTests {      @Test("Milestone with nil completionDate excluded when lastStatusChangeDate is out of range")     func milestoneNilCompletionDateOutOfRangeExcluded() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -122,7 +127,8 @@ struct ReportMilestoneTests {      @Test("Milestone taskCount reflects assigned tasks")     func milestoneTaskCount() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -147,7 +153,8 @@ struct ReportMilestoneTests {      @Test("Project group created for milestone-only project (no tasks)")     func milestoneOnlyProjectGroup() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "MilestoneOnly", context: ctx) @@ -169,7 +176,8 @@ struct ReportMilestoneTests {      @Test("No milestones results in empty milestones array")     func emptyMilestones() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -184,7 +192,8 @@ struct ReportMilestoneTests {      @Test("Task milestoneName populated when task has milestone")     func taskMilestoneNamePopulated() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) @@ -203,7 +212,8 @@ struct ReportMilestoneTests {      @Test("Task milestoneName nil when task has no milestone")     func taskMilestoneNameNil() throws {-        let ctx = try makeReportTestContext()+        let testContainer = try makeReportTestContainer()+        let ctx = testContainer.context         let now = reportTestNow         let project = makeTestProject(name: "Project", context: ctx) 
Transit/TransitTests/SafeRollbackTests.swift Modified +18 / -11
diff --git a/Transit/TransitTests/SafeRollbackTests.swift b/Transit/TransitTests/SafeRollbackTests.swiftindex d6adbec..e594d5f 100644--- a/Transit/TransitTests/SafeRollbackTests.swift+++ b/Transit/TransitTests/SafeRollbackTests.swift@@ -14,8 +14,8 @@ struct SafeRollbackTests {      // MARK: - Helpers -    private func makeContext() throws -> ModelContext {-        try TestModelContainer.newContext()+    private func makeTestContainer() throws -> TestModelContainer {+        try TestModelContainer()     }      private func makeProject(@@ -51,7 +51,8 @@ struct SafeRollbackTests {     // MARK: - Project re-faulting      @Test func safeRollbackRevertsProjectProperties() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         try context.save() @@ -73,7 +74,8 @@ struct SafeRollbackTests {     // MARK: - Task re-faulting      @Test func safeRollbackRevertsTaskProperties() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = makeTask(project: project, in: context)         try context.save()@@ -92,7 +94,8 @@ struct SafeRollbackTests {     }      @Test func safeRollbackRevertsTaskStatusChange() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = makeTask(project: project, in: context)         try context.save()@@ -109,7 +112,8 @@ struct SafeRollbackTests {     // MARK: - Milestone re-faulting      @Test func safeRollbackRevertsMilestoneProperties() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)          let milestone = Milestone(@@ -137,7 +141,8 @@ struct SafeRollbackTests {     // MARK: - Comment re-faulting      @Test func safeRollbackRevertsCommentDeletion() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = makeTask(project: project, in: context) @@ -166,7 +171,8 @@ struct SafeRollbackTests {     // MARK: - Multi-entity atomicity      @Test func safeRollbackRevertsMultipleEntityMutationsAtomically() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(name: "Original Project", in: context)         let task = makeTask(name: "Original Task", project: project, in: context) @@ -198,7 +204,8 @@ struct SafeRollbackTests {     // MARK: - Metadata re-faulting      @Test func safeRollbackRevertsTaskMetadata() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(             name: "Task",@@ -223,8 +230,8 @@ struct SafeRollbackTests {     // MARK: - SyncHeartbeat re-faulting (T-777)      @Test func safeRollbackRevertsSyncHeartbeatProperties() throws {-        let context = try makeContext()-+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let heartbeat = SyncHeartbeat()         context.insert(heartbeat)         try context.save()
Transit/TransitTests/ShareTextTests.swift Modified +30 / -16
diff --git a/Transit/TransitTests/ShareTextTests.swift b/Transit/TransitTests/ShareTextTests.swiftindex 2a03d6f..0550cbb 100644--- a/Transit/TransitTests/ShareTextTests.swift+++ b/Transit/TransitTests/ShareTextTests.swift@@ -6,8 +6,8 @@ import Testing @MainActor @Suite(.serialized) struct ShareTextTests { -    private func makeContext() throws -> ModelContext {-        try TestModelContainer.newContext()+    private func makeTestContainer() throws -> TestModelContainer {+        try TestModelContainer()     }      private func makeProject(in context: ModelContext, name: String = "My Project") -> Project {@@ -19,7 +19,8 @@ struct ShareTextTests {     // MARK: - Header      @Test func shareTextIncludesDisplayIDNameAndType() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Fix login", type: .bug, project: project, displayID: .permanent(42))         context.insert(task)@@ -29,7 +30,8 @@ struct ShareTextTests {     }      @Test func shareTextUsesProvisionalDisplayID() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Research caching", type: .research, project: project, displayID: .provisional)         context.insert(task)@@ -41,7 +43,8 @@ struct ShareTextTests {     // MARK: - Project      @Test func shareTextIncludesProjectName() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context, name: "Transit")         let task = TransitTask(name: "Add share", type: .feature, project: project, displayID: .permanent(1))         context.insert(task)@@ -52,7 +55,8 @@ struct ShareTextTests {     // MARK: - Description      @Test func shareTextIncludesDescription() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(             name: "Task",@@ -67,7 +71,8 @@ struct ShareTextTests {     }      @Test func shareTextOmitsEmptyDescription() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", description: nil, type: .chore, project: project, displayID: .permanent(1))         context.insert(task)@@ -79,7 +84,8 @@ struct ShareTextTests {     // MARK: - Metadata      @Test func shareTextIncludesMetadataSortedByKey() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(             name: "Task",@@ -101,7 +107,8 @@ struct ShareTextTests {     }      @Test func shareTextOmitsMetadataWhenEmpty() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .permanent(1))         context.insert(task)@@ -114,7 +121,8 @@ struct ShareTextTests {     // MARK: - Milestone      @Test func shareTextIncludesMilestoneWhenAssigned() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let milestone = Milestone(name: "v1.0 Release", project: project, displayID: .permanent(3))         context.insert(milestone)@@ -127,7 +135,8 @@ struct ShareTextTests {     }      @Test func shareTextOmitsMilestoneWhenNil() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Add feature", type: .feature, project: project, displayID: .permanent(7))         context.insert(task)@@ -137,7 +146,8 @@ struct ShareTextTests {     }      @Test func shareTextMilestoneAppearsAfterProject() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context, name: "Transit")         let milestone = Milestone(name: "Beta", project: project, displayID: .permanent(1))         context.insert(milestone)@@ -154,7 +164,8 @@ struct ShareTextTests {     // MARK: - Comments (T-86 regression)      @Test func shareTextIncludesComments() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .permanent(10))         context.insert(task)@@ -170,7 +181,8 @@ struct ShareTextTests {     }      @Test func shareTextOmitsCommentsSectionWhenEmpty() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .permanent(10))         context.insert(task)@@ -180,7 +192,8 @@ struct ShareTextTests {     }      @Test func shareTextIncludesNewlyAddedComment() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let service = CommentService(modelContext: context)         let task = TransitTask(name: "Bug report", type: .bug, project: project, displayID: .permanent(86))@@ -202,7 +215,8 @@ struct ShareTextTests {     // MARK: - Full format      @Test func shareTextFullFormat() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let project = makeProject(in: context, name: "Transit")         let task = TransitTask(             name: "Add share button",
Transit/TransitTests/SyncDisabledGatingTests.swift Modified +10 / -5
diff --git a/Transit/TransitTests/SyncDisabledGatingTests.swift b/Transit/TransitTests/SyncDisabledGatingTests.swiftindex 8e3fd78..6463daa 100644--- a/Transit/TransitTests/SyncDisabledGatingTests.swift+++ b/Transit/TransitTests/SyncDisabledGatingTests.swift@@ -65,7 +65,8 @@ struct SyncDisabledGatingTests {      @Test     func promoteProvisionalTasks_withCloudSyncInactive_leavesTasksProvisional() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, isCloudSyncActive: false)@@ -83,7 +84,8 @@ struct SyncDisabledGatingTests {      @Test     func promoteProvisionalMilestones_withCloudSyncInactive_leavesMilestonesProvisional() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, isCloudSyncActive: false)@@ -104,7 +106,8 @@ struct SyncDisabledGatingTests {      @Test     func createTask_withCloudSyncInactive_assignsProvisionalID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, isCloudSyncActive: false)@@ -121,7 +124,8 @@ struct SyncDisabledGatingTests {      @Test     func createMilestone_withCloudSyncInactive_assignsProvisionalID() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let store = InMemoryCounterStore(initialNextDisplayID: 1)         let allocator = DisplayIDAllocator(store: store, isCloudSyncActive: false)@@ -140,7 +144,8 @@ struct SyncDisabledGatingTests {      @Test     func reassignDuplicates_withCloudSyncInactive_neverTouchesCounterStore() async throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let taskStore = InMemoryCounterStore(initialNextDisplayID: 1)         let milestoneStore = InMemoryCounterStore(initialNextDisplayID: 1)
Transit/TransitTests/TaskCommentCountTests.swift Modified +8 / -5
diff --git a/Transit/TransitTests/TaskCommentCountTests.swift b/Transit/TransitTests/TaskCommentCountTests.swiftindex 1bd1984..49f6544 100644--- a/Transit/TransitTests/TaskCommentCountTests.swift+++ b/Transit/TransitTests/TaskCommentCountTests.swift@@ -16,8 +16,8 @@ struct TaskCommentCountTests {      // MARK: - Helpers -    private func makeContext() throws -> ModelContext {-        try TestModelContainer.newContext()+    private func makeTestContainer() throws -> TestModelContainer {+        try TestModelContainer()     }      private func makeTask(in context: ModelContext) -> TransitTask {@@ -31,7 +31,8 @@ struct TaskCommentCountTests {     // MARK: - Relationship count      @Test func commentsRelationshipCount_returnsZeroWhenNoComments() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let task = makeTask(in: context)         try context.save() @@ -39,7 +40,8 @@ struct TaskCommentCountTests {     }      @Test func commentsRelationshipCount_reflectsAddedComments() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let task = makeTask(in: context)          let comment1 = Comment(content: "First", authorName: "Alice", isAgent: false, task: task)@@ -52,7 +54,8 @@ struct TaskCommentCountTests {     }      @Test func commentsRelationshipCount_decreasesAfterDeletion() throws {-        let context = try makeContext()+        let testContainer = try makeTestContainer()+        let context = testContainer.context         let task = makeTask(in: context)          let comment1 = Comment(content: "Keep", authorName: "Alice", isAgent: false, task: task)
Transit/TransitTests/TaskCreationResultTests.swift Modified +6 / -15
diff --git a/Transit/TransitTests/TaskCreationResultTests.swift b/Transit/TransitTests/TaskCreationResultTests.swiftindex 0f44542..da995aa 100644--- a/Transit/TransitTests/TaskCreationResultTests.swift+++ b/Transit/TransitTests/TaskCreationResultTests.swift@@ -6,18 +6,6 @@ import Testing  @MainActor @Suite(.serialized) struct TaskCreationResultTests {-    private func makeContext() throws -> ModelContext {-        let schema = Schema([Project.self, TransitTask.self, Milestone.self])-        let config = ModelConfiguration(-            "TaskCreationResultTests-\(UUID().uuidString)",-            schema: schema,-            isStoredInMemoryOnly: true,-            cloudKitDatabase: .none-        )-        let container = try ModelContainer(for: schema, configurations: [config])-        return ModelContext(container)-    }-     private func makeTask(         in context: ModelContext,         name: String = "Task",@@ -34,7 +22,8 @@ struct TaskCreationResultTests {     }      @Test func fromTaskMapsRequiredFields() throws {-        let context = try makeContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let task = makeTask(in: context, name: "Map me", type: .bug, displayID: 33)          let result = try TaskCreationResult.from(task)@@ -49,7 +38,8 @@ struct TaskCreationResultTests {     }      @Test func fromTaskThrowsWhenProjectIsMissing() throws {-        let context = try makeContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let task = makeTask(in: context)         task.project = nil @@ -63,7 +53,8 @@ struct TaskCreationResultTests {     // the task name (not the project name) so the user sees the task that was     // just created. The project name belongs in the subtitle as context.     @Test func displayRepresentationUsesTaskNameAsTitle() throws {-        let context = try makeContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let task = makeTask(in: context, name: "Investigate flaky test", type: .bug, displayID: 42)          let result = try TaskCreationResult.from(task)
Transit/TransitTests/TaskEditAtomicSaveTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskEditAtomicSaveTests.swift b/Transit/TransitTests/TaskEditAtomicSaveTests.swiftindex 7e633fe..16e49f2 100644--- a/Transit/TransitTests/TaskEditAtomicSaveTests.swift+++ b/Transit/TransitTests/TaskEditAtomicSaveTests.swift@@ -12,7 +12,8 @@ struct TaskEditAtomicSaveTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/TaskEditConcurrentUpdateTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskEditConcurrentUpdateTests.swift b/Transit/TransitTests/TaskEditConcurrentUpdateTests.swiftindex 0917c73..9e7fdbe 100644--- a/Transit/TransitTests/TaskEditConcurrentUpdateTests.swift+++ b/Transit/TransitTests/TaskEditConcurrentUpdateTests.swift@@ -16,7 +16,8 @@ struct TaskEditTestEnv {     let project: Project      static func make() throws -> TaskEditTestEnv {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskService = TaskService(             modelContext: context,             displayIDAllocator: DisplayIDAllocator(store: InMemoryCounterStore())
Transit/TransitTests/TaskEditSaveErrorTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskEditSaveErrorTests.swift b/Transit/TransitTests/TaskEditSaveErrorTests.swiftindex d96f3da..f2f475d 100644--- a/Transit/TransitTests/TaskEditSaveErrorTests.swift+++ b/Transit/TransitTests/TaskEditSaveErrorTests.swift@@ -16,7 +16,8 @@ struct TaskEditSaveErrorTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/TaskEditViewMilestoneTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskEditViewMilestoneTests.swift b/Transit/TransitTests/TaskEditViewMilestoneTests.swiftindex 88abaee..b1ecc98 100644--- a/Transit/TransitTests/TaskEditViewMilestoneTests.swift+++ b/Transit/TransitTests/TaskEditViewMilestoneTests.swift@@ -7,7 +7,8 @@ import Testing struct TaskEditViewMilestoneTests {      private func makeMilestoneService() throws -> (MilestoneService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let allocator = DisplayIDAllocator(store: InMemoryCounterStore())         let service = MilestoneService(modelContext: context, displayIDAllocator: allocator)         return (service, context)
Transit/TransitTests/TaskEntityQueryTests.swift Modified +7 / -12
diff --git a/Transit/TransitTests/TaskEntityQueryTests.swift b/Transit/TransitTests/TaskEntityQueryTests.swiftindex 08db845..2342ee0 100644--- a/Transit/TransitTests/TaskEntityQueryTests.swift+++ b/Transit/TransitTests/TaskEntityQueryTests.swift@@ -5,26 +5,21 @@ import Testing  @MainActor @Suite(.serialized) struct TaskEntityQueryTests {+    @MainActor     private struct TestEnv {-        let context: ModelContext+        let testContainer: TestModelContainer         let taskService: TaskService++        var context: ModelContext { testContainer.context }     }      private func makeEnv() throws -> TestEnv {-        let schema = Schema([Project.self, TransitTask.self, Milestone.self])-        let config = ModelConfiguration(-            "TaskEntityQueryTests-\(UUID().uuidString)",-            schema: schema,-            isStoredInMemoryOnly: true,-            cloudKitDatabase: .none-        )-        let container = try ModelContainer(for: schema, configurations: [config])-        let context = ModelContext(container)+        let testContainer = try TestModelContainer()         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return TestEnv(-            context: context,-            taskService: TaskService(modelContext: context, displayIDAllocator: allocator)+            testContainer: testContainer,+            taskService: TaskService(modelContext: testContainer.context, displayIDAllocator: allocator)         )     } 
Transit/TransitTests/TaskEntityTests.swift Modified +4 / -14
diff --git a/Transit/TransitTests/TaskEntityTests.swift b/Transit/TransitTests/TaskEntityTests.swiftindex cc839ae..1e96c92 100644--- a/Transit/TransitTests/TaskEntityTests.swift+++ b/Transit/TransitTests/TaskEntityTests.swift@@ -5,18 +5,6 @@ import Testing  @MainActor @Suite(.serialized) struct TaskEntityTests {-    private func makeContext() throws -> ModelContext {-        let schema = Schema([Project.self, TransitTask.self, Milestone.self])-        let config = ModelConfiguration(-            "TaskEntityTests-\(UUID().uuidString)",-            schema: schema,-            isStoredInMemoryOnly: true,-            cloudKitDatabase: .none-        )-        let container = try ModelContainer(for: schema, configurations: [config])-        return ModelContext(container)-    }-     private func makeTask(         in context: ModelContext,         name: String = "Task",@@ -33,7 +21,8 @@ struct TaskEntityTests {     }      @Test func fromTaskMapsRequiredFields() throws {-        let context = try makeContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let task = makeTask(in: context, name: "Map me", type: .bug, displayID: 33)          let entity = try TaskEntity.from(task)@@ -50,7 +39,8 @@ struct TaskEntityTests {     }      @Test func fromTaskThrowsWhenProjectIsMissing() throws {-        let context = try makeContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let task = makeTask(in: context)         task.project = nil 
Transit/TransitTests/TaskIdentifierValidationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskIdentifierValidationTests.swift b/Transit/TransitTests/TaskIdentifierValidationTests.swiftindex 3345963..cba07d5 100644--- a/Transit/TransitTests/TaskIdentifierValidationTests.swift+++ b/Transit/TransitTests/TaskIdentifierValidationTests.swift@@ -20,7 +20,8 @@ struct TaskIdentifierValidationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let milestoneStore = InMemoryCounterStore()
Transit/TransitTests/TaskServicePriorityTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskServicePriorityTests.swift b/Transit/TransitTests/TaskServicePriorityTests.swiftindex f86c077..1a36cb8 100644--- a/Transit/TransitTests/TaskServicePriorityTests.swift+++ b/Transit/TransitTests/TaskServicePriorityTests.swift@@ -9,7 +9,8 @@ struct TaskServicePriorityTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/TaskServiceTests.swift Modified +5 / -4
diff --git a/Transit/TransitTests/TaskServiceTests.swift b/Transit/TransitTests/TaskServiceTests.swiftindex ecbade4..47a1b63 100644--- a/Transit/TransitTests/TaskServiceTests.swift+++ b/Transit/TransitTests/TaskServiceTests.swift@@ -10,7 +10,8 @@ struct TaskServiceTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)@@ -226,10 +227,10 @@ struct TaskServiceTests {             isStoredInMemoryOnly: true,             cloudKitDatabase: .none         )-        let container = try ModelContainer(for: schema, configurations: [config])+        let testContainer = try TestModelContainer(schema: schema, configurations: [config])          // Use container.mainContext for the service — this is the fix-        let context = container.mainContext+        let context = testContainer.container.mainContext         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)@@ -248,7 +249,7 @@ struct TaskServiceTests {         try service.updateStatus(task: task, to: .inProgress)          // Verify the change persisted by re-fetching from a fresh context-        let verifyContext = ModelContext(container)+        let verifyContext = ModelContext(testContainer.container)         let taskID = task.id         let descriptor = FetchDescriptor<TransitTask>(             predicate: #Predicate { $0.id == taskID }
Transit/TransitTests/TaskServiceUpdateTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskServiceUpdateTests.swift b/Transit/TransitTests/TaskServiceUpdateTests.swiftindex a8394b5..3172ee6 100644--- a/Transit/TransitTests/TaskServiceUpdateTests.swift+++ b/Transit/TransitTests/TaskServiceUpdateTests.swift@@ -9,7 +9,8 @@ struct TaskServiceUpdateTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/TaskUpdateValidatorTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/TaskUpdateValidatorTests.swift b/Transit/TransitTests/TaskUpdateValidatorTests.swiftindex 73ecf3e..e16718e 100644--- a/Transit/TransitTests/TaskUpdateValidatorTests.swift+++ b/Transit/TransitTests/TaskUpdateValidatorTests.swift@@ -23,7 +23,8 @@ struct TaskUpdateValidatorTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskStore = InMemoryCounterStore()         let taskAllocator = DisplayIDAllocator(store: taskStore)         let milestoneStore = InMemoryCounterStore()
Transit/TransitTests/TestModelContainer.swift Modified +25 / -11
diff --git a/Transit/TransitTests/TestModelContainer.swift b/Transit/TransitTests/TestModelContainer.swiftindex 9c1978c..274645b 100644--- a/Transit/TransitTests/TestModelContainer.swift+++ b/Transit/TransitTests/TestModelContainer.swift@@ -2,18 +2,23 @@ import Foundation import SwiftData @testable import Transit -/// Provides isolated in-memory ModelContexts for tests.+/// Owns an isolated in-memory ModelContainer and its ModelContext for tests.+///+/// Construct this fixture at the test boundary instead of returning a bare+/// ModelContext from helper functions. Every container is retained centrally,+/// including custom-schema fixtures used by multi-context tests, so no public+/// raw-container factory can bypass the ownership guarantee. @MainActor-enum TestModelContainer {-    /// Returns a fresh ModelContext backed by its own in-memory container to-    /// avoid cross-test state leakage between suites.-    static func newContext() throws -> ModelContext {-        let container = try newContainer()-        return ModelContext(container)-    }+struct TestModelContainer {+    let container: ModelContainer+    let context: ModelContext++    // Intentionally retained for the test process lifetime. Do not clear this+    // while escaped contexts may still be in use; bounded test-only memory is+    // the tradeoff that makes accidental temporary fixture extraction safe.+    private static var retainedContainers: [ModelContainer] = [] -    /// Returns a fresh in-memory ModelContainer for tests needing multiple contexts on one store.-    static func newContainer() throws -> ModelContainer {+    init() throws {         let schema = Schema([Project.self, TransitTask.self, Comment.self, Milestone.self, SyncHeartbeat.self])         let config = ModelConfiguration(             "TransitTests-\(UUID().uuidString)",@@ -21,7 +26,16 @@ enum TestModelContainer {             isStoredInMemoryOnly: true,             cloudKitDatabase: .none         )-        return try ModelContainer(for: schema, configurations: [config])+        try self.init(schema: schema, configurations: [config])+    }++    /// Creates a retained fixture for tests that need a custom schema or+    /// multiple contexts sharing one store.+    init(schema: Schema, configurations: [ModelConfiguration]) throws {+        let container = try ModelContainer(for: schema, configurations: configurations)+        self.container = container+        self.context = ModelContext(container)+        Self.retainedContainers.append(container)     }      /// Performs a rollback and forces re-faulting of all @Model objects.
Transit/TransitTests/TestModelContainerLifetimeTests.swift Added +40 / -0
diff --git a/Transit/TransitTests/TestModelContainerLifetimeTests.swift b/Transit/TransitTests/TestModelContainerLifetimeTests.swiftnew file mode 100644index 0000000..6e341fb--- /dev/null+++ b/Transit/TransitTests/TestModelContainerLifetimeTests.swift@@ -0,0 +1,40 @@+import Foundation+import SwiftData+import Testing+@testable import Transit++@MainActor @Suite(.serialized)+struct TestModelContainerLifetimeTests {+    private final class WeakContainerReference {+        weak var value: ModelContainer?+    }++    private func makeEscapedContext() throws -> (ModelContext, WeakContainerReference) {+        let fixture = try TestModelContainer()+        let containerReference = WeakContainerReference()+        containerReference.value = fixture.container+        return (fixture.context, containerReference)+    }++    @Test func escapedContextKeepsBackingContainerAvailableForItsFullUse() throws {+        let (context, containerReference) = try makeEscapedContext()++        #expect(containerReference.value != nil)++        let project = Project(+            name: "Lifetime probe",+            description: "",+            gitRepo: nil,+            colorHex: "#000000"+        )+        context.insert(project)+        try context.save()++        let retainedContainer = try #require(containerReference.value)+        let verificationContext = ModelContext(retainedContainer)+        let persistedProjects = try verificationContext.fetch(FetchDescriptor<Project>())++        #expect(persistedProjects.contains { $0.name == "Lifetime probe" })+        #expect(containerReference.value != nil)+    }+}
Transit/TransitTests/TransitTaskPriorityTests.swift Modified +10 / -5
diff --git a/Transit/TransitTests/TransitTaskPriorityTests.swift b/Transit/TransitTests/TransitTaskPriorityTests.swiftindex b288f42..b4a24b3 100644--- a/Transit/TransitTests/TransitTaskPriorityTests.swift+++ b/Transit/TransitTests/TransitTaskPriorityTests.swift@@ -15,7 +15,8 @@ struct TransitTaskPriorityTests {     // MARK: - Default      @Test func defaultPriorityRawValueIsMedium() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .provisional) @@ -26,7 +27,8 @@ struct TransitTaskPriorityTests {     // MARK: - Accessor fallback (effective-priority invariant)      @Test func emptyRawValueReadsAsMedium() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .provisional) @@ -35,7 +37,8 @@ struct TransitTaskPriorityTests {     }      @Test func unrecognizedRawValueReadsAsMedium() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .provisional) @@ -46,7 +49,8 @@ struct TransitTaskPriorityTests {     // MARK: - Setter      @Test func setterWritesRawValue() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(name: "Task", type: .feature, project: project, displayID: .provisional) @@ -60,7 +64,8 @@ struct TransitTaskPriorityTests {     // MARK: - Init param      @Test func initParamSetsPriorityRawValue() throws {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let project = makeProject(in: context)         let task = TransitTask(             name: "Task", type: .feature, project: project, displayID: .provisional, priority: .high
Transit/TransitTests/UpdateMilestoneClearDescIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/UpdateMilestoneClearDescIntentTests.swift b/Transit/TransitTests/UpdateMilestoneClearDescIntentTests.swiftindex 3d702f2..a863c12 100644--- a/Transit/TransitTests/UpdateMilestoneClearDescIntentTests.swift+++ b/Transit/TransitTests/UpdateMilestoneClearDescIntentTests.swift@@ -17,7 +17,8 @@ struct UpdateMilestoneClearDescIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let allocator = DisplayIDAllocator(store: InMemoryCounterStore())         return Services(             milestone: MilestoneService(modelContext: context, displayIDAllocator: allocator),
Transit/TransitTests/UpdateMilestoneIdentifierValidationTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/UpdateMilestoneIdentifierValidationTests.swift b/Transit/TransitTests/UpdateMilestoneIdentifierValidationTests.swiftindex 4aa1f70..319cc95 100644--- a/Transit/TransitTests/UpdateMilestoneIdentifierValidationTests.swift+++ b/Transit/TransitTests/UpdateMilestoneIdentifierValidationTests.swift@@ -17,7 +17,8 @@ struct UpdateMilestoneIdentifierValidationTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/UpdateMilestoneIntentSameStatusTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/UpdateMilestoneIntentSameStatusTests.swift b/Transit/TransitTests/UpdateMilestoneIntentSameStatusTests.swiftindex 191b298..f0f9f41 100644--- a/Transit/TransitTests/UpdateMilestoneIntentSameStatusTests.swift+++ b/Transit/TransitTests/UpdateMilestoneIntentSameStatusTests.swift@@ -17,7 +17,8 @@ struct UpdateMilestoneIntentSameStatusTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/UpdateMilestoneIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/UpdateMilestoneIntentTests.swift b/Transit/TransitTests/UpdateMilestoneIntentTests.swiftindex e51d3e3..29ca9e5 100644--- a/Transit/TransitTests/UpdateMilestoneIntentTests.swift+++ b/Transit/TransitTests/UpdateMilestoneIntentTests.swift@@ -15,7 +15,8 @@ struct UpdateMilestoneIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         return Services(
Transit/TransitTests/UpdateStatusIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/UpdateStatusIntentTests.swift b/Transit/TransitTests/UpdateStatusIntentTests.swiftindex 1241248..c9ec43f 100644--- a/Transit/TransitTests/UpdateStatusIntentTests.swift+++ b/Transit/TransitTests/UpdateStatusIntentTests.swift@@ -9,7 +9,8 @@ struct UpdateStatusIntentTests {     // MARK: - Helpers      private func makeService() throws -> (TaskService, ModelContext) {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let store = InMemoryCounterStore()         let allocator = DisplayIDAllocator(store: store)         let service = TaskService(modelContext: context, displayIDAllocator: allocator)
Transit/TransitTests/UpdateTaskIntentTests.swift Modified +2 / -1
diff --git a/Transit/TransitTests/UpdateTaskIntentTests.swift b/Transit/TransitTests/UpdateTaskIntentTests.swiftindex 4b97265..dee1b37 100644--- a/Transit/TransitTests/UpdateTaskIntentTests.swift+++ b/Transit/TransitTests/UpdateTaskIntentTests.swift@@ -19,7 +19,8 @@ struct UpdateTaskIntentTests {     }      private func makeServices() throws -> Services {-        let context = try TestModelContainer.newContext()+        let testContainer = try TestModelContainer()+        let context = testContainer.context         let taskStore = InMemoryCounterStore()         let taskAllocator = DisplayIDAllocator(store: taskStore)         let milestoneStore = InMemoryCounterStore()
docs/agent-notes/project-structure.md Modified +1 / -1
diff --git a/docs/agent-notes/project-structure.md b/docs/agent-notes/project-structure.mdindex 631eee6..f00b95a 100644--- a/docs/agent-notes/project-structure.md+++ b/docs/agent-notes/project-structure.md@@ -94,5 +94,5 @@ prerequisite and prefix the command with `$(XCODEBUILD_ENV)` and  ## Test Infrastructure -- **TestModelContainer** (`TransitTests/TestModelContainer.swift`) — Shared in-memory ModelContainer for SwiftData tests. Uses `Schema` + `cloudKitDatabase: .none` to avoid conflicts with the app's CloudKit entitlements. Tests get fresh `ModelContext` instances via `newContext()`.+- **TestModelContainer** (`TransitTests/TestModelContainer.swift`) — Owning in-memory SwiftData fixture with explicit `Schema` and `cloudKitDatabase: .none`. Each initializer centrally retains its container; custom-schema and multi-context tests use `init(schema:configurations:)`. - Test suites using SwiftData should use `@Suite(.serialized)` trait.
docs/agent-notes/reports.md Modified +1 / -1
diff --git a/docs/agent-notes/reports.md b/docs/agent-notes/reports.mdindex 029791c..474010d 100644--- a/docs/agent-notes/reports.md+++ b/docs/agent-notes/reports.md@@ -74,7 +74,7 @@ App Intent that generates a markdown report via Shortcuts. Located at `Transit/T - `ReportLogicTests` uses `@Suite(.serialized)` with `TestModelContainer` since it needs SwiftData - Test helpers in `ReportLogicTestHelpers.swift` for SwiftData-based tests - Formatter tests construct `ReportData`/`ProjectGroup`/`ReportTask` directly via local helpers-- `GenerateReportIntentTests` uses `makeReportTestContext()` and tests the static `execute` method directly+- `GenerateReportIntentTests` uses `makeReportTestContainer()`, keeps the returned `TestModelContainer` alive, and tests the static `execute` method directly - `IntentCompatibilityAndDiscoverabilityTests` checks shortcut count — must be updated when adding new shortcuts  ## SwiftLint
docs/agent-notes/technical-constraints.md Modified +13 / -6
diff --git a/docs/agent-notes/technical-constraints.md b/docs/agent-notes/technical-constraints.mdindex 4209584..1fd514d 100644--- a/docs/agent-notes/technical-constraints.md+++ b/docs/agent-notes/technical-constraints.md@@ -89,16 +89,23 @@ For report generation, use `fetchTerminalTasks()` / `fetchTerminalMilestones()`  ## SwiftData Test Container -Creating multiple `ModelContainer` instances for the same schema in one process causes `loadIssueModelContainer` errors. The app's CloudKit entitlements trigger auto-discovery of `@Model` types at test host launch, conflicting with test containers.+A `ModelContext` does not safely keep its `ModelContainer`/store alive for later model access. Never create a container in a helper and return only its context or models; ARC can release the backing store and cause nondeterministic SwiftData `SIGTRAP`/`EXC_BREAKPOINT` crashes. -**Solution**: Use a shared `TestModelContainer` singleton that creates one container with:-1. An explicit `Schema([Project.self, TransitTask.self])`-2. A named `ModelConfiguration` with `cloudKitDatabase: .none`+**Solution**: Construct the container-owning `TestModelContainer` fixture at the test boundary:++```swift+let testContainer = try TestModelContainer()+let context = testContainer.context+```++The fixture creates a fresh container with:+1. An explicit `Schema` containing all five models+2. A uniquely named `ModelConfiguration` with `cloudKitDatabase: .none` 3. `isStoredInMemoryOnly: true` -All three are required. Without `cloudKitDatabase: .none`, it conflicts with the CloudKit-enabled default store. Without the explicit `Schema`, the `cloudKitDatabase: .none` parameter crashes.+All three are required. Without `cloudKitDatabase: .none`, it conflicts with the CloudKit-enabled default store. Without the explicit `Schema`, the `cloudKitDatabase: .none` parameter crashes. The fixture retains both container and context, and test support centrally retains created containers so accidentally extracting a temporary fixture's context cannot orphan its store. -Each test gets a fresh `ModelContext` via `TestModelContainer.newContext()` for isolation.+Tests that intentionally need multiple contexts on one store construct `TestModelContainer` and derive each context from its `container` property. Tests needing a custom schema or configuration use `TestModelContainer(schema:configurations:)`; every initializer participates in central retention. Direct `ModelContainer` construction and raw container/context factories in test sources are rejected by the ownership guard run from `make lint`.  Test files that use SwiftData need `@Suite(.serialized)` to avoid concurrent access issues. 
scripts/validate_test_model_container_ownership.py Added +345 / -0
diff --git a/scripts/validate_test_model_container_ownership.py b/scripts/validate_test_model_container_ownership.pynew file mode 100755index 0000000..a907892--- /dev/null+++ b/scripts/validate_test_model_container_ownership.py@@ -0,0 +1,345 @@+#!/usr/bin/env python3+"""Reject SwiftData test-container construction that bypasses the owning fixture."""++from __future__ import annotations++import argparse+import re+import sys+from pathlib import Path++REPOSITORY_ROOT = Path(__file__).resolve().parents[1]+DEFAULT_TEST_ROOT = REPOSITORY_ROOT / "Transit" / "TransitTests"+DEFAULT_SUPPORT_FILE = (DEFAULT_TEST_ROOT / "TestModelContainer.swift").resolve()+SOURCE_SUFFIXES = (".swift", ".swift.fixture")+++def mask_comments_and_strings(source: str) -> str:+    """Preserve code positions while masking Swift comments and string contents.++    String interpolation is code, so it remains visible to the ownership checks.+    Raw strings use the same number of ``#`` characters for their closing and+    interpolation delimiters.+    """+    result = list(source)++    def mask(start: int, end: int) -> None:+        for offset in range(start, min(end, len(source))):+            if source[offset] != "\n":+                result[offset] = " "++    def string_opener(index: int) -> tuple[int, int, int] | None:+        cursor = index+        while cursor < len(source) and source[cursor] == "#":+            cursor += 1+        hash_count = cursor - index+        if source.startswith('"""', cursor):+            return hash_count, 3, cursor + 3+        if cursor < len(source) and source[cursor] == '"':+            return hash_count, 1, cursor + 1+        return None++    def scan_block_comment(index: int) -> int:+        depth = 1+        cursor = index + 2+        mask(index, cursor)+        while cursor < len(source) and depth:+            if source.startswith("/*", cursor):+                mask(cursor, cursor + 2)+                depth += 1+                cursor += 2+            elif source.startswith("*/", cursor):+                mask(cursor, cursor + 2)+                depth -= 1+                cursor += 2+            else:+                mask(cursor, cursor + 1)+                cursor += 1+        return cursor++    def scan_string(index: int, hash_count: int, quote_count: int, content_start: int) -> int:+        closing = '"' * quote_count + "#" * hash_count+        interpolation = "\\" + "#" * hash_count + "("+        mask(index, content_start)+        cursor = content_start++        while cursor < len(source):+            if source.startswith(closing, cursor):+                mask(cursor, cursor + len(closing))+                return cursor + len(closing)+            if source.startswith(interpolation, cursor):+                # Mask the interpolation escape but preserve its parentheses and+                # recursively scanned code, including nested strings/comments.+                mask(cursor, cursor + len(interpolation) - 1)+                cursor = scan_code(cursor + len(interpolation), stop_at_closing_paren=True)+                continue+            if hash_count == 0 and source[cursor] == "\\":+                # A non-raw string escape cannot begin an interpolation here,+                # because that case was handled immediately above.+                mask(cursor, cursor + 2)+                cursor += 2+                continue+            mask(cursor, cursor + 1)+            cursor += 1++        return cursor++    def scan_code(index: int, *, stop_at_closing_paren: bool = False) -> int:+        cursor = index+        nested_parens = 0+        while cursor < len(source):+            if source.startswith("//", cursor):+                line_end = source.find("\n", cursor)+                if line_end == -1:+                    line_end = len(source)+                mask(cursor, line_end)+                cursor = line_end+                continue+            if source.startswith("/*", cursor):+                cursor = scan_block_comment(cursor)+                continue++            opener = string_opener(cursor)+            if opener is not None:+                hash_count, quote_count, content_start = opener+                cursor = scan_string(cursor, hash_count, quote_count, content_start)+                continue++            if stop_at_closing_paren:+                if source[cursor] == "(":+                    nested_parens += 1+                elif source[cursor] == ")":+                    if nested_parens == 0:+                        return cursor + 1+                    nested_parens -= 1+            cursor += 1+        return cursor++    scan_code(0)+    return "".join(result)+++def source_files(paths: list[Path]) -> list[Path]:+    files: list[Path] = []+    for path in paths:+        if path.is_dir():+            files.extend(+                candidate for candidate in path.rglob("*")+                if candidate.is_file() and candidate.name.endswith(SOURCE_SUFFIXES)+            )+        elif path.is_file() and path.name.endswith(SOURCE_SUFFIXES):+            files.append(path)+        else:+            raise ValueError(f"not a Swift source file or directory: {path}")+    return sorted(set(files))+++def line_number(source: str, offset: int) -> int:+    return source.count("\n", 0, offset) + 1+++def matching_brace(masked: str, opening_offset: int) -> int | None:+    depth = 0+    for offset in range(opening_offset, len(masked)):+        if masked[offset] == "{":+            depth += 1+        elif masked[offset] == "}":+            depth -= 1+            if depth == 0:+                return offset+    return None+++def initializer_ranges(masked: str) -> list[tuple[int, int]]:+    ranges: list[tuple[int, int]] = []+    initializer = re.compile(r"(?<!\.)\binit\s*[!?]?\s*\(")+    for match in initializer.finditer(masked):+        opening_brace = masked.find("{", match.end())+        if opening_brace == -1:+            continue+        closing_brace = matching_brace(masked, opening_brace)+        if closing_brace is not None:+            ranges.append((opening_brace, closing_brace))+    return ranges+++def is_top_level_in_body(masked: str, offset: int, body: tuple[int, int]) -> bool:+    opening_brace, closing_brace = body+    if not opening_brace < offset < closing_brace:+        return False+    depth = 0+    for character in masked[opening_brace + 1:offset]:+        if character == "{":+            depth += 1+        elif character == "}":+            depth -= 1+    return depth == 0+++def validate_support_file(+    path: Path,+    source: str,+    masked: str,+    raw_constructor_matches: list[re.Match[str]]+) -> list[str]:+    errors: list[str] = []+    unique_raw_matches = {match.start(): match for match in raw_constructor_matches}+    if len(unique_raw_matches) != 1:+        errors.append(+            f"{path}: expected exactly one centralized ModelContainer construction, "+            f"found {len(unique_raw_matches)}"+        )+        return errors++    raw_match = next(iter(unique_raw_matches.values()))+    containing_initializers = [+        body for body in initializer_ranges(masked)+        if body[0] < raw_match.start() < body[1]+    ]+    if len(containing_initializers) != 1 or not is_top_level_in_body(+        masked, raw_match.start(), containing_initializers[0]+    ):+        errors.append(+            f"{path}:{line_number(source, raw_match.start())}: centralized ModelContainer "+            "construction must occur directly in a TestModelContainer initializer"+        )+        return errors++    body = containing_initializers[0]+    if not re.search(+        r"private\s+static\s+var\s+retainedContainers\s*:\s*\[ModelContainer\]",+        masked+    ):+        errors.append(f"{path}: TestModelContainer must privately retain created containers")++    retained_references = list(re.finditer(r"\bretainedContainers\b", masked))+    if len(retained_references) != 2:+        errors.append(+            f"{path}: retainedContainers must only be declared and appended to; "+            f"found {len(retained_references)} references"+        )++    required_steps = [+        (re.compile(r"\bself\s*\.\s*container\s*=\s*container\b"), "assign self.container"),+        (+            re.compile(r"\bself\s*\.\s*context\s*=\s*ModelContext\s*\(\s*container\s*\)"),+            "derive self.context from the retained container"+        ),+        (+            re.compile(r"\bSelf\s*\.\s*retainedContainers\s*\.\s*append\s*\(\s*container\s*\)"),+            "register every created container unconditionally"+        )+    ]++    previous_offset = raw_match.start()+    for pattern, description in required_steps:+        matches = [+            match for match in pattern.finditer(masked)+            if is_top_level_in_body(masked, match.start(), body)+        ]+        if len(matches) != 1 or matches[0].start() <= previous_offset:+            errors.append(f"{path}: TestModelContainer initializer must {description}")+            continue+        previous_offset = matches[0].start()++    raw_return = re.compile(r"\bfunc\b[^\{;]*->[^\{;]*\bModel(?:Context|Container)\b", re.DOTALL)+    for match in raw_return.finditer(masked):+        errors.append(+            f"{path}:{line_number(source, match.start())}: fixture support must not expose a raw "+            "ModelContext/ModelContainer factory"+        )++    return errors+++def validate_file(path: Path, support_file: Path = DEFAULT_SUPPORT_FILE) -> list[str]:+    source = path.read_text(encoding="utf-8")+    masked = mask_comments_and_strings(source)+    errors: list[str] = []++    checks = [+        (+            re.compile(+                r"\bfunc\b[^\{;]*->\s*(?:\w+\s*\.\s*)*"+                r"Model(?:Context|Container)\s*[?!]?\s*(?:where\b[^\{;]*)?\{",+                re.DOTALL+            ),+            "raw ModelContext/ModelContainer factory must return an owning fixture instead"+        ),+        (+            re.compile(r"\bTestModelContainer\s*\.\s*(?:newContext|newContainer)\s*\("),+            "removed raw TestModelContainer factory; construct and retain TestModelContainer instead"+        ),+        (+            re.compile(r"\bModelContainer\s*\.\s*init\b"),+            "direct ModelContainer.init construction bypasses TestModelContainer ownership"+        ),+        (+            re.compile(r"\bModelContainer\s*\("),+            "direct ModelContainer construction bypasses TestModelContainer ownership"+        ),+        (+            re.compile(r":\s*(?:\w+\s*\.\s*)*ModelContainer\s*=\s*\.\s*init\s*\("),+            "inferred ModelContainer.init construction bypasses TestModelContainer ownership"+        ),+        (+            re.compile(r"\btypealias\s+\w+\s*=\s*(?:\w+\s*\.\s*)*ModelContainer\b"),+            "ModelContainer aliases bypass direct-construction ownership validation"+        )+    ]++    is_support_file = path.resolve() == support_file.resolve()+    raw_constructor_matches: list[re.Match[str]] = []+    for pattern, message in checks:+        for match in pattern.finditer(masked):+            if is_support_file and (+                message.startswith("direct ModelContainer")+                or message.startswith("inferred ModelContainer")+            ):+                raw_constructor_matches.append(match)+                continue+            errors.append(f"{path}:{line_number(source, match.start())}: {message}")++    if is_support_file:+        errors.extend(validate_support_file(path, source, masked, raw_constructor_matches))++    return errors+++def main() -> int:+    parser = argparse.ArgumentParser(description=__doc__)+    parser.add_argument(+        "--support-file",+        type=Path,+        default=DEFAULT_SUPPORT_FILE,+        help="override the centralized fixture path (used by validator self-tests)"+    )+    parser.add_argument(+        "paths",+        nargs="*",+        type=Path,+        default=[DEFAULT_TEST_ROOT],+        help="Swift files or directories to validate (default: Transit/TransitTests)"+    )+    args = parser.parse_args()++    try:+        files = source_files(args.paths)+    except ValueError as error:+        print(f"error: {error}", file=sys.stderr)+        return 2++    support_file = args.support_file.resolve()+    errors = [error for path in files for error in validate_file(path, support_file)]+    if errors:+        print("SwiftData test ownership validation failed:", file=sys.stderr)+        for error in errors:+            print(f"  {error}", file=sys.stderr)+        return 1++    print(f"SwiftData test ownership validation passed ({len(files)} files).")+    return 0+++if __name__ == "__main__":+    raise SystemExit(main())
specs/bugfixes/test-contexts-drop-swiftdata-containers/report.md Added +104 / -0
diff --git a/specs/bugfixes/test-contexts-drop-swiftdata-containers/report.md b/specs/bugfixes/test-contexts-drop-swiftdata-containers/report.mdnew file mode 100644index 0000000..a26da7f--- /dev/null+++ b/specs/bugfixes/test-contexts-drop-swiftdata-containers/report.md@@ -0,0 +1,104 @@+# Bugfix Report: Test Contexts Drop Their SwiftData Containers++**Date:** 2026-08-01+**Status:** Fixed++## Description of the Issue++Test helpers create an in-memory SwiftData `ModelContainer` locally and return only its `ModelContext`. The context does not keep the backing container/store safely alive, so later model access can trap after ARC releases the container.++**Reproduction steps:**+1. Create a context with `TestModelContainer.newContext()` or one of the bespoke context-only helpers.+2. Let the helper return, dropping its local strong reference to the container.+3. Access or mutate a SwiftData model through the escaped context and observe an intermittent `SIGTRAP`/`EXC_BREAKPOINT` in SwiftData.++**Impact:** The unit-test host can crash nondeterministically, moving the apparent failure between unrelated tests and making the suite unreliable.++## Investigation Summary++The investigation followed the systematic debugger workflow.++- **Phase 1 — overview:** Expected every context to have a live in-memory store for the full test. Actual behavior allows the store owner to die when helper scope ends.+- **Phase 2 — inspection:** Inspected `TestModelContainer.swift`, all `newContext()` callers, `TaskEntityTests.swift`, `TaskCreationResultTests.swift`, `ReportLogicTestHelpers.swift`, context-only wrappers, and setup structs that retain contexts.+- **Phase 3 — root cause:** Ownership is erased at helper boundaries: containers are local variables while only contexts or models escape.+- **Phase 4 — solution:** Replace the bare-context API with a container-owning fixture, migrate all callers, consolidate bespoke helpers, and add a lifetime regression plus static call-site verification.++## Discovered Root Cause++A `ModelContext` was treated as if it owned its `ModelContainer`. It does not provide that lifetime guarantee. Helpers returned the context while the only strong container reference was a local variable, so ARC could release the persistent-store owner before the test finished.++**Defect type:** Data lifetime / ownership error++**Five Whys:**+1. Why did arbitrary SwiftData model access trap? The backing store was no longer valid.+2. Why was the store no longer valid? Its `ModelContainer` had been released.+3. Why was the container released? Helpers returned only `ModelContext`.+4. Why did this recur? Test support exposed a context-only API and suites copied that shape locally.+5. Why was it nondeterministic? ARC release timing and the next model access varied with test execution.++**Contributing factors:** More than 100 shared-helper calls, additional local wrappers, and fixtures that retained services/contexts but not their container owner.++## Resolution for the Issue++**Changes made:**+- `Transit/TransitTests/TestModelContainer.swift` — replaced `newContext()` with a fixture that owns both `ModelContainer` and `ModelContext`; created containers are centrally retained so temporary fixture extraction cannot orphan a store.+- `Transit/TransitTests/TestModelContainerLifetimeTests.swift` — added an API/lifetime regression covering model access through the owning fixture.+- `Transit/TransitTests/TaskEntityTests.swift`, `TaskCreationResultTests.swift`, and `ReportLogicTestHelpers.swift` — removed bespoke local-container/context-only factories and delegated to shared test support.+- 89 additional `TransitTests` files — migrated all remaining direct and wrapper-based context acquisition to `TestModelContainer`.+- `CLAUDE.md` and `docs/agent-notes/technical-constraints.md` — documented the owning-fixture rule and removed stale `newContext()` guidance.+- `scripts/validate_test_model_container_ownership.py`, `tests/validation/`, and `Makefile` — added an executable ownership boundary that rejects raw container construction/factories and proves unsafe bare, tuple, and environment forms fail while owning forms pass.++**Approach rationale:** A container-owning fixture preserves each test's isolated in-memory store while making ownership explicit at direct call sites. Central container retention is intentionally load-bearing for existing helpers that return service/context tuples or temporarily extract only `context`; those APIs remain safe even when they do not forward the fixture. The process-lifetime array is the accepted bounded-memory tradeoff that also protects future accidental owner drops.++The executable validator replaces the earlier SwiftLint regex because a single regex could not reliably distinguish comments and string literals from executable interpolation, recognize aliases and inferred constructors, or prove that the sole raw construction and unconditional retention append remain in the same initializer. The validator uses a small position-preserving lexical scan plus accepted/unsafe fixtures for those boundaries. It requires `python3`, which is provided by the Xcode developer toolchain already required to build Transit (`xcrun --find python3`), and runs as a prerequisite of both `make lint` and `make lint-fix`.++**Alternatives considered:**+- Return a `(ModelContainer, ModelContext)` tuple — callers can discard the container and recreate the bug.+- Wrap every test body in a closure — lifetime-safe but much more invasive, especially for setup structs that escape helper boundaries.+- Keep a SwiftLint-only regex — rejected after it missed tuple/inferred/lexical shapes and could not validate the fixture implementation's construction/retention structure.+- Change production code — rejected because the defect is isolated to test fixture ownership.++## Regression Test++**Test file:** `Transit/TransitTests/TestModelContainerLifetimeTests.swift`+**Test name:** `escapedContextKeepsBackingContainerAvailableForItsFullUse`++**What it verifies:** A helper can let its local fixture go out of scope and return only the context; the centrally retained backing container remains available for a save and a fetch through a fresh context on the same store.++**Run command:** `make test-quick PIPE_PRETTY=`++## Affected Files++| File group | Change |+|------|--------|+| `Transit/TransitTests/TestModelContainer.swift` | Owning fixture API and defensive process-lifetime retention |+| `Transit/TransitTests/TestModelContainerLifetimeTests.swift` | Regression coverage |+| 92 migrated test/helper files | 207 context-acquisition call sites moved to the fixture API |+| `CLAUDE.md` | Updated test-infrastructure guidance |+| `docs/agent-notes/technical-constraints.md` | Corrected SwiftData container-lifetime rule |+| `Makefile`, `scripts/`, and `tests/` | Replaced the narrow SwiftLint regex with executable ownership validation and positive/negative fixtures |+| `CHANGELOG.md` | Recorded T-2003 fix |++## Verification++**Automated:**+- [x] Escaped-context regression passes as part of `make test-quick PIPE_PRETTY=`+- [x] Complete macOS unit suite passes via `make test-quick PIPE_PRETTY=`+- [x] `make lint` passes, including executable unsafe/owning fixtures and repository ownership validation+- [x] Ownership validation finds zero raw test `ModelContainer` construction outside `TestModelContainer`, or calls to removed `newContext()`/`newContainer()` APIs+- [ ] Full iOS scheme passes: all unit tests completed successfully, then unrelated UI tests `testClearAll` and `testEditViewPreservesTaskMilestone` failed and the runner hung retrying simulator launches with `DebuggerLLDB.DebuggerVersionStore.StoreError` / `no debugger version`; the hung run was terminated after preserving its log++**Manual verification:**+- Reviewed representative direct callers, helper wrappers, report fixtures, MCP setup, and all three ticket-named bespoke helpers.+- Confirmed the diff contains test support/tests/docs only; production sources are unchanged.++## Prevention++- Construct `TestModelContainer` at test/setup boundaries and derive its `context`; helpers should carry the fixture when practical.+- Keep `TestModelContainer`'s central retention backstop for setup structs that expose services/contexts without forwarding the fixture.+- Run `make lint`; it executes rule fixtures and rejects raw test container construction outside the retained fixture boundary.++## Related++- Transit T-2003+- `Flaky SwiftData test crashes from a non-retained ModelContainer.md`
tests/fixtures/model_container_ownership/accepted/owning_forms.swift.fixture Added +38 / -0
diff --git a/tests/fixtures/model_container_ownership/accepted/owning_forms.swift.fixture b/tests/fixtures/model_container_ownership/accepted/owning_forms.swift.fixturenew file mode 100644index 0000000..8101c54--- /dev/null+++ b/tests/fixtures/model_container_ownership/accepted/owning_forms.swift.fixture@@ -0,0 +1,38 @@+struct Service {+    init(modelContext: ModelContext) {}+}++func makeFixture() throws -> TestModelContainer {+    try TestModelContainer()+}++func makeServiceAndOwner() throws -> (Service, TestModelContainer) {+    let fixture = try TestModelContainer()+    return (Service(modelContext: fixture.context), fixture)+}++struct Environment {+    let fixture: TestModelContainer+    let context: ModelContext+    let service: Service+}++func makeEnvironment() throws -> Environment {+    let fixture = try TestModelContainer()+    return Environment(+        fixture: fixture,+        context: fixture.context,+        service: Service(modelContext: fixture.context)+    )+}++// Ownership-like text in comments and strings is documentation, not code.+let ordinaryText = "ModelContainer(for: Schema([]))"+let rawText = #"TestModelContainer.newContext() and ModelContainer.init(for:)"#+let multilineText = """+ModelContainer(for: Schema([]))+"""+let interpolatedSafeValue = "fixture: \(String(describing: TestModelContainer.self))"+/* Nested comments are also ignored:+   /* ModelContainer(for: Schema([])) */+*/
tests/fixtures/model_container_ownership/support/accepted/centralized_initializer.swift.fixture Added +12 / -0
diff --git a/tests/fixtures/model_container_ownership/support/accepted/centralized_initializer.swift.fixture b/tests/fixtures/model_container_ownership/support/accepted/centralized_initializer.swift.fixturenew file mode 100644index 0000000..fe52907--- /dev/null+++ b/tests/fixtures/model_container_ownership/support/accepted/centralized_initializer.swift.fixture@@ -0,0 +1,12 @@+struct TestModelContainer {+    let container: ModelContainer+    let context: ModelContext+    private static var retainedContainers: [ModelContainer] = []++    init(schema: Schema, configurations: [ModelConfiguration]) throws {+        let container = try ModelContainer(for: schema, configurations: configurations)+        self.container = container+        self.context = ModelContext(container)+        Self.retainedContainers.append(container)+    }+}
tests/fixtures/model_container_ownership/support/unsafe/cleared_retention.swift.fixture Added +13 / -0
diff --git a/tests/fixtures/model_container_ownership/support/unsafe/cleared_retention.swift.fixture b/tests/fixtures/model_container_ownership/support/unsafe/cleared_retention.swift.fixturenew file mode 100644index 0000000..fbae97a--- /dev/null+++ b/tests/fixtures/model_container_ownership/support/unsafe/cleared_retention.swift.fixture@@ -0,0 +1,13 @@+struct TestModelContainer {+    let container: ModelContainer+    let context: ModelContext+    private static var retainedContainers: [ModelContainer] = []++    init(schema: Schema, configurations: [ModelConfiguration]) throws {+        let container = try ModelContainer(for: schema, configurations: configurations)+        self.container = container+        self.context = ModelContext(container)+        Self.retainedContainers.append(container)+        Self.retainedContainers.removeAll()+    }+}
tests/fixtures/model_container_ownership/support/unsafe/conditional_retention.swift.fixture Added +14 / -0
diff --git a/tests/fixtures/model_container_ownership/support/unsafe/conditional_retention.swift.fixture b/tests/fixtures/model_container_ownership/support/unsafe/conditional_retention.swift.fixturenew file mode 100644index 0000000..d7e29a7--- /dev/null+++ b/tests/fixtures/model_container_ownership/support/unsafe/conditional_retention.swift.fixture@@ -0,0 +1,14 @@+struct TestModelContainer {+    let container: ModelContainer+    let context: ModelContext+    private static var retainedContainers: [ModelContainer] = []++    init(schema: Schema, configurations: [ModelConfiguration]) throws {+        let container = try ModelContainer(for: schema, configurations: configurations)+        self.container = container+        self.context = ModelContext(container)+        if false {+            Self.retainedContainers.append(container)+        }+    }+}
tests/fixtures/model_container_ownership/support/unsafe/construction_outside_initializer.swift.fixture Added +16 / -0
diff --git a/tests/fixtures/model_container_ownership/support/unsafe/construction_outside_initializer.swift.fixture b/tests/fixtures/model_container_ownership/support/unsafe/construction_outside_initializer.swift.fixturenew file mode 100644index 0000000..9f91b4f--- /dev/null+++ b/tests/fixtures/model_container_ownership/support/unsafe/construction_outside_initializer.swift.fixture@@ -0,0 +1,16 @@+struct TestModelContainer {+    let container: ModelContainer+    let context: ModelContext+    private static var retainedContainers: [ModelContainer] = []++    private static var freshContainer: ModelContainer {+        try! ModelContainer(for: Schema([]))+    }++    init() {+        let container = Self.freshContainer+        self.container = container+        self.context = ModelContext(container)+        Self.retainedContainers.append(container)+    }+}
tests/fixtures/model_container_ownership/support/unsafe/delegated_retention.swift.fixture Added +16 / -0
diff --git a/tests/fixtures/model_container_ownership/support/unsafe/delegated_retention.swift.fixture b/tests/fixtures/model_container_ownership/support/unsafe/delegated_retention.swift.fixturenew file mode 100644index 0000000..ff87045--- /dev/null+++ b/tests/fixtures/model_container_ownership/support/unsafe/delegated_retention.swift.fixture@@ -0,0 +1,16 @@+struct TestModelContainer {+    let container: ModelContainer+    let context: ModelContext+    private static var retainedContainers: [ModelContainer] = []++    init(schema: Schema, configurations: [ModelConfiguration]) throws {+        let container = try ModelContainer(for: schema, configurations: configurations)+        self.container = container+        self.context = ModelContext(container)+        Self.register(container)+    }++    private static func register(_ container: ModelContainer) {+        Self.retainedContainers.append(container)+    }+}
tests/fixtures/model_container_ownership/unsafe/aliased_container.swift.fixture Added +5 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/aliased_container.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/aliased_container.swift.fixturenew file mode 100644index 0000000..3948d01--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/aliased_container.swift.fixture@@ -0,0 +1,5 @@+typealias TestStore = ModelContainer++func makeAliasedContainer() throws -> TestStore {+    try TestStore(for: Schema([]))+}
tests/fixtures/model_container_ownership/unsafe/bare_context_from_fixture.swift.fixture Added +3 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/bare_context_from_fixture.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/bare_context_from_fixture.swift.fixturenew file mode 100644index 0000000..a463247--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/bare_context_from_fixture.swift.fixture@@ -0,0 +1,3 @@+func makeBareContext() throws -> ModelContext {+    try TestModelContainer().context+}
tests/fixtures/model_container_ownership/unsafe/context_only_environment.swift.fixture Added +10 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/context_only_environment.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/context_only_environment.swift.fixturenew file mode 100644index 0000000..f4939c3--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/context_only_environment.swift.fixture@@ -0,0 +1,10 @@+struct Environment {+    let context: ModelContext+    let service: Service+}++func makeEnvironment() throws -> Environment {+    let container = try ModelContainer(for: Schema([]))+    let context = ModelContext(container)+    return Environment(context: context, service: Service(modelContext: context))+}
tests/fixtures/model_container_ownership/unsafe/explicit_container_init.swift.fixture Added +4 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/explicit_container_init.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/explicit_container_init.swift.fixturenew file mode 100644index 0000000..a4cae9e--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/explicit_container_init.swift.fixture@@ -0,0 +1,4 @@+func makeContext() throws -> ModelContext {+    let container = try ModelContainer.init(for: Schema([]))+    return ModelContext(container)+}
tests/fixtures/model_container_ownership/unsafe/interpolated_construction.swift.fixture Added +3 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/interpolated_construction.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/interpolated_construction.swift.fixturenew file mode 100644index 0000000..0b05062--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/interpolated_construction.swift.fixture@@ -0,0 +1,3 @@+func describeUnsafeContainer() throws -> String {+    "container: \(try ModelContainer(for: Schema([])))"+}
tests/fixtures/model_container_ownership/unsafe/nonthrowing_bare_context.swift.fixture Added +4 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/nonthrowing_bare_context.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/nonthrowing_bare_context.swift.fixturenew file mode 100644index 0000000..e087fb1--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/nonthrowing_bare_context.swift.fixture@@ -0,0 +1,4 @@+func makeContext() -> ModelContext {+    let container = try! ModelContainer(for: Schema([]))+    return ModelContext(container)+}
tests/fixtures/model_container_ownership/unsafe/tuple_from_raw_container.swift.fixture Added +5 / -0
diff --git a/tests/fixtures/model_container_ownership/unsafe/tuple_from_raw_container.swift.fixture b/tests/fixtures/model_container_ownership/unsafe/tuple_from_raw_container.swift.fixturenew file mode 100644index 0000000..5362698--- /dev/null+++ b/tests/fixtures/model_container_ownership/unsafe/tuple_from_raw_container.swift.fixture@@ -0,0 +1,5 @@+func makeService() throws -> (Service, ModelContext) {+    let container = try TestModelContainer.newContainer()+    let context = ModelContext(container)+    return (Service(modelContext: context), context)+}
tests/validation/test_model_container_ownership_guard.sh Added +60 / -0
diff --git a/tests/validation/test_model_container_ownership_guard.sh b/tests/validation/test_model_container_ownership_guard.shnew file mode 100755index 0000000..e41059d--- /dev/null+++ b/tests/validation/test_model_container_ownership_guard.sh@@ -0,0 +1,60 @@+#!/usr/bin/env bash+# Proves the T-2003 ownership guard rejects representative unsafe factory+# shapes and accepts APIs that carry the owning TestModelContainer fixture.++set -euo pipefail++ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"+VALIDATOR="$ROOT/scripts/validate_test_model_container_ownership.py"+FIXTURES="$ROOT/tests/fixtures/model_container_ownership"++fail() {+    echo "FAIL: $*" >&2+    exit 1+}++pass() {+    echo "PASS: $*"+}++expect_rejected() {+    local fixture="$1"+    shift+    local output+    local status++    set +e+    output="$(python3 "$VALIDATOR" "$@" "$fixture" 2>&1)"+    status=$?+    set -e++    if [[ $status -ne 1 ]] || ! grep -q "ownership validation failed" <<<"$output"; then+        echo "$output" >&2+        fail "unsafe fixture did not produce an ownership violation: $(basename "$fixture") (exit $status)"+    fi+    pass "unsafe fixture rejected: $(basename "$fixture")"+}++python3 "$VALIDATOR" "$FIXTURES/accepted" >/dev/null \+    || fail "owning fixture and lexical literal forms should pass"+pass "owning fixture APIs and lexical literals pass"++for fixture in "$FIXTURES"/unsafe/*.swift.fixture; do+    expect_rejected "$fixture"+done++for fixture in "$FIXTURES"/support/accepted/*.swift.fixture; do+    python3 "$VALIDATOR" --support-file "$fixture" "$fixture" >/dev/null \+        || fail "valid support fixture unexpectedly failed: $(basename "$fixture")"+    pass "valid support fixture accepted: $(basename "$fixture")"+done++for fixture in "$FIXTURES"/support/unsafe/*.swift.fixture; do+    expect_rejected "$fixture" --support-file "$fixture"+done++python3 "$VALIDATOR" "$ROOT/Transit/TransitTests" >/dev/null \+    || fail "repository test sources violate the ownership boundary"+pass "repository test sources obey the centralized ownership boundary"++echo "All SwiftData ownership guard checks passed."

Things to double-check

UI simulator environment. make test and make test-ui both reproduced the same six UI failures while Xcode repeatedly reported DebuggerLLDB.DebuggerVersionStore.StoreError / no debugger version. Dedicated UI execution passed 18 runs. The branch changes neither production nor UI-test source, and the ownership fixture is not loaded by the UI-only run, so this is not assessed as a PR #192 regression; rerun the UI suite after repairing the local Xcode debugger store.