|
| 1 | +# Foundry Consumer Parity — Shared Ontology + Contracts for SMB + MedCare |
| 2 | + |
| 3 | +> **Status:** Active |
| 4 | +> **Author:** main thread (Opus 4.7 1M), session 2026-04-26 |
| 5 | +> **Scope:** Map the Foundry parity surface shared between smb-office-rs |
| 6 | +> and medcare-rs; resolve callcenter UNKNOWNs; document the DataFusion/SQL |
| 7 | +> groundtruth pattern both consumers need. |
| 8 | +> **Cross-ref:** `smb-office-rs/docs/foundry-parity-checklist.md` (45 LF chunks); |
| 9 | +> `medcare-rs` session architecture review (callcenter-as-owner proposal); |
| 10 | +> `lance-graph/plans/q2-foundry-integration-v1.md`; `lance-graph/plans/lf-integration-mapping-v1.md` |
| 11 | +
|
| 12 | +--- |
| 13 | + |
| 14 | +## §1 Callcenter UNKNOWN Resolutions |
| 15 | + |
| 16 | +Resolved by medcare-rs architecture review (2026-04-26). Both SMB and |
| 17 | +medcare-rs confirm the same answers — these are consumer-validated. |
| 18 | + |
| 19 | +| UNKNOWN | Question | Resolution | Consumer evidence | |
| 20 | +|---|---|---|---| |
| 21 | +| **UNKNOWN-2** | Phoenix wire-protocol vs direct Rust API? | **Both.** Phoenix WS for realtime push (SMB: Wartezimmer; medcare: waiting-room/lab-result push). Direct Rust API for bespoke routes (auth, DMS upload, views). | Both consumers | |
| 22 | +| **UNKNOWN-3** | Does any consumer need pgwire? | **No.** All clients are HTTP/WS. Neither SMB nor medcare-rs runs a PostgreSQL wire client. PostgREST shape is the target, not pgwire. | Both consumers | |
| 23 | +| **UNKNOWN-4** | Right `actor_id` type? | **String** (JWT `sub` claim). Custom claims via `ActorContext::custom()` for domain-specific fields: SMB needs `praxis_id`, medcare needs `praxis_id` + `role`. | Both consumers | |
| 24 | +| **UNKNOWN-5** | Lance dataset path convention? | **Single root URI** env var (`LANCE_URI=file:///var/lib/{app}/lance/`), subpaths per dataset. SMB: `MEDCARE__LANCE_PATH`-compatible; medcare: same pattern. | Both consumers | |
| 25 | +| **§8 PostgREST** | Confirm PostgREST compat needed? | **Yes.** SMB clinic UI uses REST URL shape. medcare ~87 of 115 routes collapse to PostgREST auto-routes. This is the highest-leverage callcenter deliverable. | Both consumers | |
| 26 | + |
| 27 | +### Action: DM-8 (PostgRestHandler) is UNBLOCKED |
| 28 | + |
| 29 | +The `§8 stop-point` in `callcenter-membrane-v1.md` asked: "confirm |
| 30 | +PostgREST compat is needed before building." Two consumers confirm. |
| 31 | +DM-8 can proceed. |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## §2 Shared Foundry Surface — What Both Consumers Need |
| 36 | + |
| 37 | +Both SMB and medcare-rs need the SAME Foundry-equivalent contract surface. |
| 38 | +Neither should build its own; both consume from `lance-graph-contract`. |
| 39 | + |
| 40 | +### Already shipped (Tier 0 — consume directly) |
| 41 | + |
| 42 | +| Contract module | SMB use | MedCare use | |
| 43 | +|---|---|---| |
| 44 | +| `ontology` (Ontology, Schema, LinkSpec, ActionSpec) | Customer/Invoice/TaxDecl ontology | Patient/Diagnosis/Lab/Vital ontology | |
| 45 | +| `property` (PropertyKind, PropertySpec, Marking) | GDPR marking per field | GDPR + clinical marking per field | |
| 46 | +| `repository` (EntityStore, EntityWriter) | MongoConnector + LanceConnector | MySQL-as-oracle + Lance-as-SoR | |
| 47 | +| `external_membrane` (ExternalRole, ExternalEventKind) | SMB roles (operator, debtor) | MedCare roles (doctor, nurse, admin) | |
| 48 | +| `auth` (ActorContext, JwtMiddleware) | praxis_id + role claims | praxis_id + role + ward claims | |
| 49 | +| `rls` (RlsRewriter) | tenant_id per Steuerberater | tenant_id per Praxis | |
| 50 | +| `cognitive_shader` (BindSpace SoA) | extends with SMB entity columns | extends with clinical entity columns | |
| 51 | +| `a2a_blackboard` (multi-expert composition) | dunning/tax/doc-lookup experts | triage/prescription/lab-trend experts | |
| 52 | +| `distance` (Distance trait + FisherZ) | similarity for customer dedup | similarity for diagnosis suggestion | |
| 53 | +| `graph_render` (visual render traits) | q2 Gotham cockpit | q2 clinical dashboard | |
| 54 | + |
| 55 | +### Needed but not shipped (Tier 1+2 — both consumers request) |
| 56 | + |
| 57 | +| LF-id | What | SMB need | MedCare need | Priority | |
| 58 | +|---|---|---|---|---| |
| 59 | +| **DM-8** | PostgRestHandler | 50+ routes collapse | 87+ routes collapse | **P-0** (highest leverage) | |
| 60 | +| **LF-12** | Pipeline DAG | ingestion orchestration | MySQL→Lance sync orchestration | **P-0** | |
| 61 | +| **LF-31** | scan_as_of (time travel) | audit trail queries | clinical history queries | **P-1** | |
| 62 | +| **LF-20** | FunctionSpec | German tax-rule transforms | clinical rule transforms | P-1 | |
| 63 | +| **LF-23** | NotificationSpec | dunning event triggers | lab-result alert triggers | P-1 | |
| 64 | +| **LF-40** | Full-text search | customer/document search | patient/diagnosis search | P-1 | |
| 65 | +| **LF-41** | Faceted aggregation | filter+facet on invoices | filter+facet on lab values | P-1 | |
| 66 | +| **LF-50** | ModelRegistry | tax classifier model | triage classifier model | P-2 | |
| 67 | +| **LF-52** | LlmProvider | xAI/OpenAI for reasoning | xAI/OpenAI for diagnosis support | P-2 | |
| 68 | +| **LF-60** | Approval workflow | Mahnung approval gates | prescription approval gates | P-2 | |
| 69 | +| **LF-61** | NARS decision capture | user corrections on tax class | doctor corrections on diagnosis | P-2 | |
| 70 | +| **LF-90** | Audit log | SOC2/GDPR audit trail | clinical audit trail | **P-0** | |
| 71 | +| **LF-91** | SLA/health tracking | pipeline freshness | data quality monitoring | P-2 | |
| 72 | +| **LF-92** | Multi-tenant isolation | per-Steuerberater isolation | per-Praxis isolation | P-1 | |
| 73 | + |
| 74 | +--- |
| 75 | + |
| 76 | +## §3 The DataFusion/SQL Groundtruth Pattern |
| 77 | + |
| 78 | +Both consumers use the SAME architecture: |
| 79 | + |
| 80 | +``` |
| 81 | + lance-graph-callcenter (PostgREST + Phoenix + RLS) |
| 82 | + │ |
| 83 | + │ ExternalMembrane trait |
| 84 | + │ |
| 85 | + ┌──────────┴──────────┐ |
| 86 | + │ │ |
| 87 | + SMB membrane MedCare membrane |
| 88 | + (schema decls + (schema decls + |
| 89 | + RLS rules + RLS rules + |
| 90 | + bespoke routes) bespoke routes) |
| 91 | + │ │ |
| 92 | + ▼ ▼ |
| 93 | + Lance datasets Lance datasets |
| 94 | + (system of record) (system of record) |
| 95 | + │ │ |
| 96 | + │ reconciler │ reconciler |
| 97 | + ▼ ▼ |
| 98 | + MySQL oracle MySQL oracle |
| 99 | + (groundtruth, (groundtruth, |
| 100 | + never retired) never retired) |
| 101 | +``` |
| 102 | + |
| 103 | +**DataFusion IS the query surface for both sides:** |
| 104 | +- Incoming REST queries → PostgREST translates to DataFusion SQL |
| 105 | +- DataFusion plans execute against Lance datasets (via lance-datafusion) |
| 106 | +- RLS rewriter injects tenant/actor predicates into every plan |
| 107 | +- VSA UDFs (vsa_distance, vsa_similarity) available in WHERE/ORDER BY |
| 108 | +- MySQL serves as the parity oracle — reconciler compares SQL results |
| 109 | + from both systems to verify Lance produces identical answers |
| 110 | + |
| 111 | +**lance-datafusion (from lancedb 0.27.2) is required:** |
| 112 | +- Registers Lance datasets as DataFusion `TableProvider` |
| 113 | +- SQL queries over patient/customer records, joins across entity types |
| 114 | +- Predicate pushdown into Lance's native filter engine |
| 115 | +- Without it, Lance is just a vector store, not a relational store |
| 116 | + |
| 117 | +--- |
| 118 | + |
| 119 | +## §4 Ontology Unification — One Contract, Two Domains |
| 120 | + |
| 121 | +The contract defines the SHAPE; each consumer fills in domain-specific content: |
| 122 | + |
| 123 | +```rust |
| 124 | +// lance-graph-contract::ontology — shared shape (zero-dep) |
| 125 | +pub struct Ontology { |
| 126 | + pub schemas: Vec<Schema>, // SMB: Customer, Invoice, ... |
| 127 | + // MedCare: Patient, Diagnosis, ... |
| 128 | + pub links: Vec<LinkSpec>, // SMB: Customer→Invoice |
| 129 | + // MedCare: Patient→Diagnosis |
| 130 | + pub actions: Vec<ActionSpec>, // SMB: SendMahnung, ClassifyTax |
| 131 | + // MedCare: OrderLab, Prescribe |
| 132 | +} |
| 133 | + |
| 134 | +// The AGI surface is IDENTICAL for both: |
| 135 | +// - FreeEnergy::compose → Resolution per cycle |
| 136 | +// - CausalEdge64 emitted per strong hit |
| 137 | +// - OntologyDelta (Column E) per novel pattern |
| 138 | +// - AwarenessColumn (Column F) per word |
| 139 | +// - EntityTypeId (Column H) per row |
| 140 | +// - ModelRef (Column G) per ONNX binding |
| 141 | +// |
| 142 | +// The ONLY difference is which Schema instances are registered |
| 143 | +// and which RLS rules are configured. The cognitive stack doesn't |
| 144 | +// care whether it's thinking about a Mahnung or a Prescription — |
| 145 | +// it processes fingerprints, emits edges, learns ontology. |
| 146 | +``` |
| 147 | + |
| 148 | +**"Foundry outside, AGI inside" means:** |
| 149 | +- Outside: Ontology + Schema + LinkSpec + ActionSpec = Foundry's typed object model |
| 150 | +- Inside: BindSpace SoA + FreeEnergy + CausalEdge64 + NARS = AGI's cognitive substrate |
| 151 | +- The callcenter membrane translates between them |
| 152 | +- Both consumers see the SAME Foundry surface; neither sees the AGI internals |
| 153 | +- The AGI learns from both domains simultaneously (if running in the same BindSpace) |
| 154 | + |
| 155 | +--- |
| 156 | + |
| 157 | +## §5 Build Priority (Shared Leverage) |
| 158 | + |
| 159 | +Ordered by "serves both consumers": |
| 160 | + |
| 161 | +1. **DM-8 PostgRestHandler** — 87+ medcare routes + 50+ SMB routes collapse. |
| 162 | + Depends on: UNKNOWN-3 resolved (no pgwire), UNKNOWN-5 resolved (LANCE_URI). |
| 163 | + The single highest-leverage callcenter deliverable. |
| 164 | + |
| 165 | +2. **LF-90 AuditLog** — both consumers need SOC2/GDPR/clinical audit. |
| 166 | + Already drafted (Tier 0 has `AuditEntry` shape). Wire it. |
| 167 | + |
| 168 | +3. **LF-12 Pipeline DAG** — both consumers need orchestrated ingestion. |
| 169 | + SMB: MongoDB→Lance sync. MedCare: MySQL→Lance sync. Same `Pipeline` trait. |
| 170 | + |
| 171 | +4. **LF-31 scan_as_of** — both consumers need time-travel queries. |
| 172 | + lancedb 0.27.2 `Table::checkout(version)` maps directly. |
| 173 | + |
| 174 | +5. **LF-92 Multi-tenant** — both consumers isolate by `praxis_id`. |
| 175 | + The RLS rewriter (already shipped) does this per-query; LF-92 adds |
| 176 | + project-level structural isolation. |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +## §6 What This Plan Does NOT Cover |
| 181 | + |
| 182 | +- **Q2 UI chunks** — tracked in `q2-foundry-integration-v1.md` |
| 183 | +- **SMB-specific domain logic** — tracked in `smb-office-rs/docs/foundry-parity-checklist.md` |
| 184 | +- **MedCare-specific domain logic** — tracked in `medcare-rs` session |
| 185 | +- **ndarray SIMD work** — separate; consumed as-is |
| 186 | +- **Per-consumer bespoke routes** — auth, DMS, migration, views stay hand-rolled |
0 commit comments