TransitPR #192origin/main...HEAD2026-08-01

Independent pre-push review

T-2003: SwiftData test-container lifetime migration

Needs fixes

The runtime fix is coherent and the 101-file migration is complete for test sources. Fresh containers preserve test isolation, process-lifetime retention protects contexts that escape setup helpers, and the regression passes. The PR should not be pushed yet because its advertised recurrence guard does not cover several realistic unsafe factory forms; one active agent note also directs contributors to a removed helper.

Scope reviewed

  • Fetched origin/main
  • Reviewed git diff origin/main...HEAD
  • 101 files: 627 additions, 293 deletions
  • No production Swift source changes

Verdict basis

  • Migration completeness: pass
  • Container ownership: pass
  • Retention tradeoff: acceptable and explicit
  • Lint guard coverage: must fix
  • Regression tests: pass, with scope note

Findings

P2 · Must fix

.swiftlint.yml:13-17 — the guard misses unsafe factories that can recreate T-2003

The error-level custom rule matches only a throwing function whose entire return type is exactly ModelContext, plus calls to the removed newContext(). A direct probe showed:

Factory shapeSwiftLint result
func f() throws -> ModelContextRejected
func f() -> ModelContext (for example using try!)Accepted
func f() throws -> (Service, ModelContext)Accepted
func f() throws -> Env where Env stores only a context/serviceAccepted

The tuple/setup exemptions are safe in the migrated code only because those implementations call TestModelContainer(), whose static registry retains the container. The rule cannot enforce that premise. A future helper can call the public, explicitly unregistered TestModelContainer.newContainer() (or construct ModelContainer directly), return a tuple/setup object without its owner, pass lint, and reintroduce the same crash.

Fix direction: enforce ownership rather than one signature spelling. Options include restricting raw container/context construction to an allowlisted fixture file, making the unregistered escape hatch harder to misuse, adding a broader source guard for context-bearing factory returns, and adding rule-fixture tests that prove both accepted and rejected shapes.

P3 · Documentation

docs/agent-notes/reports.md:77 still recommends the removed makeReportTestContext()

The migration replaces that helper with makeReportTestContainer(), but the active reports agent note still says GenerateReportIntentTests uses makeReportTestContext(). This undermines the new ownership guidance and will send future changes toward a nonexistent, unsafe API shape. Update it as part of this migration. Historical changelog/spec references do not need rewriting.

Audit details

Migration completeness

SwiftData ownership and retention tradeoff

Regression tests

Validation

CheckResultEvidence
make lintPass303 Swift files; 0 violations.
make test-quick PIPE_PRETTY=PassmacOS TransitTests completed; lifetime regression explicitly passed.
make test PIPE_PRETTY=UI-only failuresAll unit tests completed; six UI tests failed while Xcode repeatedly emitted DebuggerLLDB.DebuggerVersionStore.StoreError / no debugger version. Full log: /tmp/transit-pr192-make-test-20260801-205150.log; xcresult: DerivedData/Logs/Test/Test-Transit-2026.08.01_20-51-56-+1000.xcresult.
Static migration searchesPassNo legacy helper calls in test sources; sole raw fixture escape hatch retains its container.
Custom-rule probesCoverage gapExact throwing return rejected; nonthrowing, tuple, and setup-struct unsafe shapes accepted.
Worktree status after reviewCleanNo source changes made; no merge performed.

The UI failures are not attributed to this PR: the merge-base diff changes only test-target sources, lint/docs/changelog/spec files, while the failures occur in the separate UI-test target and coincide with repeated debugger-version launch errors. They remain recorded because the documented pre-push suite did not return success.

Recommended push gate

  1. Strengthen the prevention mechanism and add executable rule fixtures for bypass shapes.
  2. Update docs/agent-notes/reports.md to the owning-container helper.
  3. Re-run make lint, the lifetime test/macOS suite, and the full iOS suite when the simulator/debugger environment is healthy.