The scan terminal service had accumulated cache, payload, filtering, AI prompt, AI merge, METAR gate, ranking, and city-row construction details in one file. This splits those stable responsibilities into focused modules while preserving the endpoint payload shape and existing behavior.
Constraint: User-visible behavior and release version must remain unchanged for this internal refactor
Rejected: Rewrite the terminal scan flow around a new abstraction | too risky while production behavior is being stabilized
Confidence: high
Scope-risk: moderate
Directive: Keep scan_terminal_service.py as orchestration; add detailed rule changes to the focused modules instead of re-growing the service file
Tested: py_compile for extracted modules; ruff check .; pytest tests/test_scan_terminal_modules.py tests/test_web_observability.py; full pytest; npm run test:business; npm run build; git diff --cached --check
Qingdao needs the same airport-settlement path as the other Wunderground-backed APAC cities, so the registry, aliases, timezone, prewarm, official links, market focus, and tests now point to ZSQD / Qingdao Jiaodong International Airport.
Constraint: User supplied Wunderground Qingdao/ZSQD settlement URL.
Rejected: Add a partial registry-only entry | it would show in APIs without frontend links, prewarm coverage, or alias support.
Confidence: high
Scope-risk: narrow
Reversibility: clean
Tested: pytest tests/test_country_networks.py tests/test_web_observability.py::test_cities_endpoint_includes_new_wunderground_cities -q
Tested: npm run build
Not-tested: Live Wunderground fetch for ZSQD in production.
DeepSeek can return a polished city forecast that conflicts with already-computed stale-observation, observed-break, or peak-window evidence. The completion path now carries the deterministic fallback guard state and overwrites only the critical fields when provider text or numbers contradict those local facts.
Constraint: Airport-read latency optimization keeps provider output narrow, so backend completion remains the authority for final highs and evidence conflicts.
Rejected: Trust provider final wording when present | it can reintroduce stale METAR anchors or miss observed high breaks.
Confidence: high
Scope-risk: narrow
Tested: pytest tests/test_web_observability.py -q
Tested: npm run build