Страницы · Health Debug
X2 — AI BYOK Proxy — Session Card
Per-module session list for X2 AI BYOK Proxy. Read this alongside
docs/plan/13-execution-modules-and-sessions.md(the execution framework this card implements),docs/plan/10-security-integrations-b2b.md(the authoritative BYOK/AI design), anddocs/plan/02-platform-divergences.md§2.4 (divergence #4). This is a planning artifact — no production code, no invented constants.
Purpose
X2 delivers the Bring-Your-Own-Key (BYOK) AI layer: users supply their own API key for one or more of four supported providers (OpenAI, Anthropic, Google, Apple Intelligence); the ToGO backend stores those keys encrypted at rest, and all AI calls are proxied server-side so no key ever reaches any client. The AI does behavioral pattern analysis only — never diagnosis, prescription, or drug-category guessing — and the mandatory "Consult your doctor." deferral is enforced deterministically in the proxy layer, not left to the prompt. Every client "AI settings" screen is a pure passthrough form to the backend: write-only key submission, no read-back, nothing stored locally. This module closes divergence #4 (AI working on legacy iOS via Apple Intelligence, missing on Android) once the Android session lands, by turning "integrate AI" into "render a passthrough screen against a contract that already exists."
Feature parameters relevant to this module (exact — do not invent)
These are the fixed facts this module builds against. No numeric engine constants apply to the AI proxy; the binding constraints are categorical/security rules.
- Supported providers (enum):
openai,anthropic,google,apple_intelligence. This is the only provider set. - No key ever reaches a client. Keys travel once (client → backend, authenticated HTTPS) and are never returned, cached, or transited by any client afterward.
- No key read-back endpoint. Clients may learn only that a key exists for a provider (status: exists / not set), never what it is. A masked hint is PENDING DESIGN (open question #8).
- Encrypted at rest. Keys are encrypted before persistence in PostgreSQL; decrypted only in server memory at the moment of an outbound provider call. Encryption mechanism (application-level envelope encryption vs. external KMS) and the encryption-key rotation policy are an OPEN QUESTION (doc 10 §6 #4) — do not pick one silently.
- All AI calls proxied server-side. No client constructs prompts, selects providers, or post-processes AI output. Client role is strictly: submit key (write-only) / send analysis request / render response.
- Deterministic guardrail (Core Opinion 2). Every AI output ends with "Consult your doctor.", appended/verified in the proxy layer (post-processing), independent of model obedience. The AI is strictly prohibited from diagnosing, prescribing, or guessing drug categories.
- Categorical, not quantitative (Core Opinion 1). The AI performs no quantitative food deduction; behavioral analysis runs over categorical protocol events only.
ai_provider_keysschema: every columnNOT NULLwith a defined default (per the strict schema rule). Planning sketch (doc 10 §2.5):provider text NOT NULL DEFAULT 'openai'(enum-checkedopenai|anthropic|google|apple_intelligence),encrypted_key bytea NOT NULL DEFAULT ''(ciphertext only; plaintext never stored),key_status text NOT NULL DEFAULT 'active'(active|revoked), plusid/user_id/created_at/updated_at. One row per (user, provider); rotation-history retention is undecided.- API surface sketch (names are placeholders, finalized against the Phase 1 API-conventions doc):
PUT /v1/ai/keys/{provider}(submit/replace — returns no key material),GET /v1/ai/keys(list provider status — never returns material),DELETE /v1/ai/keys/{provider}(revoke),POST /v1/ai/analyze(behavioral analysis — returns analysis text only).
Session table
One row per session. Surfaces follow the module order (backend → web → chrome → apple → android → desktop); there is no mcp session — the MCP surface holds no AI keys and no protocol/AI logic (doc 13 §5). Backend must land before any client session. Replace <date> (YYYY-MM-DD) and NN (zero-padded index) at session start.
| Session ID | Surface | Scope (what this one session builds) | Entry deps | Done criteria (doc 13 §5) | Plan docs to read |
|---|---|---|---|---|---|
S-<date>-X2-backend-NN | backend | The aiproxy module/plugin: ai_provider_keys schema + migration; encrypt-at-rest write path; PUT/GET/DELETE key endpoints (write-only, status-only list, no read-back); POST /v1/ai/analyze proxy that builds the guardrail system prompt server-side, calls the user's configured provider, and deterministically appends/verifies "Consult your doctor." in the proxy layer; provider adapters (openai/anthropic/google/apple_intelligence) stubbed or wired per Phase-1 scope decision. | M0.1–M0.4 (kernel, TOGO auth + per-user users row, plugin framework, migration harness); M1 backend exists (X-modules land after M1 — doc 13 §4). | Backend-engine template, adapted for a non-engine module: module registered on the kernel; migration is expand-contract and every column is NOT NULL with a default; endpoints return computed state; no endpoint returns key material (verified); key is encrypted before persistence and decrypted only in-memory server-side; the "Consult your doctor." deferral is enforced in the proxy and covered by a unit test that passes regardless of model output; no diagnosis/prescription/drug-category output path exists; unit tests encode the provider enum + deferral literally; integration test vs. real Postgres (key write → rotate → revoke; no-readback; deferral append; cross-user isolation 404-not-403) passes; no key material leaves the backend. Record the encryption-mechanism choice as an open question if still unresolved. | 10 §2–§3 & §6; 04 §2 (aiproxy module) & §4–§5; 13 §5–§6; 01 (Core Opinions). |
S-<date>-X2-web-NN | web | /settings/ai — the BYOK passthrough form: provider picker + key field; write-only submit to PUT /v1/ai/keys/{provider}; renders provider status from GET /v1/ai/keys; renders proxied analysis (incl. the server's "Consult your doctor." deferral) verbatim where surfaced. Never displays stored key material. | S-<date>-X2-backend-NN done; M0.5–M0.7 (web shell + typed API client, theme engine, i18n engine). | Client-engine template, adapted for a settings passthrough: screen renders server key-status and submits key intents only (write-only); thin-client/SSOT audit passes — no key persisted in browser storage, no AI-provider SDK/endpoint in client code, no prompt construction, no client-side deferral logic (the deferral is rendered from server output, not synthesized); both themes render per the strict color spec; Arabic RTL mirrors correctly; strings are ICU, none concatenated. Masked-hint treatment is PENDING DESIGN. | 05 §1 (constraints), §4 (API map), §9.3; 10 §2.3; 13 §5. |
S-<date>-X2-chrome-NN | chrome | Options-page AI BYOK section: provider + key entry submitted write-only to the backend (POST /ai/keys); renders provider status; no AI calls originate in the extension. | S-<date>-X2-backend-NN done; Chrome extension shell + TOGO auth linkage (from M1 chrome). | Client template (as above). Additionally: keys are never written to chrome.storage (which is not encrypted at rest), never attached to any client-side call, never echoed; a static scan proves zero AI keys/SDKs/provider endpoints in the extension bundle; both themes + Arabic RTL + ICU strings. | 06 §1 (row 4), §3.2, §9.3, §11–§12; 10 §2.3; 13 §5. |
S-<date>-X2-apple-NN | apple | Settings AI BYOK passthrough screen (iOS, shared with macOS): provider + key entry, write-only submit, status render, proxied-analysis render with the deferral verbatim. | S-<date>-X2-backend-NN done; Apple workspace + shared packages + TOGO auth session (from M1 apple / Apple scaffold). | Client template (as above). Additionally: no provider key in Keychain, memory, or entitlements; copy audit confirms no diagnostic/prescriptive phrasing and that AI-surface copy carries the "Consult your doctor." deferral; both themes + native RTL mirroring + ICU. Apple Intelligence BYOK shape is an OPEN QUESTION (doc 10 §6 #5, doc 07 OQ #8) — do not ship a client-side Apple Intelligence path that violates "no key on client / all calls proxied"; if the platform forces an exception, document it narrowly rather than implement silently. | 07 §1 (rows 3–4), §4 (AI row), §9 (audits), Open Questions #8; 10 §2.3 & §6 #5; 13 §5. |
S-<date>-X2-android-NN | android | Settings AI BYOK passthrough screen (Kotlin/Compose): provider + key entry, write-only submit, status render, proxied-analysis render with the deferral. Closes divergence #4 (AI missing on Android). | S-<date>-X2-backend-NN done; Android app shell + TOGO auth + core/network (from M1 android). | Client template (as above). Additionally, the divergence-#4 closure criteria: static scan shows zero AI-provider SDKs/keys/endpoints in the client; runtime shows AI features function through the ToGO proxy only; no key on device; both themes render on physical device; Arabic RTL mirrors; ICU strings. Whether Apple Intelligence is selectable from Android is an open question (doc 02 OQ #1) — render only what the backend offers. | 08 §1 (row 4), §4.3 (AI row), §10 (#4 closure), §11 acceptance; 02 §2.4; 10 §2.3; 13 §5. |
S-<date>-X2-desktop-NN | desktop | Settings AI BYOK section reusing the shared web component: submit the key once over HTTPS, render status + proxied results. No key caching, no key display after entry. | S-<date>-X2-backend-NN done; Electron shell + shared React app + packages/api-client (from M1 desktop). | Client template (as above). Additionally: no AI provider key in config, memory, the renderer, or the main process; key submitted once and never displayed again; reuses the web /settings/ai component so both themes + RTL + ICU inherit from Phase 2; SSOT audit confirms packages/api-client holds no AI logic. | 09 (AI & BYOK section), §3 constraints; 05 §9.3 (shared component); 10 §2.3; 13 §5. |
Notes & gotchas
- Legacy precedent worth reusing (concept only, not code): legacy iOS already had a working API-key proxy for AI via Apple Intelligence (divergence #4, ahead side). The greenfield design generalizes that proxy into the server-side
aiproxymodule so every client is a thin passthrough — reuse the idea of server-side proxying, port none of the legacy client-side AI code. - Divergence #4 is only closed by the Android session. Backend + iOS parity is not the closure; the ledger entry for #4 flips only when
S-<date>-X2-android-NNpasses its acceptance (doc 02 §2.4, doc 08 §10). - Liabilities to avoid (hard rules):
- Never store, cache, echo, or log a provider key on any client — including
chrome.storage(not encrypted at rest), Keychain, entitlements,localStorage, config files, the Electron renderer/main process, or memory beyond the single submit request. - Never add a key read-back endpoint.
GET /v1/ai/keysreturns status only. - Enforce "Consult your doctor." in the proxy layer deterministically — never rely on the model/prompt alone to produce it.
- No client builds prompts, selects providers, or post-processes AI text; no client-side diagnosis/prescription/drug-category logic; no quantitative food modeling (Core Opinion 1).
- No
mcpsession for X2 — the MCP surface holds no AI keys and no AI logic (doc 13 §5).
- Never store, cache, echo, or log a provider key on any client — including
- PENDING DESIGN items (do not invent; blocked on the Figma/design track):
- Whether a masked key hint is shown at all in the AI settings screen (open question #8).
- The AI settings screen visuals per platform — dark-glow / light-flat palette application and full RTL/Arabic mirroring (open question #9).
- OPEN QUESTIONS to carry (undecided — surface in each session's handoff, do not resolve unilaterally): key-encryption mechanism (app-level envelope vs. KMS) + encryption-key rotation (doc 10 §6 #4);
aiproxyPhase-1 scope — ship vs. reserve table + plugin slot only (doc 04 §2); Apple Intelligence BYOK shape / possible narrow proxy exception (doc 10 §6 #5, doc 02 OQ #1); AI proxy audit logging & retention (doc 10 §6 #6); server-side output filtering beyond the mandatory deferral (doc 10 §6 #7).
Handoff reminder
At the end of every X2 session, write one session-handoff memory to the healthdebug brain (retain the content in the doc 13 §6 structure, then memory/edit to attach metadata — retain cannot set metadata) with a unique source_ref: handoff/X2-ai-byok/<surface>/<n> (never reuse) and metadata { project: "healthdebug", category: "session-handoff", era: "greenfield", status: "current", surface: "<surface>", module: "X2", title: "Handoff <session-id>", tags: [...], next: "<module+surface>" }. Then update the single build-ledger memory (source_ref: build-ledger, edited in place) so one recall shows the whole frontier and the recommended next session. Any new architectural decision or open question also gets its own classified memory and, if it changes the plan, an edit to the relevant plan doc. See doc 13 §6 and docs/brain/BRAIN-INDEX.md.