What is missing
ParkNudgeTests/TestFixtures.swift provides a ParkingSession builder and a FixedClock, and nothing else. There are no fakes for the nine protocols in ServiceProtocols.swift, so AppModel — which owns most of the app's decision-making — cannot be constructed in a unit test.
Everything it does is therefore either untested or tested indirectly through XCUITest, which is slow, device-dependent, and cannot assert on things that have no visible representation.
Concrete cost, already paid
Issue #15 asked for "UI coverage using a fake requester; verify no prompt is requested on first completion". That could not be written. ReviewPromptPolicy is fully unit-tested as a pure decision, but the wiring — that finishActive() evaluates it after the paywall flag is set, and passes the real completion count — is unverified.
The same gap hides:
- whether the first-completion paywall and the rating request can ever fire together;
- whether
alertMessage being set actually suppresses the rating request in practice;
- whether
thumbnail(for:)'s updatedAt-keyed cache really retires a replaced photo.
Suggested approach
Add in-memory fakes for ParkingRepository, LocationProviding, NotificationScheduling, PhotoStoring, DirectionsOpening, PurchaseProviding, CSVExporting and ReviewRequesting — the last one recording calls — plus a builder that assembles an AppModel from them with a FixedClock. AppEnvironment.makeUITesting already contains most of these as private types; promoting them into the test target is the smaller move than writing new ones.
Acceptance
Deferred deliberately from #15; recorded here rather than left implicit.
Resolution plan
- Verified: 2026-08-25T04:51:16Z against
main@04a6cd5e808720983471ee9595fd40bc94e1f0fe (commit time 2026-08-25T00:53:29Z).
- Source basis: Original issue body, all 0 comment(s), current default-branch tree, referenced pull-request states, and the protected top-90 dossier revalidated without modifying it.
- Disposition: Code or verification work - not complete on the verified default branch.
- Outcome: No AppModel test harness, so model-level behaviour is only ever proven through the UI
Current evidence and corrected premise
Verdict — NOT_STARTED. Confirmed by the shape of the test directory.
ParkNudge/Application/AppModel.swift exists. ParkNudgeTests/ contains 8 files and none of them
is an AppModel test:
CSVAndMoneyTests FeatureAccessTests MeterStateTests ParkingCoordinatorTests
ReminderPlannerTests ReviewPromptPolicyTests SwiftDataParkingRepositoryTests TestFixtures
The domain layer is well covered — MeterState, ReminderPlanner, ParkingCoordinator,
ReviewPromptPolicy, the repository. The application layer that composes them is not.
P2 · enhancement, area: ios, priority:p2, revenue:r3 · Canonical source: origin/main
Cluster: red or missing test suites — see CLUSTERS.md.
All 0 issue comment(s) were read. There are no comments.
Verified source paths on this head:
ParkNudge/Application/AppEnvironment.swift
ParkNudge/Application/AppModel.swift
ParkNudge/Domain/Services/ServiceProtocols.swift
ParkNudgeTests/ParkingCoordinatorTests.swift
ParkNudgeTests/TestFixtures.swift
scripts/verify.sh
Filed or dossier path references not present on this head; treat them as stale until relocated:
ParkNudgeTests/AppModelTests.swift
Resolution steps
Exact fix
Add ParkNudgeTests/AppModelTests.swift, following the conventions already in the directory:
- Reuse
ParkNudgeTests/TestFixtures.swift — it exists precisely to build domain objects for
tests; do not introduce a second fixture style.
- Follow
ParkingCoordinatorTests.swift for the composition-under-test pattern; it is the closest
analog (a coordinator over the same repository seam).
- Inject rather than construct:
AppEnvironment.swift is where ReviewRequester and
ReviewPromptPolicy are wired (3 references), so AppModel should be constructible with test
doubles through it. If it currently is not, making it injectable is the first task — and is
the real content of this issue.
- Cover at minimum: starting and ending a parking session updates state; the meter state exposed to
the UI matches MeterState for the same inputs; the review prompt is requested exactly when
ReviewPromptPolicy.shouldRequest says so (this closes a real gap — the policy is tested, its
invocation is not).
Tests and acceptance
Test / proof
xcodebuild test -scheme ParkNudge -only-testing:ParkNudgeTests/AppModelTests
The new tests must fail if AppModel stops calling a domain policy — verify by temporarily removing
one call and confirming a red.
Gate — the repo's unit scheme
- For every listed
xcodebuild argv, submit the equivalent focused job through the shared fleet-build gate after iOS capacity admission; do not run xcodebuild directly.
Dependencies and stop gates
Out of scope — ParkNudgeUITests; #29's unrendered meter states
- Do not close this issue until every acceptance item is mapped to exact merged-head evidence.
Next AI first action
Reuse ParkNudgeTests/TestFixtures.swift** — it exists precisely to build domain objects for
What is missing
ParkNudgeTests/TestFixtures.swiftprovides aParkingSessionbuilder and aFixedClock, and nothing else. There are no fakes for the nine protocols inServiceProtocols.swift, soAppModel— which owns most of the app's decision-making — cannot be constructed in a unit test.Everything it does is therefore either untested or tested indirectly through XCUITest, which is slow, device-dependent, and cannot assert on things that have no visible representation.
Concrete cost, already paid
Issue #15 asked for "UI coverage using a fake requester; verify no prompt is requested on first completion". That could not be written.
ReviewPromptPolicyis fully unit-tested as a pure decision, but the wiring — thatfinishActive()evaluates it after the paywall flag is set, and passes the real completion count — is unverified.The same gap hides:
alertMessagebeing set actually suppresses the rating request in practice;thumbnail(for:)'supdatedAt-keyed cache really retires a replaced photo.Suggested approach
Add in-memory fakes for
ParkingRepository,LocationProviding,NotificationScheduling,PhotoStoring,DirectionsOpening,PurchaseProviding,CSVExportingandReviewRequesting— the last one recording calls — plus a builder that assembles anAppModelfrom them with aFixedClock.AppEnvironment.makeUITestingalready contains most of these as private types; promoting them into the test target is the smaller move than writing new ones.Acceptance
AppModelconstructible in a unit test with all dependencies faked.isPaywallPresentedoralertMessageis set../scripts/verify.shstill green.Deferred deliberately from #15; recorded here rather than left implicit.
Resolution plan
main@04a6cd5e808720983471ee9595fd40bc94e1f0fe(commit time 2026-08-25T00:53:29Z).Current evidence and corrected premise
Verdict — NOT_STARTED. Confirmed by the shape of the test directory.
ParkNudge/Application/AppModel.swiftexists.ParkNudgeTests/contains 8 files and none of themis an AppModel test:
The domain layer is well covered —
MeterState,ReminderPlanner,ParkingCoordinator,ReviewPromptPolicy, the repository. The application layer that composes them is not.P2 ·
enhancement, area: ios, priority:p2, revenue:r3· Canonical source:origin/mainCluster: red or missing test suites — see
CLUSTERS.md.All 0 issue comment(s) were read. There are no comments.
Verified source paths on this head:
ParkNudge/Application/AppEnvironment.swiftParkNudge/Application/AppModel.swiftParkNudge/Domain/Services/ServiceProtocols.swiftParkNudgeTests/ParkingCoordinatorTests.swiftParkNudgeTests/TestFixtures.swiftscripts/verify.shFiled or dossier path references not present on this head; treat them as stale until relocated:
ParkNudgeTests/AppModelTests.swiftResolution steps
Exact fix
Add
ParkNudgeTests/AppModelTests.swift, following the conventions already in the directory:ParkNudgeTests/TestFixtures.swift— it exists precisely to build domain objects fortests; do not introduce a second fixture style.
ParkingCoordinatorTests.swiftfor the composition-under-test pattern; it is the closestanalog (a coordinator over the same repository seam).
AppEnvironment.swiftis whereReviewRequesterandReviewPromptPolicyare wired (3 references), soAppModelshould be constructible with testdoubles through it. If it currently is not, making it injectable is the first task — and is
the real content of this issue.
the UI matches
MeterStatefor the same inputs; the review prompt is requested exactly whenReviewPromptPolicy.shouldRequestsays so (this closes a real gap — the policy is tested, itsinvocation is not).
Tests and acceptance
Test / proof
xcodebuild test -scheme ParkNudge -only-testing:ParkNudgeTests/AppModelTestsThe new tests must fail if
AppModelstops calling a domain policy — verify by temporarily removingone call and confirming a red.
Gate — the repo's unit scheme
xcodebuildargv, submit the equivalent focused job through the shared fleet-build gate after iOS capacity admission; do not runxcodebuilddirectly.Dependencies and stop gates
Out of scope —
ParkNudgeUITests; #29's unrendered meter statesNext AI first action
Reuse
ParkNudgeTests/TestFixtures.swift** — it exists precisely to build domain objects for