mcp: session-notes — Android client → split-surface migration map + contract investigation
This commit is contained in:
parent
0e1d5c5ecc
commit
9b0b7ceb4e
@ -0,0 +1,52 @@
|
||||
---
|
||||
created: '2026-06-25'
|
||||
path: Sources/Dev
|
||||
project: petal-dispatch-phase-4-2-ingress-split
|
||||
tags:
|
||||
- dispatch
|
||||
- authentik
|
||||
- cloudflare
|
||||
- lovebug
|
||||
- mcp
|
||||
type: session-notes
|
||||
---
|
||||
|
||||
Planning + recon session (no code changes). Mapped how the `petal-dispatch-android` client must change to ride the split surface (ingress LXC) instead of the fused service, and verified the app↔ingress API contract against the live `phase-4.2/ingress-split` branch (`4002b17`). Travis added a major direction change mid-session: at cutover the **CF Access front-end is dropped in favor of his self-hosted Authentik layer**.
|
||||
|
||||
## Outcome
|
||||
|
||||
The app-side change to reach the split is **smaller than feared**. Verified findings:
|
||||
|
||||
- **Transport is already split-compatible.** `SseConsumer` already uses `?from_seq=N` with a live-only first connect and ignores `Last-Event-ID` — exactly the ingress contract (`harness_routes` reuse). Host coupling is centralized in one constant (`DispatchHttp.BASE_URL`).
|
||||
- **Contract investigation — four suspected gaps resolved (source-authoritative; route table grepped from `src/petal_ingress/app.py`):**
|
||||
1. `POST /api/tasks/{session_id}/action` — **MISSING. The one real functional gap.** No `/action` handler exists in `petal_ingress`. The app's worker pause/stop/delete (`DispatchApi.taskAction`) has no backend. Matches thread-605's deferred "small admin endpoint, not tonight" note. Fix = DB air-gap pattern (ingress writes action to a queue, executor consumes).
|
||||
2. `GET /api/threads?hide_archived=false` — param **ignored, non-breaking**. Split derives threads from `thread_state` BIGSERIAL (no archived concept). "Show archived" toggle is inert, not an error.
|
||||
3. `POST /api/threads/unassigned/activate` — **PRESENT** (app.py:523). Not a gap.
|
||||
4. `dispatch_session_id` in `POST /api/chat` — hardcoded `null` (app.py:658), but the app **never reads it** (`ChatProjection.sendOne` branches on `targetThreadId`). Benign.
|
||||
- **Design decision (Travis): the dispatch host becomes the app's first-ever setting**, which dissolves the earlier Path A (DNS repoint) vs Path B (point app at split) fork.
|
||||
- **Current-state drift caught:** loopback curls to `127.0.0.1:8001` returned 401 on `/api/*` — the ingress app itself is auth-gating now (CF-oriented middleware live), NOT the `_auth_noop` the checkpoints described.
|
||||
|
||||
## Topics Covered
|
||||
|
||||
- Recon of plan 300 (security rationale: ingress/executor split, DB as air-gap) + thread 605 (Phases 1–4 complete, parallel-run live, Phase 5 cutover gated on Travis).
|
||||
- Read the Android client end-to-end: `DispatchHttp`, `DispatchApi`, `SseConsumer`, `AuthManager`, `AndroidManifest`.
|
||||
- Live + source contract verification against the running ingress on this host.
|
||||
- The Authentik-replaces-CF-Access cascade and its (simplifying) effect on `AuthManager`.
|
||||
|
||||
## Key Learnings
|
||||
|
||||
- **The URL-setting dissolves the host fork but NOT the auth/manifest coupling.** A runtime `BASE_URL` cleanly drives REST/SSE and derives `REDIRECT_URI` + `RESOURCE`. But Android App Link `<data android:host>` is **compile-time** — autoVerify links are fixed in the APK and verified at install. So auth-capable hosts remain a bounded, pre-declared set. Recommended shape: make `BASE_URL` the setting; declare **both** `dispatch.herbylab.dev` and `split.herbylab.dev` as App Links (each origin serves `assetlinks.json`); register **both** redirect URIs at DCR (currently `buildDcrRequestBody` sends a single-element array). Host change ⇒ re-auth (token is audience-scoped) + SSE reconnect (`SseConsumer.restart()` exists).
|
||||
- **Dropping CF Access for Authentik DELETES app code rather than adding it.** Most of `AuthManager`'s complexity exists only to paper over CF's non-standard OAuth: the hand-rolled `parseDiscoveryConfig` (CF omits `jwks_uri`), the runtime DCR path (`ensureClientId`/`buildDcrRequestBody`/`parseDcrClientId`), the RFC 8707 `resource` indicator, and the `oauth:` bearer-prefix uncertainty. Authentik is a full OIDC provider → revert to AppAuth standard discovery, ship a static pre-registered `client_id`, drop the resource indicator (also removes one host-coupled auth constant). Unchanged: auth-code+PKCE flow, https redirect, manifest App Link + assetlinks, the Chromium Custom-Tab handoff workaround. Server side: ingress middleware swaps CF-assertion validation → Authentik JWT validation (issuer/audience/jwks).
|
||||
- **Keep IdP discovery/client_id pinned in config, NOT free-text user settings** — only the dispatch host should be user-facing. Pointing auth discovery at an arbitrary URL is a security smell.
|
||||
- Code answers "what is"; vault/trellis answer "what we decided and why." (Self-correction from earlier in session: should run `list_projects`/`list_threads` scoped to a subsystem before reconstructing intent from source.)
|
||||
|
||||
## Follow-ons
|
||||
|
||||
- [ ] **OPEN DECISION (blocks sequencing the auth work):** Authentik flow topology — does the app do auth-code+PKCE directly with Authentik (keeps a slimmed `AuthManager`), or does Authentik sit as a Traefik forward-auth outpost and the app rides an edge-managed session (removes most of `AuthManager`)? This fork decides how much auth code survives.
|
||||
- [ ] Build `POST /api/tasks/{session_id}/action` on ingress (DB air-gap queue → executor consumer) to restore worker lifecycle.
|
||||
- [ ] Add the dispatch-host setting (app's first settings screen): `BASE_URL` const → runtime read; `DispatchApi.BASE` dynamic; derive `REDIRECT_URI`.
|
||||
- [ ] Manifest: declare both hosts as App Links; serve `assetlinks.json` on each origin with the app's signing fingerprint.
|
||||
- [ ] Rewrite auth for Authentik: static `client_id`, standard AppAuth OIDC discovery, drop RFC 8707 resource, simplify token handling.
|
||||
- [ ] Server: swap ingress in-app middleware from CF Access assertion → Authentik JWT validation (or forward-auth header trust), depending on topology decision above.
|
||||
- [ ] Confirm before public exposure: ingress CF→Authentik cutover removes the `_auth_noop` history entirely; the loopback 401 shows in-app gating is already active.
|
||||
- [ ] Optional context-source improvement: there is almost certainly a dedicated vault plan + trellis thread for the Android client (it has `phase-4.1-cfauth` versioning, `docs/RECON.md`, `docs/HANDOFF-4b.md`) — locate it before the build to avoid re-deriving intent. Thread 588 (android + web build, long) is the likely home.
|
||||
Loading…
Reference in New Issue
Block a user