# DanoGo Mobile Bare Runtime Checkpoint — 2026-10-05

## Canonical architecture
DanoGo Mobile is a bare React Native persistent mobile runtime. Expo/EAS/Expo Updates are not in the canonical dependency chain.

Canonical source:
- `/native`

Legacy/migration evidence only:
- `/dano-mobile`
- `/ota` (Expo Updates experiment)

## Pinned runtime wheels
- React Native 0.87.1
- React Native Community CLI 20.2.0
- Hot Updater 0.36.17
- LiveKit React Native 3.0.0
- LiveKit WebRTC 144.2.0
- livekit-client 2.22.3
- AsyncStorage 3.1.1
- react-native-keychain 10.0.0
- react-native-device-info 15.0.2

## Native identity
- iOS bundle ID: com.dano.go
- Android application ID: com.dano.go
- Apple Team ID: 8L7A4LNY96
- default Hot Updater channel: danogo-home

## Runtime switching model
- `danogo-home` = embedded launcher/default
- `project/<canonical-project-id>` = guest project runtime channel
- reset channel + reload = return to DanoGo Mobile

## OTA topology
No S3/R2/MinIO/Postgres.

- Node OTA metadata service
- one local SQLite file
- first-party Hot Updater Kysely migration
- libSQL + Drizzle runtime commits
- Core local static HTTPS bundle files
- Hot Updater standalone repository protocol

### Why Kysely + libSQL/Drizzle
Hot Updater's Kysely SQLite runtime adapter passes raw booleans/objects to better-sqlite3 and fails binding.
Hot Updater's Drizzle adapter correctly maps:
- booleans -> SQLite integer boolean mode
- metadata/target cohorts -> JSON blob mode

Drizzle + better-sqlite3 cannot use Hot Updater's async transaction callback.
Local libSQL supports the async transaction contract while remaining a one-file embedded SQLite database.

Migration remains Kysely because Hot Updater only exposes its first-party migrator for Kysely/MongoDB.

## Verification evidence

### Registry contract
`v2/server/mobile-app-registry-v1.test.ts`
- 2 tests passed
- malformed v2 markers rejected
- only active explicitly opted-in projects returned
- secret/workspace-root leakage rejected

### Bare TypeScript
`npx --prefix native tsc -p native/tsconfig.json --noEmit`
- PASS

### Hot Updater doctor
- success: true
- server: 0.36.17
- update strategy: appVersion
- iOS detected: true
- iOS channel: danogo-home
- iOS bundleProviderConfigured: true
- Android detected: true
- Android channel: danogo-home
- Android bundleProviderConfigured: true
- native issues: []

### OTA server smoke
- health: PASS
- database: sqlite-libsql-drizzle
- version route: 200
- anonymous management route: 401
- authorized management route: 200
- SQLite file created: true

### Real Android OTA deploy
Channel:
`verification/android`

Target app version:
`1.0.0`

Bundle ID:
`01a10c98-43af-7910-bdda-a11e95192864`

Result:
- Metro build: PASS
- Hermes compilation: PASS
- upload to danogo-core-static: PASS
- standalone metadata commit: PASS
- deployment: PASS
- bundle HTTP download: PASS
- downloaded bytes: 1,513,111

Storage URL shape:
`/mobile-bundles/bundles/<bundle-id>/bundle.zip`

Hot Updater v0.36 also stores:
- manifest under the bundle directory
- content-addressed assets under `assets/sha256/<prefix>/<hash>.<ext>`

## Android native compile gate
Gradle reached project configuration successfully but Core has no Android SDK.
Failure is environmental:
`SDK location not found`

Do not install Android SDK on Core merely to satisfy this gate.
Run Android native compilation on a proper Android/Windows build worker.

## Remaining gates
1. Prove guest-project channel switch + return-to-home behavior.
2. Expose DanoGo `GET /v1/mobile/apps` through governed core mutation.
3. Wire evidence upload endpoint.
4. Add RSA OTA signing after private key can be stored in DanoGo Source/secret storage.
5. Build/sign real Android artifact on a mobile build worker.
6. Build/sign real iOS artifact on a macOS-capable worker or approved Apple build path.
7. Real-device proof: launcher -> project -> LiveKit -> Mark Issue -> return home.
