medOS ultra

Membrane Buildout (Master)

Orchestrating plan for the buildable, additive slice of the Membrane sovereign multimodal-bio-AI vision.

7 min read diagramsUpdated 2026-06-09docs/architecture/membrane-buildout/00-MASTER.md

The orchestrating plan for building the buildable, additive, useful-now slice of the Membrane vision into medOS-ultra: Layer 0 (the Human Event Stream schema) → the Intelligence Query layer on top of it → a demo surface. This is the institution-node scope. Everything that needs a fleet, a trained foundation model, or on-device compute is explicitly out of scope and gated — per Membrane’s own sequencing discipline (“the platform is the last organ to grow, not the first”).

Companion docs: docs/architecture/human-event-stream-layer0.md (the Layer-0 spec, shipped), the Membrane platform analysis (in-conversation), and the execution framework docs/module-loop/00-MASTER.md + docs/module-loop/AUTONOMOUS-MODE.md. This plan is a module-loop run: 10-stage discipline, 28 hard principles, additive-only, sandbox+static verification per iteration.


0. Why this scope, and not the whole platform

Membrane is five layers (schema → runtime → SDK → modules → coordination plane) plus the Osmosis federated protocol. The analysis established that medOS-ultra already realizes ~4 of the 5 in partial form except the live federated network, which is the actual business and which the doc says comes last. The honest, disciplined build target is therefore the part that is (a) additive, (b) reversible, © useful immediately, and (d) verifiable without a fleet or a trained model:

  • Layer 0 — the typed, time-stamped, modality-tagged, encoder-versioned, consent-scoped event shape, as an additive extension of the live observations read model. (Substrate already shipped: 20260603d.)
  • The Intelligence Query layer — structured cohort query + semantic (vector) retrieval over that stream, driven by an LLM that function-calls allowlisted, parameterized RPCs (never raw SQL). This is what “give me diabetic patients age 40–60” actually needs, and it reuses the shipped runAgentLoop + ASSISTANT_REGISTRY substrate.
  • A demo surface — a read-only Cohort/Intelligence Query console in the super-admin Intelligence section.

Explicitly OUT OF SCOPE (gated — do NOT build in this loop)

Excluded Why gated
Federation / Osmosis (secure aggregation, DP, LoRA delta sync) Gated on single-modality FL working at all; bleeding-edge; no scaffolding exists
On-device model training / tiered placement runtime The secure-custody half (wallet/did:bio) exists; federated-compute half does not
Coordination plane (Layer 4 — the business) Needs a fleet + a trained model to coordinate
survival module (time-to-event) / predict_next_events() trajectory SDK Gated on a foundation model proving the moat (Horizon 1)
Pseudonymizing the operational store Wrong by design — de-id is a Silver-layer concern (ai-training-corpus.md)
Applying migrations to prod / pushing to release Manual + requires explicit user sign-off

1. Invariants (every iteration must hold these)

  1. Additive-only. New columns/tables/functions/files only. Never alter/drop an existing column, constraint, index, RLS policy, or file. (web/CLAUDE.md ABSOLUTE GUARDRAILS.)
  2. LLM never writes raw SQL. It function-calls allowlisted, parameterized RPCs; it fills params; a vetted RPC executes. No hallucinated entities (reuse the seenMatches guard).
  3. RLS + consent_scope bound every read. Query RPCs run with caller privileges (RLS-enforced), not SECURITY DEFINER, unless a reviewed reason exists. PHI (patient lists) is gated behind an explicit param + role; default returns counts/aggregates.
  4. Recommender-only. No autonomous writes, no gating of clinical actions, every AI call audited (llm_audit_log). Feature-flagged OFF by default, per-tenant.
  5. No migration is applied by the loop. Migrations are written + statically reviewed; apply is a manual, user-gated step (per Deployment Status table).
  6. Reuse, don’t rebuild. runAgentLoop, ASSISTANT_REGISTRY, @medical-kit/code-systems, llm_search_embeddings pattern, design-kit wrappers, the cron_jobs registry — extend them.
  7. Bilingual seed/UI (TH/EN) where user-facing, per repo i18n rule.
  8. Stay on main, never branch/switch/stash. Commit additive work incrementally with loop trailers; do not push.

2. STOP conditions (halt the loop, ask the user)

  • Any change that would be destructive / non-additive (drop, stub, bulk-edit, config edit).
  • Any need to apply a migration to a live DB, push to release, or deploy.
  • Any ambiguity in auth/RLS/consent semantics for a query that returns PHI.
  • Any place where returning a patient list could leak beyond consent and the gate isn’t obvious.
  • Discovery that an assumed read-model column/JSONB path doesn’t exist (verify, then proceed or ask).

3. Phases

Each phase is a loop iteration: build → static-verify → commit (feat(membrane): … / Loop: membrane-buildout / Phase: Pn). Order is dependency-driven; later phases consume earlier RPCs/types.

P0 — Layer 0 substrate completion

  • 20260603d_human_event_stream_layer0.sqlobservations + modality/embedding(768)/encoder_id/encoder_version/consent_scope.
  • docs/architecture/human-event-stream-layer0.md.
  • 20260603e_observation_modality_backfill.sql — idempotent category/source_kindmodality backfill (WHERE modality IS NULL).
  • HumanEvent TS contract + read-only accessor over observations (Layer-2 seed; no writes). Home: web/src/services/human-event-stream/.
  • Verify: SQL static review vs 20260512_observation_unification.sql; tsc on the new TS.
  • infrastructure/medbase/functions/observation-embedder/index.ts — Deno edge fn: select observations WHERE embedding IS NULL (batch), build a compact text doc per row (code_display + value + unit + modality), call Ollama /api/embeddings (nomic-embed-text, 768), UPDATE embedding, encoder_id, encoder_version. Idempotent, batched, fail-soft, env-driven OLLAMA_URL.
  • 20260603f_observation_semantic_search.sqlsearch_observations_by_embedding(vector(768), patient_id?, modality?, limit, min_score) RPC (cosine <=>, RLS-enforced, capped limit).
  • cron_jobs registry row for the embedder (off by default; per cron-jobs-registry.md).
  • Verify: Deno typecheck if available; SQL static review vs llm_search_embeddings/search_conference_decisions_by_embedding.

P2 — find_patient_cohort RPC

  • ☐ Verify exact shapes first: patient_clinical_cache (age/gender columns), encounter_journey_cache diagnosis JSONB path (handleDiagnosisRecorded), observations lab filter.
  • 20260603g_find_patient_cohort.sql — parameterized RPC: {age_min, age_max, gender, diagnosis_codes text[], lab_code, lab_min, lab_max, date_from, date_to, include_subjects bool, limit}. Returns count + aggregates by default; subject rows only when include_subjects (role-gated). RLS-aware.
  • Verify: SQL static review; a *.sql-shaped self-test (EXPLAIN-able) documented in the phase notes.

P3 — Population READ tool (cohort-query domain)

  • web/src/services/ai/cohort-query/{tools,runner,dispatcher,prompts,index}.ts — tools findPatientCohort, searchSimilarObservations; dispatcher calls supabase.rpc(...); register cohortQueryDomain in ASSISTANT_REGISTRY (toolClass read, featureFlag: 'assistant.cohortQuery.enabled').
  • ☐ Reuse runAgentLoop; enforce no-raw-SQL + param allowlist + audit.
  • Verify: tsc; unit test of the dispatcher mapping (NL params → rpc args) with a mocked supabase client.

P4 — Cohort Query Console (frontend demo)

  • CohortQueryConsole.tsx in the super-admin Intelligence section + a route under /admin/intelligence/…. NL input → parsed cohort chips → result count + aggregate bar + gated subject table. design-kit wrappers; confidence + consent badges; read-only.
  • ☐ Sandbox target + registry.ts entry + *.sandbox.spec.ts smoke.
  • Verify: pnpm dev:sandbox + Playwright sandbox smoke (no auth).

P5 — Docs + verification + UAT

  • ☐ “Query & retrieval” section in human-event-stream-layer0.md (3 modes: structured cohort RPC / per-patient time-series / semantic vector; the no-raw-SQL contract).
  • ☐ Demo script (docs/demo-scripts/intelligence-query.md) + UAT checklist.
  • ☐ End-to-end static + sandbox verification pass; update this progress log.

4. Verification reality (what “verify” means without a fleet)

  • SQL: static review against the exact patterns in already-applied migrations (read, don’t guess); idempotent + additive; never applied by the loop. Apply is the user’s manual step.
  • TS: tsc (workspace or scratch per docs/architecture/fhir-ipd-handoff-2026-05-09.md /tmp/jest-run trick if deps aren’t installed).
  • Frontend: lightweight sandbox (:5179 ?target=…) + playwright.sandbox.config.ts (no auth). Local full-app Supabase is stale (memory) — do not rely on live data locally.
  • Edge fn: Deno typecheck; logic review; deploy is manual (supabase functions deploy).

5. Progress log

Date Phase What landed Commit
2026-06-03 Plan + P0 master plan + Layer-0 substrate (20260603d/e, HumanEvent TS contract, layer0 doc) 3dd80d29e
2026-06-03 P1 + P2 semantic-search RPC (20260603f) + observation-embedder edge fn + writer RPC (20260603h) + find_patient_cohort RPC (20260603g) bff52c8c0
2026-06-03 P3 cohort-query READ tool (6 files + registry); 11/11 dispatcher unit tests 5a87a7394
2026-06-03 P4 CohortQueryConsole + /admin/intelligence/cohort-query route; 4/4 e2e agent-loop test 4a69d8bee
2026-06-03 P5 query-layer doc section + this log (this commit)

Buildout status (2026-06-03): P0–P5 SHIPPED as code — additive, verified, committed to main, NOT applied/pushed. To go live (each a manual, user-gated step): (1) apply migrations 20260603d–h to the target Supabase; (2) supabase functions deploy observation-embedder + set LLM_EMBED_URL; (3) optionally run the embedder + register its cron_jobs row; (4) set assistant.cohortQuery.enabled for the tenant; (5) deploy frontend via release. OUT-OF-SCOPE items (federation/Osmosis/on-device training/coordination plane) remain gated — promoting any is a separate decision. One flagged review item: the cohort-query cross-patient PHI posture (aggregates-first, RLS-safe-fail, subjects opt-in) — confirm before exposing the subject-list path to non-service roles.

Update this table every iteration. When all P0–P5 boxes are ticked and verified, the buildout is complete; promotion of any OUT-OF-SCOPE item is a separate, user-gated decision.


Design intent + build plan. Additive only. No federation, no on-device training, no prod apply, no push — all gated. “Membrane”/“Osmosis” are placeholder names.

Ask Anything