EmberKeep โ€” Full-Stack Architecture with EmberGraph

EmberKeep โ€” Full-Stack Architecture with EmberGraph

Companion to PR #470 canonical deck. Renders the full top-to-bottom stack with EmberGraph slotted into its actual position. Built 2026-06-24 to give Lydo visual clarity before committing to the multi-quarter build.

Color convention (matches PR #470):


Section 1 โ€” What problem are we solving?

EmberKeep mediates third-party access to records the principal owns. Three things make this unusual:

  1. Principal can be in one of 3 lifecycle states (alive ยท incapacitated ยท deceased) and what each role sees depends on that state
  2. 15 distinct role types, some dormant until activated by lifecycle change
  3. Every access decision must be auditable (legal + medical compliance)

The standard "Clerk + RLS + app code" pattern most SaaS products use doesn't fit because the matrix of (record ร— role ร— state) decisions is too large to encode inline at every consumer.

So we built a matrix. We have it. The question isn't "should we build EmberGraph" โ€” it's "should we let the 3 parallel engines that drifted apart stay drifted, or converge them."


Section 2 โ€” Database vs EmberGraph (the cleanest distinction)

Question Database (Supabase) EmberGraph
What does it own? The bytes The decision
What's its primitive? Rows, columns, JSONB blobs Access decisions + audit entries
Example question it answers "Give me row 12345" "Should viewer Anne see row 12345 right now, and in what form?"
Stays the same across products? Yes (Postgres is Postgres) Yes (matrix is matrix)
What goes in/out? SQL โ†’ rows (viewer, record, state) โ†’ projected payload + audit log entry
What it does NOT know What "Cat 1" means; what "incapacitated" means; what a "role" is Where the bytes physically live; how indexing works

The shortest answer: the database is the filing cabinet. EmberGraph is the librarian who knows which documents each visitor is allowed to see, in what state the owner is in, and whether to hand over a full document, summary, or refuse.


Section 3 โ€” The full stack, top to bottom

                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                       โ”‚  WHO USES THE APP            โ”‚
                       โ”‚  Member ยท Advisor ยท Heir ยท   โ”‚
                       โ”‚  AI agent ยท Attorney         โ”‚
                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                      โ”‚
                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                       โ”‚              โ”‚              โ”‚
                       โ–ผ              โ–ผ              โ–ผ
                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                  โ”‚ CLERK  โ”‚   โ”‚  STRIPE  โ”‚   โ”‚ RESEND โ”‚   (sub-processors)
                  โ”‚ (auth) โ”‚   โ”‚ (billing)โ”‚   โ”‚ (email)โ”‚
                  โ”‚ SOC 2  โ”‚   โ”‚ PCI-DSS  โ”‚   โ”‚        โ”‚
                  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
                       โ”‚ identity
                       โ–ผ
                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                  โ”‚  APPLICATION LAYER                      โ”‚
                  โ”‚  Next.js 14 (App Router) on Vercel      โ”‚
                  โ”‚                                         โ”‚
                  โ”‚  โ€ข UI surfaces                          โ”‚
                  โ”‚    Letters ยท Family View ยท Emergency ยท  โ”‚
                  โ”‚    Final Wishes ยท Settlement Packet ยท   โ”‚
                  โ”‚    Settings / Who has access            โ”‚
                  โ”‚  โ€ข API routes                           โ”‚
                  โ”‚  โ€ข Business logic                       โ”‚
                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                     โ”‚
                "can this viewer see this record? in what form?"
                                     โ”‚
                                     โ–ผ
       โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
       โ•‘                                                           โ•‘
       โ•‘   โ˜…  EMBERGRAPH  โ˜…                                        โ•‘
       โ•‘   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                  โ•‘
       โ•‘   the access decision substrate                           โ•‘
       โ•‘                                                           โ•‘
       โ•‘   INPUTS                                                  โ•‘
       โ•‘     viewer identity   โ†  from Clerk                       โ•‘
       โ•‘     record requested  โ†  application                      โ•‘
       โ•‘     principal state   โ†  alive ยท incap ยท deceased         โ•‘
       โ•‘     role + activation โ†  three-stage chain                โ•‘
       โ•‘                                                           โ•‘
       โ•‘   LOGIC                                                   โ•‘
       โ•‘     1.  consult 360-cell visibility matrix                โ•‘
       โ•‘         (classification ร— role ร— state)                   โ•‘
       โ•‘     2.  apply sub-filters                                 โ•‘
       โ•‘         (release date ยท role scope ยท activation gate)     โ•‘
       โ•‘     3.  produce projection                                โ•‘
       โ•‘         (FULL ยท SUMMARY ยท REDACTED ยท DENY)                โ•‘
       โ•‘                                                           โ•‘
       โ•‘   OUTPUTS                                                 โ•‘
       โ•‘     โ–ธ  projected payload  โ†’  caller                       โ•‘
       โ•‘     โ–ธ  immutable audit entry  โ†’  hash-chained log         โ•‘
       โ•‘                                                           โ•‘
       โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•คโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
                            โ”‚
              "fetch these rows / these specific fields"
                            โ”‚
                            โ–ผ
       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
       โ”‚   DATABASE LAYER                                          โ”‚
       โ”‚   Supabase Postgres + Storage                             โ”‚
       โ”‚                                                           โ”‚
       โ”‚   โ€ข Records (artifacts, vault_sections, role_activations) โ”‚
       โ”‚   โ€ข JSONB blobs                                           โ”‚
       โ”‚   โ€ข File pointers + storage buckets (signed URLs)         โ”‚
       โ”‚   โ€ข Coarse RLS = deny-all safety net (the FLOOR;          โ”‚
       โ”‚     EmberGraph is the ceiling)                            โ”‚
       โ”‚   โ€ข AES-256 encrypted at rest                             โ”‚
       โ”‚   โ€ข Hash-chained audit log table                          โ”‚
       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                               โ”‚
                  (for the most sensitive vault content)
                               โ–ผ
       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
       โ”‚   CLIENT-SIDE SDB ENCRYPTION                              โ”‚
       โ”‚                                                           โ”‚
       โ”‚   PBKDF2 โ†’ AES-GCM 256 ยท PIN-derived                     โ”‚
       โ”‚   Keys never leave browser. EmberKeep cannot read SDB.    โ”‚
       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜


                    โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

                       SUPPORTING SUBSTRATE

   Anthropic + Gemini  ยท  GCS (backup target)  ยท  Vercel edge

                              โ”‚
                              โ”‚ TODAY: AI calls bypass EmberGraph
                              โ”‚        (slide-7 known gap)
                              โ”‚
                              โ–ผ
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚   AI REDACTION LAYER  (new โ€” gap fix)โ”‚
              โ”‚   lib/ai/redact.ts                  โ”‚
              โ”‚                                     โ”‚
              โ”‚   Every AI call routes through      โ”‚
              โ”‚   EmberGraph FIRST. Model sees only โ”‚
              โ”‚   what the caller could have seen.  โ”‚
              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Section 4 โ€” Today vs Target

Today (3 engines)

   Letters                6 role-display          vault_sections
                          surfaces                (every member read)
       โ”‚                       โ”‚                       โ”‚
       โ–ผ                       โ–ผ                       โ–ผ
   projectArtifact()    contact-roles.ts        vault_share_grants
   (1 surface uses      (6 surfaces, bypass     (coarse RLS, no
    matrix)              the matrix)             per-classification)
       โ”‚                       โ”‚                       โ”‚
       โ–ผ                       โ–ผ                       โ–ผ
   ENGINE #1              ENGINE #2               ENGINE #3
   matrix-driven          raw role state          per-section RLS

Honest: the canonical deck says "one engine." Reality is three. The matrix is correct logic that 6 of 7 surfaces don't consult.

Target (1 engine, multiple shapers)

   Letters ยท 6 role-display surfaces ยท vault_sections ยท EK 4.0 RAG
                              โ”‚
                              โ–ผ
                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                   โ”‚  decideAccess()      โ”‚
                   โ”‚  (the SINGLE PDP)    โ”‚
                   โ”‚  consults matrix     โ”‚
                   โ”‚  applies sub-filters โ”‚
                   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ–ผ               โ–ผ               โ–ผ
        shapeRecord()  decideRoleVisibility()  shapeRagContext()
        (Letters,      (6 role-display          (future EK 4.0)
         vault         surfaces)
         sections)
              โ”‚               โ”‚               โ”‚
              โ–ผ               โ–ผ               โ–ผ
       ALL audited through the hash-chained audit log

The reframing the external review locked: one decision authority, multiple enforcement paths. Not one function for everything.


Section 5 โ€” AI gating: closing the slide-7 gap

   TODAY (broken)                       TARGET (gap closed)
   โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                     โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

   Application                          Application
       โ”‚                                    โ”‚
       โ–ผ                                    โ–ผ
   Build prompt                         Build prompt
       โ”‚                                    โ”‚
       โ”‚  unredacted vault content          โ–ผ
       โ–ผ                                EmberGraph
                                            โ”‚
                                            โ–ผ
                                        decideAccess(AI_agent, record)
                                            โ”‚
                                            โ–ผ
                                        Redacted payload
                                            โ”‚
                                            โ–ผ
   Anthropic / Gemini โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  Anthropic / Gemini
       โ”‚                                    โ”‚
       โ–ผ                                    โ–ผ
   Response                             Response

   ๐Ÿ”ด Cat-1, Cat-2, Cat-3              ๐ŸŸข Model receives only what
      content shipped to model            the caller could have seen.
      regardless of viewer rights         Audit entry recorded per call.

This is the load-bearing reason EmberGraph exists at the chokepoint. Without it, every AI feature is a manual access-control surface.


Section 6 โ€” Future-proof slots

What plugs into the stack later without a redesign:

Future product Plugs in where Why it works
EK 4.0 โ€” "EmberKeep Knows Me" (AI-native vault) shapeRagContext() โ€” new shaper, same decideAccess kernel RAG retrieval is gated by the matrix; no special-case logic
Attorney B2B (Eric Gold's firm scenario) New role type added to the matrix; existing decideAccess consults it Adding roles is a config change, not an architectural change
Wealth advisor channel (BofA / Forward Inheritance) New role + new release_condition (e.g. client_signed_engagement) Sub-filter, not new code path
International / jurisdiction New axis on the matrix (jurisdiction ร— classification ร— role ร— state) Synthesis OPEN item; needs orthogonal modeling, not retrofit
Multi-principal / joint records Schema change on records; matrix consults principal_set instead of principal_id Bounded change inside the matrix layer
Compliance reporting (audit replay) Already wired via hash-chained audit log + policy versioning (synthesis OPEN) Audit log is the substrate

The chokepoint pays for itself the second time you add a new surface.


Section 7 โ€” Honest gaps (state of the substrate, 2026-06-24)

Layer What's wired What's the gap Severity
Auth (Clerk) โœ… Live, SOC 2 inherited None โ€”
Database (Supabase) โœ… Live, 59 migrations, RLS on 39 of 60 tables ๐Ÿ”ด 21 of 60 tables lack RLS (slide 3) P0 before alpha
EmberGraph matrix โœ… Wired in lib/access/visibility-matrix.ts ๐ŸŸก Only 1 of 7 surfaces consults it P0 (parallel-engine drift)
AI gating ๐Ÿ”ด NOT WIRED AI calls send unredacted vault content (slide 7) P0 before alpha
Audit log โœ… Hash-chained, RLS deny-all UPDATE/DELETE ๐ŸŸก Co-transactional only on Letters surface P1
Client-side SDB encryption โœ… Live, PBKDF2 โ†’ AES-GCM 256 None โ€”
Three-stage role activation chain โœ… Schema invariants enforced ๐ŸŸก 0 candidates in active state (no member-side UI) P0 (EMB-420)
Dev/prod separation ๐Ÿ”ด NOT WIRED โ€” single Supabase project Local dev hits production DB P0 before alpha
Observability / error tracking ๐Ÿ”ด NOT WIRED โ€” PostHog stubbed, no Sentry Production failures invisible P1
Backup + DR ๐ŸŸข Nightly to GCS; ๐Ÿ”ด no documented restore RTO/RPO unknown P1
Threat model (written) ๐Ÿ”ด NOT WRITTEN No artifact for advisor review P1
security.txt ๐Ÿ”ด NOT PUBLISHED RFC 9116 noncompliance P2

Pen test scheduled (locked 2026-05-22) before SOC 2 pursuit. Pen test scope must include the new chokepoint.


Section 8 โ€” Future-proof verdict per layer

Layer Future-proof? Confidence Why
Database (Supabase Postgres) โœ… YES HIGH Postgres scales; vendor not locked-in
Hosting (Vercel) โœ… YES HIGH Edge runtime; serverless migration is possible
Auth (Clerk) โœ… YES HIGH Standard OIDC; replaceable; SOC 2 inherited
EmberGraph matrix โœ… YES HIGH Patent-track substrate; future-proofs against EK 4.0 + multi-product
Audit log (hash-chained) โœ… YES MEDIUM Substrate is right; external anchoring needed at scale (synthesis)
Client-side SDB encryption โœ… YES HIGH Already E2E for the sensitive layer
AI gating โŒ NOT YET โ€” The load-bearing close; closes slide-7 gap; enables EK 4.0
Dev/prod separation โŒ NOT YET โ€” Substrate gap; pre-revenue is cheapest moment
Observability stack โŒ NOT YET โ€” Required for SLO tracking

Verdict: the stack is fundamentally sound. The gaps are specific, named, and fixable. The chokepoint convergence + AI gating + dev/prod separation are the three load-bearing closes.


Section 9 โ€” External review panel (5 LLMs)

The architectural commit was reviewed by 5 independent LLM reviewers (ChatGPT, Perplexity, Gemini, Grok, Claude CoWork) against a sanitized design doc. Full synthesis at embergraph-external-review-synthesis-2026-06-23.md.

Per-question panel positions

# Design question ChatGPT Perplexity Gemini Grok CoWork Convergence
1 Single chokepoint vs peer engines PDP/PEP split One policy authority, not one shape Logical SoT yes, physical no Shared kernel + adapters Right for decision, wrong as function 5/5 PUSHBACK
2 Wrap (A) vs merge (B) for role-display Shared kernel + role-specific evaluators Reject B as written Dedicated decideRoleVisibility A superior; dedicated primitive B's doc-stated definition IS the category error 5/5 AGAINST B-as-written
3 Per-row / per-field / migrate (vault_sections) Per-field bridge, migrate long-term Per-field transitional Migrate NOW Migrate NOW (>6-9mo threshold) False dichotomy โ€” per-section is a VIEW over unified store SPLIT โ€” CoWork reframes
4 Classification โŠฅ semantic facets orthogonal Load-bearing, day 1 Load-bearing Load-bearing, day 1 Load-bearing, day 1 Load-bearing as constraint, you're already violating it 5/5 STRONG
5 Co-transactional audit invariant Tier sync/aggregate Co-trans for security-critical only Outbox pattern; drop advisory lock Strict; correct for trust-critical Split the artifact (decision sync, chain spine async + anchored) 4-DISTINCT POSITIONS
6 Sub-filter reification (all code?) Hybrid (procedural + declarative) Hybrid; declarative for stable Fully declarative metadata Hybrid, declarative-first Separate binding (data) from evaluation (code) 5/5 AGAINST PURE CODE
7 Three-state principal lifecycle Decompose to 3 axes Top bucket + state machine Add Disputed / Reversible / Interregnum Richer state machine Capacity as a claim, not a property; who authorizes? 5/5 AGAINST 3-STATE
8 Dev/prod sequencing Upstream Upstream "Stop everything, fix environments" Upstream of rebuild Upstream, barely a question 5/5 STRONG
9 What's missing 8 items (versioning, temporal, break-glass, denial UX, caching, governance, regulatory drift) Policy drift across representations; metadata escalation Bootstrap paradox; break-glass; cryptographic boundary Multi-principal; performance; cross-jurisdictional State-transition authority; OIL = engine #2 reborn; right-to-erasure conflict; legal hold NOVEL findings

Confidence scorecard (22 design dimensions)

Confidence band # dimensions Status
HIGH (5/5 panel converged + structural critique) 10 As locked as they can be without writing code
MEDIUM (clear direction, implementation choices remain) 6 Refines through implementation
LOW (novel concerns surfaced but not yet designed) 7 Each is a design pass we still owe

Honest conclusion from the panel

We have the best directional design we can produce today, with 7 named gaps we haven't designed for yet. The HIGH band is decisional; the MEDIUM band is implementable; the LOW band is research-pending.


Section 10 โ€” Final recommendation: MVP + phased buildout

The MVP (ship before Warm Lead Beta ~July 1)

Phase Item Duration Why now
0 EMB-296 โ€” Dev/prod environment separation ~14-15 hrs over 4-5 days 5/5 panel locked upstream; pre-revenue cheapest moment
1a AI redaction layer (lib/ai/redact.ts) 1-2 days Closes slide-7 honest gap; load-bearing for advisor trust
1b 21 RLS table closures ~1 week Closes slide-3 honest gap; required before alpha
2 EMB-420 minimum โ€” member-side role-creation UI ~1 week Without it, 0 active roles forever; expanded scope is V2
3 Domino #2 Strategy C โ€” shared decideAccess + dedicated decideRoleVisibility ~2-3 weeks Eliminates the 3-engine drift; 5/5 panel; the actual chokepoint convergence
4 Observability stack โ€” Sentry + structured logger + cron alerting ~1 week Pre-revenue blind spots become P0 in prod

Total MVP: ~5-6 weeks of focused build. Closes every slide-3 and slide-7 honest gap. Establishes the single decision authority. Ships safely before beta.

Deferred to post-MVP (after first paying customer)

Phase Item Trigger that forces the work
5 Domino #3 โ€” vault_sections per-field classification First customer who asks "why does my attorney see HIPAA notes"
6 Lifecycle expansion to capacity-as-claim model First contested incapacity event
7 Sub-filter binding/evaluation engine 8+ sub-filters in the catalog
8 Owner Intent Ledger moved inside matrix decision flow OIL builds proven downstream
9 State-transition authorization full model + break-glass First medical-emergency surface or 2nd incapacity case
10 Audit chain external anchoring (transparency-log style) Pen test finding OR pre-SOC-2 audit prep
11 Multi-region audit replication EU customer OR uptime SLA upgrade past 99.9%
12 Jurisdiction modeling (4th matrix axis) International customer OR multi-state conflict

Phased buildout โ€” full EmberGraph

   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 0  โ€” Substrate ready (EMB-296)                   โ”‚  โ—„โ”€โ”€ BLOCK
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                   โ”‚       starts
   โ”‚  Dev/prod separation ยท staging gate ยท per-env keys      โ”‚       here
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 1  โ€” Honest-gap closure (in parallel)            โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€               โ”‚
   โ”‚  1a ยท AI redaction layer  (slide-7 fix)                 โ”‚
   โ”‚  1b ยท 21 RLS closures     (slide-3 fix)                 โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 2  โ€” Bootstrap (EMB-420 minimum)                 โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                   โ”‚
   โ”‚  Owner UI to create role candidates                     โ”‚
   โ”‚  Target-side accept flow (Stage 2 fresh re-auth)        โ”‚
   โ”‚  โ–ธ unblocks every downstream domino                     โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 3  โ€” Chokepoint convergence (Domino #2 / C)      โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€             โ”‚
   โ”‚  Shared `decideAccess` kernel                           โ”‚
   โ”‚  Dedicated `decideRoleVisibility` shaper                โ”‚
   โ”‚  6 role-display surfaces refactor                       โ”‚
   โ”‚  CI invariant: no direct role_activations reads         โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 4  โ€” Production observability                    โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                         โ”‚
   โ”‚  Sentry ยท structured logging ยท cron alerting ยท APM      โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
                โ”ƒ โ” โ” โ”  alpha ready ยท beta launch โ” โ” โ” โ”ƒ
                     โ”‚
                     โ–ผ   (driven by first-customer signal)
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 5  โ€” vault_sections classification (Domino #3)   โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€          โ”‚
   โ”‚  Per-field classification map ยท unclassified default    โ”‚
   โ”‚  Mark + Eric legal review ยท codegen pipeline ship       โ”‚
   โ”‚  Strategy 4: unified records + section views            โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 6  โ€” Lifecycle + authorization                   โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                         โ”‚
   โ”‚  Capacity-as-claim model                                โ”‚
   โ”‚  State-transition authorization framework               โ”‚
   โ”‚  Break-glass / emergency-override design                โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 7  โ€” Sub-filter engine + Owner Intent Ledger     โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€         โ”‚
   โ”‚  Code-eval + data-binding split (CoWork sharpening)     โ”‚
   โ”‚  OIL moves inside matrix decision flow                  โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  PHASE 8  โ€” Scale infrastructure                        โ”‚
   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                             โ”‚
   โ”‚  Read replicas ยท synthetic monitoring ยท SLA tracking    โ”‚
   โ”‚  Audit chain external anchoring                         โ”‚
   โ”‚  Multi-region replication (when EU customer signs)      โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The MVP-vs-marathon distinction

The MVP is what we ship before the Warm Lead Beta so we can sell to wealth advisors with a straight face. The marathon is what makes EmberKeep the patent-track substrate that future products (EK 4.0, attorney B2B, advisor channel) plug into.

Build the MVP next. Use it for 60-90 days. Let real customer questions drive the marathon's sequencing.


Generated 2026-06-24 by Claude Code. Visual artifact for design clarity. Companion HTML at full-stack-with-embergraph.html.