The native apps show the server's own UI in a WebView, where neither SSO nor
passkeys can run. They sign in through the system browser instead and need a
way to carry that session back.
The app keeps a random verifier and sends only its sha256 into the browser.
Once signed in there, the browser trades that challenge for a one-time code
(cookie session only, so an API or MCP token cannot mint itself a browser
session), and the WebView redeems the code together with the verifier. The
code rides through a URL scheme any app could claim, so on its own it is
worthless; it is single use and good for a minute.
Also: /api/health/features reports nativeApp so the apps can refuse servers
that predate this, and hashed files under assets/ are served immutable,
which the iOS app needs to start offline without a service worker.
GET /api/health/features lived in booking-import, which meant the client's
capability probe was reachable only because that domain happened to be
registered. Move it to health/ and give health an actual module instead of
two loose entries in app.module.
The extractor probe follows into a leaf module rather than health importing
BookingImportModule: features() needs isAvailable(), not llm-parse,
reservations, budget, maps and places.
The /api/_nest/{health,me,echo} smoke endpoints go. They proved boot, DI,
the cookie guard and the Zod pipe back when nothing else did; every one of
those now has real domain coverage, and nothing outside their own test ever
called them. The container probe is GET /api/health on the raw express layer
and is untouched.