NEXT LAUNCH: FRANKENSTEIN ARCHITECTURE
A deliberate architecture counterexample from 3 Days of Swift Concurrency.

OPEN
Open NextLaunchFrankenstein.xcodeproj. Select the NextLaunchFrankenstein scheme
and an iPhone or iPad simulator, then Run. Xcode 26.2 was used for validation.
iOS 17 minimum; Swift 6 language mode; complete concurrency checking;
nonisolated default actor isolation, with explicit MainActor types.
App ID: com.3DaysOfSwiftConcurrency.NextLaunchFrankenstein
Test ID: com.3DaysOfSwiftConcurrency.NextLaunchFrankenstein.NextLaunchFrankensteinTests
No external packages, network access, signing team or credentials are supplied.
Simulator execution requires a working local Simulator runtime. Physical devices
require selecting your own signing team.

WHAT THIS IS
An isolated Next Launch-inspired review lab, not a damaged copy of the course app.
It preserves the Next Launch icon, but has a separate bundle ID and product name.
The deliberate defects live in Core/LegacyLaunchManager.swift and
Core/LaunchViewModel.swift. Core/ScenarioTransport.swift and LabJournal.swift
are classroom controls: synthetic data, explicit response delivery and observation.
They are not real production providers or recommended production architecture.
The old GCD design is represented by a callback API and retained queue hop;
this is not a historical before/after migration of a real production repository.

FRANKENSTEIN ARCHITECTURE
A company teaching term for incompatible or unexamined design assumptions stitched
together without coherent ownership, lifetime and behaviour. Mixing technologies
alone is not the diagnosis. The missing contracts and their effects are.

REPRODUCE
1. Start the app. Press Refresh twice. No network request will be made.
2. The status already says Refresh complete while two responses remain pending.
3. Deliver response 2. Model current launch becomes response 2; screen snapshot
   remains empty because its completion callback ran before the response arrived.
4. Copy model snapshot. Now the screen temporarily agrees with the model.
5. Deliver response 1. The old result overwrites model state. The screen still
   shows response 2. Two authorities now disagree about the same launch.
6. Press Refresh again. Press Stop. Deliver the pending response. The model
   changes even though the screen says Stopped.
7. Copy model snapshot, press Refresh, then Fail that response. The model erases
   the useful launch; the screen retains an old snapshot and says Refresh complete.

Restart the app for a clean experiment. Deliver or fail pending responses to
finish them. Nothing persists across launches. There is intentionally no fake
Reset that claims to cancel work whose handles have already been discarded.

DEFECT MAP
FA-01: LegacyLaunchManager.refresh — completion fires when work is queued, not
       when it completes; the old main-queue hop surrounds a new Task.
FA-02: LegacyLaunchManager.refresh / LaunchViewModel.stop — Task handle discarded;
       repeated refreshes create duplicate work; Stop changes presentation only.
FA-03: LegacyLaunchManager.refresh — publication has no request relevance check.
FA-04: LegacyLaunchManager.refresh catch — failure silently clears useful data.
FA-05: LaunchViewModel.displayedLaunch — writable snapshot has no update contract.

TESTS
The four Swift Testing tests PASS when the known bugs are reproduced. They are
characterization evidence, not production acceptance tests. Command-U runs the
unit-test target in Xcode. No UI-test target was added.
The same core and tests can run on macOS with `swift test --disable-sandbox`.
They use explicit continuation gates, not sleeps or network timing.
When repairing a defect, change its test to express the intended correct outcome.
Keep the counterexample unchanged; copy it into a separate repair project first.

REPAIR BRIEF
State the product rule before changing code. Decide whether an operation should
be awaited in the current task, become structured child work, or have a separate
longer-lived owner. Repeated equivalent refreshes might share one operation;
changed inputs need an explicit policy. A ViewModel owns a screen workflow;
a Feature owns shared rules. Handle retention alone does not prevent stale writes.
Do not move all Tasks into Views or create an actor for every method.
Use the CFA AI Toolkit for iOS to guide the review and proposed repair.


