PRIOR BEHAVIOR (data-loss bug):
AppStateTests.setUp() constructed AppState() directly, which used the real
~/Library/Application Support/Stockbar/ for stocks.json. Each test method
that did 'sut.stocks = [s1, s2]' triggered didSet → saveStocks → silently
overwrote the user's actual portfolio file with 2 test entries. backupIfNeeded
then rolled all 10 backup snapshots forward, eventually erasing every
historical copy of real data.
This destroyed a user's 29-stock portfolio when xcodebuild test was run
during Korean stock feature development (2026-05-14 10:08).
FIX:
- AppState gains a static appSupportDirOverride: URL? hook
- AppStateTests.setUp() creates a unique tmpDir, sets the override, tearDown
resets and removes the directory
- Verified: after running all 7 AppStateTests, the real stocks.json is
byte-identical to before the run.
This must land before any further test run touches AppState.
AppState.koreanMarketSession (nonisolated) returns '盘中' during KST 09:00-15:30
on weekdays, nil otherwise. Marked nonisolated so it can be called from sync
non-MainActor contexts (notably tests).
AppState.refresh now has a 5th parallel branch fetching Korean quotes via
DataService.fetchKoreanQuotes. KR is non-throwing (returns [:] on failure) so
it's awaited outside the try block — any KR network failure does not abort
A股/港股fetch results.