The scan terminal had grown into overlapping CSS, request-state, AI-provider, and city-card data responsibilities. This refactor separates those boundaries without changing product behavior: CSS modules are split by surface, city AI prompt/provider/fallback logic is isolated, and scan terminal request state now has reusable RemoteData adapters plus business-state tests.
Constraint: Preserve existing global scan-terminal class names and API responses during the refactor
Constraint: No new dependencies; keep this as a file-boundary cleanup
Rejected: Introduce React Query now | higher migration risk than the requested lightweight query-client path
Rejected: Rewrite AI stream behavior | progressive/fallback states are product-sensitive and were only adapter-split
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep AI stream state changes covered by business snapshots before changing fallback/cache wording
Tested: npm run test:business; npx tsc --noEmit; npm run build; python pytest -q; ruff check; py_compile targeted city AI modules
Not-tested: Live DeepSeek provider network replay and browser visual QA
The dashboard risk is now mostly contradictory state combinations rather than styling. This extracts calendar action grouping into a pure utility and adds a lightweight TypeScript business-state runner so key decision states can be asserted without adding a test dependency.
Constraint: No new dependencies; use the existing TypeScript package for a local runner.
Rejected: Only rely on Next build/typecheck | it cannot catch product-language regressions such as fallback AI being labeled complete.
Confidence: high
Scope-risk: moderate
Reversibility: clean
Tested: npm run test:business
Tested: npm run build
Not-tested: Browser-rendered mobile fold interaction snapshots.