Common Platform · Architecture · v3.2 · Complete Edition

Projexlight Common Services, Agents, HDK & AIM

The single canonical architecture: a shared horizontal platform — services, agents, contracts, design system, native SDK ecosystem (HDK), and the AIM (Application & Identity Management) foundation — consumed by every vertical under projex_verticals/. Builds once. Multi-tenant. Multi-vertical. Multi-app. Multi-surface (web · mobile · kiosk). Petabyte-scale via pool-based horizontal scaling (no sharding). Identity expressed as a six-layer stack — Master Person · App Identity · Tenant Membership · Persona · Encounter · Relationship — encrypted end-to-end and governed by a three-evaluator access mesh.

Repo · projex_verticals/projex_common/
Workspace · pnpm + turbo
Contracts · @projexlight/contracts
Mobile stack · React Native + Kotlin / Swift native
Doc set · this file · SDK-Build-Plan-v3.1.html · AIM-Identity-Model-v3.1.html
v3.1 charter. v3.1 is the merged complete edition — everything from v2 (HDK, the 29 Common services, 12 horizontal agents, three-pillar identity foundation, governance) integrated with v3 (pool-based scaling, six-layer identity stack, encounter and relationship primitives, ReBAC access mesh, encrypted identity end-to-end). Use this document as the single canonical platform reference. Earlier docs (../Architecture.html v1, ../Architecture-v2.html v2, ../v3/Architecture-v3.html v3) are retained as historical references; this file supersedes them in scope. New material introduced in v3 is marked v3; carried-forward v2 material is marked v2 where the distinction matters.
v3.2 delta. v3.2 reconciles this architecture with the platform-layer design discussion (gaps/Analyze1.md) and its architectural critique (gaps/Analyze2.md), via the capability mapping in ../insignia/ProjexCloud-vs-Insignia-Reality-Report-v2.html. It adds §11A · Platform Control Planes & Obligation-Based Authorization and principles P16–P18: the eight-control-plane mapping, obligation-bearing authorization (decisions return mask/filter/audit/TTL, not just allow/deny), the minted Platform Principal Token (one signed internal identity, never trust forwarded headers), consent as a gating decision input, and a fail-closed + break-glass doctrine. It also records, explicitly, what is deferred by design (SPIFFE/mTLS service mesh, NATS/JetStream/Temporal, probabilistic MDM) and why. §11A.10 records the provisional Healthcare (multi-source) resolution that promotes EMPI / consent-gating / obligations to Required, and §11A.11 is the coverage map tying every analysis gap to its status and Projexlight implementation backlog (P10 · E1–E9, 53 tasks). Status note: v3.2 closes these gaps at the design level and schedules them as work — "designed & backlogged" is not "shipped." New v3.2 material is marked v3.2.

1 · Overview

Every vertical we ship — Shantam (Seva), Kiana (Realty), Music/Video, BidWork, LeadPulse, FieldOps, OneEstate, future Wellness and Healthcare — reuses 80–90% of the same plumbing: identity, payments, notifications, content, search, analytics, audit, AI gateway, geospatial, dispatch, evidence capture, and a dozen platform agents. Re-implementing this per vertical is the single largest source of waste and the single largest source of drift.

This document describes that shared layer in its v3.1 (complete) form: what lives in projex_common/, the contracts that make it consumable, the HDK native SDKs that field-grade apps depend on, the AIM pool model that lets the platform grow from 1k to 1M+ tenants and petabyte-scale data, the six-layer identity stack that handles every cross-app / cross-tenant scenario the team has identified, and the discipline that keeps it shared rather than copy-pasted.

Owns
29 services · 12 agents · 14 shared packages · 10 HDK modules · AIM pool layer
Identity, Tenant, Profile, Payment, Notification, CRM, SR, Content, Course, Event, Campaign, Social, Analytics, Search, Media, Workflow, Audit, AI Gateway, Knowledge/RAG, Conversation, Recommendation, Feature Flags, Map/Geo, Storm, Dispatch, Assignment, Lead Scoring, Field-Ops Evidence, Diagnostic-Telemetry — plus the new Pool Router, Persona, Engagement, and ReBAC services / SDKs introduced in v3.
Does not own
Vertical domain logic
Donation/80G/Acharya stay in Seva. Property/Visit/Document stay in Realty. Catalog/Rights stay in Music. Bid/Auction stay in BidWork. Storm-damage estimation & contractor settlement stay in FieldOps. Patient charts and clinical decision support stay in Healthcare. Order workflows stay in eCommerce.
Outcome
Build a vertical in weeks, not quarters · scale to 1M+ tenants
A new vertical subscribes to Common modules, embeds the HDK, defines its persona kinds and encounter kinds in @projexlight/contracts, themes the shared design system, and ships. Pool allocation is automatic; encryption and access mesh are inherited.

2 · What's in v3.1 — Quick Map

v3.1 = v2 (complete platform) ∪ v3 (AIM hardening). The table below shows where each capability area lives in this document.

Capability areaOriginWhere in this doc
Three build-time disciplines (one workspace · one contracts · Rule of Three)v2§3 Disciplines
Architecture principles P1–P10 (offline-first, evidence integrity, …)v2§4 Principles
Principles P11–P15 (no sharding, layered identity, encryption-by-default)v3§4 Principles
Client strategy (React Native + React Web)v2§5 Client Strategy
HDK — ten native modules + install orderv2§6 HDK
Identity foundation — three pillars (MDM · ABAC · Consent), scope hierarchy, canonical IDs, MDM patternsv2§7 Identity Foundation
Identity layers (Master Person · App Identity · Tenant Membership · Persona · Encounter · Relationship)v3§7 Identity Foundation
AIM pools (no sharding · admin pool · app pool · evidence pool · pool indexing · capacity targets)v3§8 AIM Pools
Pool routing & registryv3§9 Pool Routing
Multi-level encryption (root · pool · tenant · person · device · org · encounter)v2 + v3§10 Encryption
Access control mesh (ABAC + ReBAC + Encounter Grants)v2 + v3§11 Access Mesh
Tenancy & verticals (Tier S/P/G isolation)v2§12 Tenancy
Workspace layoutv2§13 Workspace
Layered view (channels · HDK · gateway · services · agents · data plane · geo · ingestion · capture)v2§14 Layered View
Worked scenarios (healthcare · eCommerce · OneEstate · cross-domain)v3§15 Scenarios
Services catalogue (29 horizontal services)v2§16 Services
Permissions (three-layer device · role · consent)v2§17 Permissions
Common AI agents (12)v2§18 Agents
Contracts & event envelopev2§19 Contracts
What stays vertical (do not lift)v2§20 Vertical-Specific
Adoption playbook (new vertical)v2§21 Playbook
Pool lifecycle & tenant migrationv3§22 Pool Lifecycle
Governance & ownershipv2 + v3§23 Governance
Cross-vertical roadmapv2 + v3§24 Roadmap

3 · The Three Build-Time Disciplines

Reuse only holds if these three rules are enforced from day one. Every architectural decision in this document derives from one of them.

1

One workspace for Common — not copies in each vertical

All shared services, agents, packages, and native SDKs live in projex_common/ as a single pnpm + turbo workspace. Verticals import packages and call services from here; they never copy code into their own tree. If a vertical needs to "tweak" a shared service, the tweak goes upstream as a config or contract change — not as a fork.

2

One contracts package — @projexlight/contracts

A single source of truth for the event envelope, every event type, every shared API shape, every shared enum, every HDK module interface, the six identity-layer types, and the pool-routing types. Both verticals and SDK modules depend on it. Schemas evolve via semver; breaking changes require a new vN topic and a dual-write window. No service emits an event the contracts package hasn't registered.

3

Rule of Three — promote only after the third vertical needs it

A capability is lifted from a vertical to projex_common/ only after a third vertical needs an equivalent — and only with a generalized contract. This avoids two failure modes: premature lifting (building "common" abstractions from a single example) and accidental fragmentation (letting two verticals each grow their own version, drifting until reconciliation costs more than rebuilding).

Test of conformance. If you can't answer "which package, service, or SDK module in projex_common/ does my code depend on?" in one sentence, you're not following discipline #1. If you're emitting an event whose schema isn't in @projexlight/contracts, you're breaking #2. If you're lifting code into common with only one consumer in mind, you're breaking #3.

3A · Opinionated Constraints Doctrine v3.1

The biggest risk to a platform this size is not technology — it is unbounded flexibility. When everything is configurable, nothing is optimizable; developers route around the platform; the rule-of-three governance gets overwhelmed by edge cases. v3.1 commits to a small set of opinionated, lint-enforced constraints that say "this is the way" — and CI rejects anything else.

Why this section exists. Two architectural reviews (../../Analyze.txt · ../../Analyze2.txt) converged on the same warning: "Platforms become too abstract, too configurable, too difficult to understand. Then developers bypass the platform." The cure is not more flexibility — it's fewer allowed patterns, enforced from week 1.

3A.1 · The constraints

#ConstraintEnforced byCost of violation
OC-1Every SDK method that is billable carries @meter(sku, unit, tier)CI lint over SDK exportsUnmetered traffic = revenue leakage; retrofit is 6+ weeks across 30+ SDKs.
OC-2Every event type is registered in the EventTypeRegistry (contracts) before any producer emitsProducer-side schema validator + CI registry diffKafka cardinality explodes; consumers break silently; observability dies (Analyze2 #4).
OC-3Every data-bearing SDK uses withTenant(...) from sdk-pool-router; no raw DSN readsLint blocks raw Postgres clients in package codeCross-pool reads slip in; isolation guarantee breaks.
OC-4Every layer-attribute read goes through resolveIdentityContext() from sdk-identity-resolverLint blocks direct sdk-identity / sdk-persona imports in non-resolver SDKsSix-layer manual traversal becomes the hot-path bottleneck (Analyze2 #1).
OC-5Every cross-pool read uses one of four sanctioned cases (resolver two-pool fetch · DSAR fan-out · analytics warehouse · lineage projection); marked with @cross_pool_sanctioned(reason)Lint blocks unmarked cross-pool clientsPool isolation degrades; ops nightmare at >200 pools.
OC-6Every agent action uses a capability token; no direct tool invocationTool runtime refuses without token; meter validates token at gateAgent leaks Tenant A into Tenant B (Analyze2 #5).
OC-7Every offline-write HDK module routes through hdk-sync; no direct write-queue implementationsLint blocks queue clients outside hdk-syncConflict-resolution policy fragments; field-ops conflicts unresolvable (Analyze2 #8).
OC-8Every encryption op uses sdk-vault; no direct KMS callsLint blocks AWS-KMS / GCP-KMS clients outside vault packageKey tier discipline breaks; cryptographic-shred becomes unreliable.
OC-9Every state-changing operation writes to sdk-auditLint requires audit emit on mutation handlers in code reviewPre-audit operations non-attestable; SOC2/HIPAA exposure.
OC-10No SDK ships a "v0 stub" of an upstream SDK to unblock its own development; upstream must be at v1.0CI fails if package depends on workspace v0 of another packageStub-driven divergence; integration day 1 is a refactor day.

3A.2 · What "opinionated" explicitly forbids

The trade. Opinionated constraints reduce flexibility in exchange for predictability. The platform is faster to learn, easier to debug, cheaper to operate, and harder to drift away from. Every constraint above is one that hyperscale platforms (AWS, GCP, Salesforce) eventually retrofit — we choose to start there.

3B · "Localize Complexity" Principle v3.1

Complement to §3A. Where §3A says "this is the only allowed pattern," §3B says "this complexity belongs HERE and only here." The rule: global standards, local behaviors. Anything global has to be agreed by Working Groups; anything local can be decided by the vertical owning it.

3B.1 · Global vs Local table

ConceptGlobal (one standard, platform-wide)Local (vertical / tenant / app decides)
IdentitySix-layer model · canonical IDs · JWT claim set · projection schemaPersona-extension fields per app · role-template names · BU tree shape
EventsEvent envelope · EventTypeRegistry namespaces · retention classesService-specific events within registered namespaces · per-event payload shape
SDK contractsPublic types in @projexlight/contracts · semver discipline · breaking-change protocolSDK-internal types · vertical-specific contract extensions (until promoted)
AuthorizationABAC engine · ReBAC engine · IQL grammar · policy decision log formatPer-tenant policies · per-app role-template overrides · per-encounter grants
Pool placementPool families · placement matrix (§8A) · cross-pool sanction rulesPer-tenant Tier (S/P/G) · sub-tenant opt-out · per-app pool capacity policy
PricingSKU schema in contracts · pricing modes · catalog versioningPer-tenant rate overrides · committed-use discounts · reseller commission rules
SemanticSemanticObject/Relation/CapabilityGraph type system · core cross-vertical concepts (Person · Address · Money · Document)Per-vertical ontology bundles · Intent definitions per vertical · per-tenant SemanticObject extensions
AgentsAgent identity types · Agent Isolation Runtime · capability-token formatPer-tenant agent definitions · per-agent scope · per-agent kill-switch
HDKNative bridge ABI · permissions model · sync protocolPer-app feature toggles · per-device profile · per-vertical sensor configurations
NotificationChannel abstraction · template engine · consent pre-flightPer-tenant templates · per-persona quiet hours · per-vertical channel mix
WorkflowTemporal facade · envelope propagation · compensable-step protocolPer-vertical workflow definitions · per-tenant SLA overrides

3B.2 · The rule for deciding global vs local

Test 1
"Would two verticals disagree?"
If yes → it's local. Different verticals will have different role names, different notification templates, different ontology coverage. Forcing one global answer creates friction.
Test 2
"Would a security audit care?"
If yes → it's global. Encryption tiers, audit chain format, consent receipt schema, ReBAC traversal limits all must be uniform — auditors cannot reason about per-vertical variants.
Test 3
"Would the answer affect cross-vertical interop?"
If yes → it's global. Event envelope, canonical IDs, pool routing, contracts all enable cross-vertical interop and must be uniform.
Test 4
"Would a 3rd vertical join later?"
If yes → start local; promote to global only after Rule of Three. Don't pre-globalize on speculation.
What this prevents. Without "Localize Complexity," every team gravitates toward putting their thing in common — common becomes a product of its own and verticals hollow out (Analyze.txt's #1 concern). With this principle, the table above is the contract: if it's not in the "global" column, it stays in the vertical or the tenant.

4 · Architecture Principles

P1–P10 carry forward from v2 unchanged. P11–P15 are introduced by v3 and now form the AIM-hardening core.

P1
Database per service
No cross-service joins. Services expose APIs and emit events; consumers project their own read models. v3 refinement: each service's database is "per service per pool" — see §8.
P2
Event-driven by default
Domain events flow over Kafka with the envelope from @projexlight/contracts. Sync APIs only where strict consistency is required.
P3
Multi-tenant + multi-vertical
Every API, table, event, log, and metric is scoped by tenant_id and vertical_id. The platform never assumes a single tenant or single vertical.
P4
Agents are not privileged
Agents call the same APIs as humans, with the same auth, the same rate limits, and the same audit trail. No backdoor.
P5
Contracts before code
An event, API, or HDK module interface does not exist until it is registered in @projexlight/contracts with a versioned schema.
P6
Composable UIs, theming over forking
Verticals theme via @projexlight/branding; they do not fork the design system.
P7
Compliance-aware
PII, audit, retention, and data residency are first-class concerns, not afterthoughts.
P8
Reuse over rebuild — but only after Rule of Three
The cheapest abstraction is the one a third consumer pulls from you.
P9
Offline-first for capture & auth
Authentication, permissions, capture, and editing must work without network. The device is the source of truth between sync windows; the cloud reconciles.
P10
Evidence integrity is non-negotiable
Captures from the HDK carry provenance (device ID, GPS, IMU, timestamp, consent reference, encounter ID) embedded at capture time. Raw and edited media are both retained.
P11 v3
No application-level sharding — pool, don't split
A tenant lives in one pool per category (admin · app · evidence). We add capacity by spinning up another parallel pool, not by splitting one tenant's data across many. Cross-shard queries are banned at lint time.
P12 v3
Identity is layered, not flat
Every authenticated request resolves to the six identity entities (when applicable). Authorization reads the whole tuple. Audit logs the whole tuple.
P13 v3
Identity entities are encrypted at rest, always
Master Person rows, credentials, secure-data bands, encounter payloads, relationship metadata — all envelope-encrypted under a key tier appropriate to the layer. Plaintext identity columns are a CI-blocking lint failure.
P14 v3
Cross-pool data movement requires an explicit migration job
Pool-to-pool tenant migration is an offline, audited, dual-write workflow — never an ad-hoc read. The Pool Router rejects any query that names a tenant whose pool is in MIGRATING state without a migration grant.
P15 v3
Tenant data never leaks across tenant memberships
A person's data at Hospital A is isolated from their data at Hospital B even though both share person_id. Cross-tenant reads require an explicit Relationship + Consent receipt; the encryption layer enforces this.
P16 v3.2
Decisions carry obligations, not just a verdict
The access mesh returns allow/deny plus obligations — fields to mask, rows to filter, audit level, decision TTL. Enforcement is server-side; UI visibility is advisory only. A caller may never be the sole thing standing between a hidden field and the wire (see §11A.3).
P17 v3.2
One minted internal principal; never trust forwarded headers
After authentication the gateway mints a single signed, audience-bound Platform Principal Token from the resolved IdentityContext. Downstream services trust that token — not raw user-supplied headers or claims. Closes the confused-deputy class of attacks (see §11A.4).
P18 v3.2
Consent gates the decision; absence fails closed
For purpose-bound resources, a missing or revoked consent receipt is a deny, not a warning. Consent is a first-class input to the access decision — distinct from authorization (can-act) and from MDM (which-entity). See §11A.5.

5 · Client Platform Strategy

One mobile framework. One web framework. One native SDK layer. One TypeScript contract spanning all three. The decision is locked; the table below records the trade-off so it stays auditable.

Decision. React Native (RN) for mobile and kiosk apps. React Web for browser surfaces. Native modules (Kotlin / Swift) for the HDK — bridged into RN. Flutter is explicitly not chosen; revisit only if the flip conditions hold.
SurfaceStackWhy
Web (browser)React + TS · @projexlight/design-systemMap page is business-critical and lives on the web first. React Web shares business logic with RN via TS packages.
Mobile (iOS · Android)React Native + TSSingle language across stack. Direct consumption of @projexlight/contracts and SDK packages.
Kiosk (sales devices)React Native, Android in COSU / device-owner modeSame RN APK as mobile, locked down via Android COSU. Login tracking, single-app pinning, MDM-managed.
HDK (native SDKs)Kotlin (Android) · Swift (iOS) · TS facadeCamera, AR, scanner, biometric, Mapbox, watermark, diagnostic — all need native APIs. The TS facade is the contract.

Why not Flutter

6 · HDK — Native SDK Ecosystem

The Hexa Development Kit (HDK) is the native counterpart to the JS/TS SDK packages. It owns the device-side capabilities that the platform needs to ship evidence-grade, offline-capable, sensor-driven experiences. Every HDK module is built once in Kotlin (Android) and Swift (iOS), bridged into React Native, and surfaced behind a TypeScript facade whose contract is registered in @projexlight/contracts.

flowchart TB
  classDef rn fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;
  classDef bridge fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef native fill:#241622,stroke:#ff6b6b,color:#e6ecf5;
  classDef ctr fill:#16241c,stroke:#5dd39e,color:#e6ecf5;

  RN["React Native app
(SevaApp · RealtyApp · FieldOpsApp · HealthcareApp · KioskApp)"]:::rn TS["TypeScript facade
@projexlight/hdk-* packages"]:::bridge CTR["@projexlight/contracts
HDK module interfaces · identity layers"]:::ctr AND["Android Native
Kotlin · AndroidX · CameraX"]:::native IOS["iOS Native
Swift · AVFoundation · CoreMotion"]:::native RN --> TS --> AND TS --> IOS TS -. types .-> CTR AND -. emits envelope events with encounter_id .-> RN IOS -. emits envelope events with encounter_id .-> RN
HDK runtime model. RN apps depend on TS facades; the facades bridge to native modules. Events carry the full identity tuple (incl. encounter_id when in scope).

6.1 · The ten HDK modules

#ModuleCapabilityNative depsOwner
1hdk-mapProvider-abstracted maps (Mapbox · Google · OSM), property bounding boxes, storm overlays, clustering, custom markers, Uber-style anchors/routes/ETAMapbox SDK · Google Maps SDKSatyam
2hdk-cameraEvidence-grade capture. Embeds GPS, IMU, timestamp, device ID, consent reference, encounter reference into media at capture time.CameraX · AVFoundation · CoreMotionKunal
3hdk-idpOffline biometric + PIN. App authenticates locally, then resolves identity (incl. App Identity binding) via cloud IDP when online.BiometricPrompt · LocalAuthenticationShoaib · Krunal
4hdk-scannerQR · Barcode · AprilTag detection with context dispatch.MLKit · Vision · custom AprilTagTBD
5hdk-image-editorShapes, arrows, text annotations, crops, filters, AI auto-correct, pinch straightening. Raw + edited both retained.Skia · GPUImage · MLKitShoheb
6hdk-video-editorTrim, segment cut-in, speed, overlays, music, volume, branding. Local saving + URI outputs.MediaCodec · AVFoundationShoheb
7hdk-measureDouble-arrow measurement annotations (m · in · ft), AR length using start/end point recognition.ARCore · ARKitTBD
8hdk-watermarkLogo placement, metadata overlays, brand-asset presets, font dropdowns.Skia · CoreGraphicsTBD
9hdk-diagnosticPermissions, Wi-Fi, internet speed, device memory, sensors, temperature. Pre-crash snapshots tied to device ID.Sentry-native · custom telemetryKunal
10hdk-permissionsDevice-level permission gates + role/consent overlay; pairs with cloud Policy + ReBAC.System permissions APIsMayur

6.2 · HDK installation order

1. @projexlight/contracts           (TS shapes, no native deps)
2. @projexlight/sdk-identity         (TS facade)
3. @projexlight/sdk-pool-router      (TS — required by every data-touching module)
4. @projexlight/hdk-idp              (native: biometric, PIN)
5. @projexlight/hdk-permissions      (native: layered enforcement)
6. @projexlight/hdk-diagnostic       (native: telemetry — required by all subsequent)
7. @projexlight/hdk-camera           (native: depends on permissions + diagnostic)
8. @projexlight/hdk-map              (native: depends on permissions)
9. @projexlight/hdk-scanner          (native: optional, depends on camera)
10. @projexlight/hdk-image-editor    (TS + native renderer)
11. @projexlight/hdk-video-editor    (TS + native renderer)
12. @projexlight/hdk-measure         (native: depends on camera + AR)
13. @projexlight/hdk-watermark       (TS + native renderer)
Android / iOS parity rule. A module ships when both platforms reach feature parity. The TS facade refuses to load if a platform implementation is missing, surfacing a clean unsupported-platform error instead of a silent no-op.

6A · Conflict Resolution Model for HDK Offline Sync v3.1

Every HDK module that does offline-write (camera, map, scanner, image-editor, video-editor, measure, watermark) eventually faces the same problem: multiple devices, multiple users, concurrent edits, offline windows, then reconnect. Without a centralized model, every module reinvents conflict handling — and field-ops verticals hit unresolvable collisions in week 1 of production.

Why a doctrine, not just an SDK. Architectural review (../../Analyze2.txt #8) flagged offline sync as one of the 9 hyperscale-killers: "bidirectional multi-device concurrent sync conflicts explode in field operations." The fix is not just hdk-sync (the SDK that executes resolution) but a documented per-event-type policy in @projexlight/contracts that every event author declares once. Then resolution is mechanical.

6A.1 · The five resolution strategies

Every event type registered in the EventTypeRegistry (§8B + sdk-audit) declares one of these strategies as its conflict_policy. hdk-sync reads the policy and applies it on reconnect.

StrategyUse forHow it resolvesExample event types
CRDT
(Conflict-free Replicated Data Type)
Collaborative editing of structured data; counters; setsMathematical merge — order doesn't matter; result is identical regardless of which device's edit arrives firstcontent.note.edit.v1 (collaborative notes); encounter.tag.add.v1 (tag sets); telemetry counters
LWW
(Last-Write-Wins)
Ephemeral state; sensor readings; UI stateHighest timestamp wins; loser's write is recorded in audit but not applieddevice.location.update.v1; device.battery.report.v1; diagnostic.heartbeat.v1
Merge Policy
(typed field-level merge)
Structured documents with non-overlapping field editsPer-field merge rule (additive · max · last-write · veto); if rules conflict, escalate to human-reviewproperty.listing.update.v1; contract.terms.amend.v1; tenant.config.update.v1
Event SourcingLedger-style data; financial entries; audit trail; immutable historyAll conflicting events are appended in causal-order; state is the fold of all events; nothing is discardedpayment.charge.v1; audit.action.v1; donation.received.v1; encounter.note.append.v1
Human ReconciliationSensitive data; PII edits; financial corrections; clinical notesConflicts queue to a Needs-Review surface; the responsible persona (or their delegate) picks the winner; sdk-approval governs delegationprofile.pii.update.v1; encounter.clinical-note.edit.v1; payment.refund.v1 (when amount disputed); property.title.amend.v1

6A.2 · How a conflict is resolved (the flow)

sequenceDiagram
  participant D1 as Device 1 (offline)
  participant D2 as Device 2 (offline)
  participant SYNC as hdk-sync
  participant POL as ConflictPolicy
(from contracts) participant AUD as sdk-audit participant HR as Human-Review queue
(if needed) D1->>D1: Edit at t=10 (offline) D2->>D2: Edit at t=12 (offline) Note over D1,D2: Both reconnect D1->>SYNC: Replay queue: edit@t=10 D2->>SYNC: Replay queue: edit@t=12 SYNC->>POL: getPolicy(event_type) POL->>SYNC: strategy=CRDT|LWW|merge|event-sourcing|human-review alt CRDT SYNC->>SYNC: mathematical merge → single state SYNC->>AUD: record both inputs + merged output else LWW SYNC->>SYNC: t=12 wins (newer) SYNC->>AUD: record loser t=10 in audit else Merge Policy SYNC->>SYNC: field-level merge — if collision → escalate SYNC->>AUD: record per-field decisions else Event Sourcing SYNC->>SYNC: append both in causal order SYNC->>AUD: full event history preserved else Human Review SYNC->>HR: queue both versions with diff HR->>SYNC: human picks winner SYNC->>AUD: record human decision + reason end SYNC->>D1: ack with resolved state SYNC->>D2: ack with resolved state

6A.3 · What contracts owns

// In @projexlight/contracts/conflict.ts

export type ConflictPolicy =
  | { kind: 'crdt'; type: 'g-counter' | 'pn-counter' | 'lww-set' | 'or-set' | 'rga-text' }
  | { kind: 'lww' }
  | { kind: 'merge'; field_policies: Record<string, FieldPolicy> }
  | { kind: 'event-sourcing' }
  | { kind: 'human-review'; queue: string; delegation: ApprovalRoute };

export type FieldPolicy = 'additive' | 'max' | 'min' | 'last-write' | 'veto-conflict';

// Each event type in the EventTypeRegistry declares its policy:
export const EventTypeRegistry = {
  'content.note.edit.v1':   { policy: { kind: 'crdt', type: 'rga-text' }, ... },
  'device.location.update.v1': { policy: { kind: 'lww' }, ... },
  'payment.charge.v1':      { policy: { kind: 'event-sourcing' }, ... },
  'profile.pii.update.v1':  { policy: { kind: 'human-review', queue: 'pii-review', delegation: 'tenant-admin' }, ... },
  // ... every event type registered
} as const;

6A.4 · Guarantees

The trade. A small upfront cost (every event-type author picks a policy at registration time) buys a large operational gain (zero unresolvable conflicts in production, full audit trail of who decided what). Without this doctrine, field-ops verticals collapse under reconciliation cost within months of launch.

7 · Identity Foundation — Three Pillars + Six Layers

The enterprise identity stack rests on three pillars (carried from v2) and is expressed through a six-layer entity stack (introduced in v3).

The three pillars. (1) MDM for canonical identity and reference data, (2) ABAC for attribute-based authorization that reads MDM facts, and (3) Consent for purpose-bound, jurisdiction-aware permission. Every domain service references MDM-owned IDs; every API call passes ABAC; every read of personal data clears Consent. v3 adds a fourth evaluator — ReBAC (relationship-based access control) — and a fifth structural primitive — the Encounter.

7.1 · The scope hierarchy — four scope levels

ScopeMeaningExample
app_idThe application surface in use. Defines the data model and event namespace.healthcare · seva.devotee-app · fieldops.contractor-kiosk
bu_idBusiness Unit within an app — a sub-division with its own approval chain, P&L, or geography. Optional.verborix-east-region · shantam-mumbai-chapter
tenant_idThe customer organization. Lives inside an app_id scope.verborix-holdings · kiana-realty · hospital-a
org_idThe org-admin scope — a meta-tenant. Used by re-sellers, MSPs, holding-company governance.projexlight-india · kpmg-msp-northeast

7.2 · Canonical master entities (v2 baseline)

MDM holds these entities and their canonical IDs. Every other service and vertical stores its domain rows against these IDs — never duplicating personal, location, or device data.

Master · MDM
person_id
The single canonical identity for a human across all apps, verticals, and tenants. The L1 layer of the identity stack.
Master · MDM
address_id
A geolocation-unique address — residential building, plot, office, warehouse, place-of-worship. Resolved at ingestion by Map/Geo. Property/Asset IDs are extensions of address_id.
Master · MDM
device_uuid
The HDK device identity (issued by hdk-idp on first install). Joins captures, evidence chains, biometric assertions, and telemetry.
Master · MDM
org_id / tenant_id
Canonical organization rows. Carry legal names, registrations, KYC status, sanctioned-region flags.

7.3 · The six identity layers v3

v2 left identity at "person_id + tenant_id". v3 expands to a six-layer entity stack. Each layer answers a question no other layer can; each carries its own audit trail, encryption key tier, and consent gates.

L1

Master Person · person_id

The single canonical human, globally unique across all apps, tenants, and verticals. Holds the alias graph, the home region pointer, the master cryptographic shred key, and a thin compliance summary. Stored in: admin pool of the home region. Key: Person Key.
L2

App Identity · app_identity_id

A person's projection into one application. One row per (person_id × app_id). Carries app-scoped profile, preferences, and notification routing.
L3

Tenant Membership · tenant_membership_id

An app identity's membership in one tenant within that app. One row per (app_identity_id × tenant_id). Carries tenant-scoped roles, status, and tenant-scoped policy attributes.
L4

Persona · persona_id

The "hat" worn at a tenant membership. Patient, Doctor, Buyer, Donor, Investor, Sales-Rep, Contractor, Homeowner. The join point to domain extension tables.
L5

Encounter · encounter_id

A bounded interaction — visit, admission, order, appointment, course term, site visit. Carries time bounds, location, participants, encounter-level consent, and a per-encounter encryption key.
L6

Relationship · relationship_id

A long-running bond between two personas — patient-doctor, customer-loyalty, investor-advisor, homeowner-contractor. Spans many encounters. Drives ReBAC.

7.4 · The full identity tuple on every request

{
  "person_id":           "pers_01HXYZ...",          // L1 master
  "app_id":              "healthcare",              // app scope
  "app_identity_id":     "apid_01HXYZ...",          // L2
  "tenant_id":           "ten_hosp_a",              // tenant scope
  "tenant_membership_id":"tmb_01HXYZ...",           // L3
  "persona_id":          "pers_01HXYZ_patient",     // L4
  "persona_role":        "patient",
  "encounter_id":        "enc_01HXYZ_visit_42",     // L5 optional
  "relationship_ids":    ["rel_01HXYZ_dr_smith"],   // L6 optional
  "device_uuid":         "dev_01HXYZ...",
  "consent_refs":        ["cnst_01HXYZ_phi_read"],
  "session_id":          "sess_01HXYZ..."
}

7.5 · Person bands — Profile · Preference · Notification · Secure Data

v2 introduced four bands of sensitivity hanging off the person. v3 re-homes them to their proper layer:

BandLayer in v3.1ExamplesEncryption tier
Profile (display)L2 App IdentityName shown in this app, locale, avatar, role hintsVault · Person key (per app envelope)
PreferenceL2 App IdentityChannels, opt-ins, language, theme — per appVault · Person key
Notification routingL2 App IdentityWhatsApp number, email, push tokens, quiet hours — per appVault · Person key
Secure DataL1 Master PersonDL · PAN · Aadhaar (last-4 in clear, full in vault) · SSN · Passport · PCI tokensVault · Person key + per-field envelope · purpose-bound consent required

7.6 · MDM methodology — Registry · Consolidation · Coexistence · Centralization

The MDM layer is not a single style; it adapts per entity and per maturity. The four classic patterns live side-by-side:

PatternWhere used
Registryperson_id for regulated tenants (Tier G) — full PII stays in tenant-owned stores; MDM holds the alias graph and consent pointers only.
Consolidationaddress_id across permits, property tax, drone feeds, and HDK GPS captures — golden record feeds Map/Geo and downstream OLAP.
Coexistencedevice_uuid attributes (last-known location, OS version, telemetry health) — Diagnostic-Telemetry, HDK, and Identity all converge.
CentralizationThe person_id alias graph; org_id and tenant_id registrations; consent receipts; the App Identity and Tenant Membership tables.

7.7 · Cross-domain reuse — the system of system

The same identity foundation underpins every domain. Each domain adds extension schemas hanging off the canonical IDs and personas — it does not duplicate them.

DomainPersonas (L4)Encounter kinds (L5)Common relationships (L6)
ConstructionWorker, Contractor, Homeowner, InspectorSite visit, Inspection, Punch-listHomeowner-Contractor, Worker-Foreman
HealthcarePatient, Doctor, Nurse, CaregiverVisit, Admission, Surgery, ER episodePatient-PCP, Care team
EducationLearner, Educator, Parent, AdministratorEnrollment term, Course session, ExamStudent-Teacher, Student-Counselor
RecruitmentCandidate, Recruiter, Hiring ManagerInterview, Offer round, OnboardingCandidate-Recruiter
HREmployee, Manager, HR partnerPerformance cycle, Promotion review, Off-cycleEmployee-Manager
Real estateInvestor, Owner, Agent, TenantSite visit, Document execution, Cap call, DistributionInvestor-Advisor, Owner-Agent
SevaDevotee, Acharya, DonorDonation, Anushthan, ProgrammeDevotee-Acharya
FieldOpsContractor, Rep, Homeowner, RooferSite visit, Estimate, Settlement, JobHomeowner-Contractor, Rep-Territory
eCommerceBuyer, SellerOrder, RMA, Cart sessionCustomer-Loyalty, Customer-Rep
The non-negotiable. No vertical, no Common service, and no agent stores a person's name, address, device, or organization as a primary string. Everything references the MDM canonical ID and the right identity layer. If a PR introduces a new person_name column on a domain table, it fails review — the column is persona_id (or higher) and the name is fetched through the Persona / Profile SDKs, with the access mesh on every call.

8 · AIM Pool Architecture v3

The platform pivots from "Postgres per service" to "Postgres per service per pool" — and we add capacity by adding pools, not by sharding tables. This is the single largest scaling decision in v3.1.

The decision. We do not shard application tables. Instead we run many parallel databases ("pools"), pin each tenant to one pool per category, and grow capacity by adding pools. A pool is a self-contained Postgres cluster (primary + replicas + PITR). The Pool Router resolves (tenant_id, app_id) → pool_index in <5ms via Redis. Every domain query touches exactly one pool.

8.1 · Why no sharding

Sharding (rejected)Pooling (chosen)
Tables split across nodes by a sharding key.Whole tenants on one node; many tenants share a node.
Cross-shard joins and transactions require coordinator nodes.All a tenant's joins are local — single-node ACID transactions.
Rebalancing requires live row migration.Rebalancing is offline tenant migration — staged dual-write, atomic cutover.
One bad query can blast every shard.Blast radius confined to one pool — capped to ~5k tenants.
Schema changes ripple across N shards.Schema changes roll pool-by-pool with the migration agent watching health.
Per-tenant encryption keys must be referenced cross-shard.Per-tenant key cached locally in pool's HSM bridge.
Compliance auditing is shard-distributed.Compliance auditing is pool-local — every PHI record on one pool, one region.

8.2 · Pool families

Family · Admin
Admin Pool · admin_pool_index
Tenant's identity-and-control plane: tenant registration, user accounts, App Identity rows, Tenant Membership rows, Persona rows (identity facet), billing, subscriptions, feature flags. ≤ 5k tenants per pool, ≤ 5TB.
Family · Application
App Pool · app_pool_index[app_id]
That app's domain data for assigned tenants. Per-app independent pool index — a tenant can be on app-pool 7 for Healthcare and 22 for eCommerce. ≤ 2k tenants per shared app pool, ≤ 30TB. Tier-G dedicated apps go up to 200TB.
Family · Evidence
Evidence Pool · evidence_pool_index
Large-blob domain data (medical images, evidence captures, contracts, recordings). Backed by S3 + Postgres metadata sidecar. ≤ 10k tenants per pool, ≤ 50TB metadata.
The admin / app pool split. A tenant's identity data lives in the admin pool (shared, compact, hot). Their operational data lives in the app pool (sized per app's growth curve — donations/day differs from orders/day differs from encounters/day). This separation lets us share admin pools across many tenants while sizing app pools independently per app.

8.3 · Pool indexing

Each pool is identified by a stable, never-reused index: admin-001, app-onestate-014, app-healthcare-007, evidence-003.

// Tenant row in the Pool Registry
{
  "tenant_id":          "ten_01HXYZ...",
  "org_id":             "org_proj_in",
  "isolation_tier":     "S | P | G",
  "region":             "ap-south-1",
  "admin_pool_index":   "admin-014",
  "app_pool_index": {
    "healthcare":       "app-healthcare-007",
    "ecommerce":        "app-ecommerce-022",
    "onestate":         "app-onestate-004",
    "seva":             "app-seva-002"
  },
  "evidence_pool_index":"evidence-003",
  "status":             "ACTIVE | PROVISIONING | MIGRATING | SUSPENDED | TOMBSTONE"
}

8.4 · Pool capacity targets

Pool familyTenants/poolSize/poolHot rows
Admin (shared)~5,000≤ 5 TB≤ 50M identity rows
App (shared · transactional)~2,000≤ 30 TB≤ 1B domain rows
App (dedicated · Tier G)1≤ 200 TB≤ 10B rows
Evidence~10,000≤ 50 TB metadata≤ 500M blob refs

8.5 · Scale projection

StageTenantsAdmin poolsApp pools (avg per app)Approx data
Pilot1 – 5011< 100 GB
Early50 – 1,00011 – 2≤ 5 TB
Growth1k – 10k2 – 33 – 8~ 50 – 200 TB
Scale10k – 100k20 – 2530 – 60~ 1 – 5 PB
Hyperscale100k – 1M+200 – 500300 – 1000+≥ 10 PB
flowchart TB
  classDef router fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef admin fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;
  classDef appp fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef ev fill:#241622,stroke:#ff6b6b,color:#e6ecf5;
  classDef ten fill:#1d1830,stroke:#b88dff,color:#e6ecf5;

  T1["Hospital A · tier S"]:::ten
  T2["Hospital B · tier P"]:::ten
  T3["Shantam · tier S"]:::ten
  T4["ContractorCo · tier S"]:::ten
  T5["KianaRealty · tier G"]:::ten

  ROUTER["Pool Router"]:::router

  AP1[("admin-001
~3000 tenants")]:::admin AP2[("admin-002
~2500 tenants")]:::admin HC1[("app-healthcare-001")]:::appp HC2[("app-healthcare-002")]:::appp EC1[("app-ecommerce-001")]:::appp SV1[("app-seva-001")]:::appp FO1[("app-fieldops-001")]:::appp RE1[("app-realty-001 · dedicated")]:::appp EV1[("evidence-001")]:::ev EV2[("evidence-002")]:::ev T1 --> ROUTER T2 --> ROUTER T3 --> ROUTER T4 --> ROUTER T5 --> ROUTER ROUTER -. admin .-> AP1 ROUTER -. admin .-> AP2 T1 -. healthcare .-> HC1 T2 -. healthcare .-> HC2 T3 -. seva .-> SV1 T4 -. fieldops .-> FO1 T5 -. realty .-> RE1 T2 -. ecommerce .-> EC1 T1 -. evidence .-> EV1 T2 -. evidence .-> EV2 T4 -. evidence .-> EV1
Five tenants spread across two admin pools and several app pools. Hospital A and Hospital B are isolated even though both run Healthcare. KianaRealty is Tier-G with its own dedicated Realty pool.

8A · Pool Placement Matrix v3.1

Every SDK's data has to land in some pool. Without an explicit matrix, each SDK team makes its own placement decision and the petabyte-scale isolation guarantees from §8 erode. This section is the canonical authority — every new SDK declares its placement here before merging contracts.

Principle
Pool isolation is for OLTP & PII
Tenant data with row-level isolation lives in pools. Aggregated, non-PII, cross-tenant analytical data lives in the warehouse layer. The two are different problems.
Principle
Cross-pool reads require justification
Default is no live cross-pool reads. The two sanctioned exceptions: (a) two-pool fetch by sdk-identity-resolver (Admin + one App per request, aggressively cached); (b) DSAR fan-out by sdk-data-rights (driven by the residency registry, not by table scans).
Principle
Platform-global data lives in contracts or Global Catalog
Static reference data (event-type registry, geographic-node tree, semantic ontology bundles, pricing-catalog schema) ships in @projexlight/contracts. Slow-changing larger artifacts get a Global Catalog read-replica pattern.

8A.1 · Pool families (recap + extensions)

FamilyWhat lives hereSizing targetIndex
Admin PoolL1 Master Person · L2 App Identity · L3 Tenant Membership · L4 persona identity facet · tenant registry · reseller/sub-tenant rows · BU tree · role templates · fiscal periods · feature flags · billing rows · API keys · webhook registry · approval state · federation config · DSAR workflows · person-pool-residency registry≤ 5k tenants · ≤ 5TBadmin-NNN
App PoolL4 persona extension data · L5 Encounter · L6 Relationship · domain entities (chart root, order, donation, listing) · agent memory namespaces · per-pool lineage subgraphVaries by app (≤ 30TB Tier-S, ≤ 200TB Tier-G)app-{vertical}-NNN
Evidence PoolProvenance-stamped media blobs · raw + edited captures · imaging · signed contracts · chain-of-custody metadata≤ 10k tenants metadata · ≤ 50TB metadata + S3-backed blobsev-NNN
Global Catalog v3.1Semantic ontology bundles (when too large for contracts) · per-region static reference data (geographic-node tree, address normalization) · event-type registry · pricing-catalog schema. Read-replicated everywhere; writes via contracts releases.One per region · ≤ 10GBcat-{region}
Warehouse v3.1Aggregated cross-pool analytics · usage rollups for billing (ClickHouse partitioned by pool_index) · cross-pool lineage projections · per-tenant analytical extracts. No PII at the row level unless tenant has consented to warehouse export.Petabyte-scale, region-pinnedwh-{region}
Vector store v3.1Per-tenant agent-memory namespaces · embeddings for sdk-knowledge-rag corpora. Hard physical partitions per tenant (not logical filters) to prevent prompt leakage.Per-pool pgvector (default) · dedicated cluster (Tier-G)vec-{pool_index}

8A.2 · Per-SDK pool placement

SDKPrimary poolCross-pool reads?Scaling notes
sdk-vaultPer-pool KEK; key material in HSM/KMSNoPer-pool key tier; cryptographic shred is scoped to pool
sdk-auditPer-pool append-only chainNo · regional rollup asyncEvent-type registry is global (contracts); retention enforcement per-pool
sdk-pool-routerPool Registry in Admin Pool of region · Redis cache per serviceN/A — it is the routing layerFederation manifest extends for 1000+ pool world
sdk-secretsKMS-backed; refs in any poolNo
sdk-meter v3.1Events in Kafka (partitioned by tenant_id) · rollups in shared Warehouse ClickHouse partitioned by pool_indexNo (rollups are pre-aggregated)Shared ClickHouse is correct for OLAP. Pool-per-ClickHouse would be 1000+ clusters at scale — wrong tool.
sdk-tenantAdmin Pool (reseller, tenant, sub-tenant, BU, geo, roles, fiscal)NoSub-tenant pool placement: hybrid — share parent by default, opt-out for Tier-P/G
sdk-identityAdmin Pool (credentials, alias graph, federation config)NoJIT-provisioning via SCIM writes Admin Pool rows
sdk-consentAdmin PoolCross-tenant consent records may span 2 Admin PoolsReceipts keyed by person_id (always in person's home Admin)
sdk-policyAdmin Pool (policies) · Redis (precomp cache)NoIQL evaluator runs in-process per service
sdk-rebacApp Pool for in-app relationships · Admin Pool for cross-tenant relationshipsBounded by traversal-depth capEdge indexes + async projection keep p99 ≤ 5ms at 10M edges
sdk-api-keys v3.1Admin Pool (hashed keys + scope)NoEach API key bound to a synthetic persona
sdk-profileL2/L3 bands in Admin Pool · Secure Data band in Admin Pool with per-field envelopeNoProfile/Preference/Routing now on App Identity (per-app)
sdk-personaIdentity facet in Admin Pool · Extension in App PoolTwo-pool fetch (via resolver only)Persona shred independent of person shred
sdk-identity-resolver v3.1Stateless · reads Admin Pool + one App Pool per requestSanctioned two-pool fetchRedis cache; p99 ≤ 1ms warm; cold-path fallback returns L1+L2+L3 only
sdk-data-rights v3.1Workflow state in Admin Pool · fan-out via person_pool_residency registryDSAR fan-out across all pools holding person's dataRegistry written on every first-touch; weekly reconciliation against actual presence
sdk-geoGeographicNode tree in Global Catalog · canonical addresses in Admin PoolNoStatic tree → cheap reads from any pool
sdk-deviceDevice registry in Admin PoolNo
sdk-feature-flagsAdmin Pool (per-tenant) · Redis evaluatorNo
sdk-mediaS3 with per-tenant prefix · keys per-poolNoEncounter-keyed blobs sealed on encounter close
sdk-notificationApp Pool (delivery state) · provider APIsNo
sdk-paymentAdmin Pool (PCI tokenized refs) · provider APIsNo
sdk-workflowTemporal cluster · workflow state in App PoolNoOne Temporal namespace per pool family
sdk-searchOpenSearch per-pool indexes · per-tenant aliasesNoIndex-per-tenant within pool
sdk-billing v3.1Admin Pool (invoices, line items) · reads Warehouse rollupsReads Warehouse onlyInvoices billed to reseller or end-tenant per contract
sdk-webhook v3.1Admin Pool (endpoint registry) · per-pool outbox · per-pool delivery workersNoHMAC keys vaulted; circuit breaker per endpoint
sdk-approval v3.1App Pool (approval state for in-app actions) · Admin Pool (cross-app approvals)No
sdk-tenant-lifecycle v3.1Admin Pool (lifecycle state) · orchestrates pool allocations + shredsBy designSandbox sub-pool with masked PII
sdk-engagementEncounter + Relationship in App Pool · Encounter Grants short-livedNoEncounter key shreds on seal
sdk-crm · sdk-content · sdk-service-request · sdk-event · sdk-campaign · sdk-socialApp PoolNo
sdk-sequence · sdk-scheduling · sdk-deliverability · sdk-offer-catalog · sdk-handoff · sdk-incident P14·15App PoolNoInboundCRM domain SDKs (Sprint3): multi-touch cadence, booking/no-show, suppression/bounce/reply, versioned offer truth, Sales→Delivery handoff, exception/incident evidence. Background workers opt-in per-SDK env flag; external I/O behind pluggable provider hooks (default no-op)
connector-twilio-voice P14·15App Pool mirror (tracking numbers + call legs) · Twilio provider APIsNoTelephony channel: number provisioning, recorded outbound calls, signed status/recording webhooks with AMD→voicemail. Recording gated on sdk-consent; call events bridge to sdk-crm timeline
sdk-ai-gatewayStateless gateway · provider APIs · Langfuse tracesNoBudget enforcement via sdk-meter
sdk-taxonomyAdmin Pool (per-tenant overrides) · platform-global templates in Global CatalogNo
sdk-knowledge-ragPer-tenant corpora in App Pool · embeddings in Vector store partitionNoHard physical partition prevents leakage
sdk-parsingPipeline state in App Pool · documents in Media · extractions to App PoolNo
sdk-agent-runtimeAgent definitions in Admin Pool · memory namespaces in Vector store partition per tenantNo (physical isolation enforced)Cross-tenant prompt-leakage CI test on every change
sdk-conversation · sdk-recommendationApp PoolNo
sdk-analyticsWarehouseBy designNo live cross-pool joins
sdk-lineage v3.1Per-pool lineage subgraph for in-pool edges · cross-pool projection in WarehouseIn-pool reads sync · cross-pool reads async via warehouseMatches "no live cross-pool joins" rule
sdk-semantic v3.1Ontology bundles in contracts (v1) or Global Catalog (when too large) · per-tenant SemanticObjects in App PoolNoTenant-defined extension types stay in App Pool; promoted types go to contracts via Rule of Three
sdk-storm · sdk-dispatch · sdk-assignment · sdk-lead-scoringApp PoolNo
sdk-evidenceMetadata in Evidence Pool · blobs in S3 · keyed per encounterNoSealed encounters block new evidence
sdk-diagnostic-telemetryApp Pool · sample to WarehouseNo
sdk-trace v3.1Stateless reader · pulls from sdk-telemetry (OTel) + sdk-audit + sdk-meter + sdk-lineage storesReads from every source (sanctioned: pure read, no mutation)One trace_id propagates end-to-end; viewer renders unified timeline; trace export per request
hdk-sync v3.1Local on-device offline queue · server-side reconciliation in App Pool · conflict-resolution decisions audited per poolNo (per-pool reconciliation; cross-pool conflicts escalate to human-review)ConflictPolicy from contracts dictates resolution; replay-safe; idempotent

8A.3 · Three new primitives required by the v3.1 additions

1 · person_pool_residency registry

Required by sdk-data-rights for DSAR fan-out. Lives in person's home Admin Pool. Schema:

person_pool_residency (
  person_id           uuid not null,
  pool_index          text not null,            -- which pool holds data
  data_class          text not null,            -- 'persona-ext' | 'encounter' | 'relationship' | 'evidence' | 'agent-memory'
  first_touched_at    timestamptz not null,
  last_touched_at     timestamptz not null,
  primary key (person_id, pool_index, data_class)
)

Every data-bearing SDK writes a row on first-touch for a (person, pool, class) tuple. Weekly reconciliation job compares the registry against actual data presence — a discrepancy halts DSAR completion until investigated. Without this registry, "I erased this person's data" is unverifiable across hundreds of pools.

2 · Cross-pool lineage projection (Warehouse view)

Required by sdk-lineage. In-pool lineage edges (record A in App Pool X derived from record B in same App Pool X) stay in the pool's lineage subgraph for sync queries. Cross-pool lineage edges (parsed doc in Evidence Pool E → derived record in App Pool A → AI score from sdk-ai-gateway) are projected asynchronously into a Warehouse table:

warehouse.cross_pool_lineage (
  edge_id          uuid not null,
  source_pool      text not null,
  source_record    text not null,
  target_pool      text not null,
  target_record    text not null,
  edge_type        text not null,               -- 'extracted_from' | 'derived_from' | 'merged_from' | ...
  tenant_id        uuid not null,
  occurred_at      timestamptz not null
)

"Show me the full derivation chain for record X" first resolves in-pool, then queries the Warehouse projection for cross-pool hops. Hot path stays in-pool; cross-pool reasoning is async-acceptable.

3 · Sub-tenant pool placement policy: hybrid

When parent_tenant_id is set, the default policy is:

8A.4 · The CI rules that keep this matrix honest

Scale verdict. With this matrix as the canonical placement reference plus the three new primitives, v3.1 supports the stated petabyte / millions-of-tenants target. Pool count scales horizontally (federation hooks in sdk-pool-router address 1000+ pools); cross-pool reads are bounded to four sanctioned cases with explicit performance budgets; PII isolation holds at the pool level; aggregation moves to Warehouse where it belongs. No SDK in the 54-SDK estate violates the model — every placement is named.

8B · Polyglot Persistence Doctrine v3.1

Postgres is the right choice — but not for everything. v3.1 commits to polyglot persistence: each workload routed to the storage engine designed for it. The Pool Placement Matrix in §8A is the per-SDK lookup; this section is the principle that explains why.

Why this matters. Architectural review (../../Analyze2.txt #7) flagged "Postgres doing everything" as one of the 9 hyperscale-killers: stuffing telemetry, vector indexes, graph traversals, PB-scale logs, and global analytics into Postgres pools will hit ceilings — at which point retrofitting polyglot persistence is a multi-month migration. Better to start polyglot.

8B.1 · The workload → storage map

WorkloadStorage engineWhy this and not Postgres
OLTP
(transactional record-keeping; identity rows; encounters; payments)
PostgreSQL pools (per family · §8)ACID, row-level security, well-understood operationally; Postgres is the right tool
Search
(full-text queries; ABAC-filtered lookups; faceted search)
OpenSearch per-pool indexes; per-tenant aliasesPostgres FTS doesn't scale to 1M+ tenants with low latency; Lucene-based engines dominate
Telemetry & metrics
(usage events; latency; counters; rollups)
ClickHouse partitioned by pool_index (shared warehouse, NOT per-pool ClickHouse)OLAP columnar engine for high-cardinality time-series; Postgres tables would degrade by 100×
Blob storage
(media; evidence; documents; signed artifacts)
S3 / object store per tenant prefix; encrypted under per-encounter or per-tenant keysPostgres BLOBs are unworkable at scale; S3 is purpose-built
AI vectors
(embeddings; agent memory; RAG corpora)
pgvector per-pool for v1 → dedicated vector DB (Pinecone / Weaviate / Qdrant) at hyperscalepgvector works to ~10M vectors per pool; beyond that, dedicated stores have specialized ANN indexes
Graph projections
(ReBAC traversals; lineage subgraphs; semantic CapabilityGraph)
Postgres projection tables with edge indexes (v1) → Neo4j or Dgraph at hyperscaleRecursive CTEs work to ~10M edges; beyond that, native graph engines amortize traversal cost
Lakehouse
(PB-scale analytics; cross-pool aggregation; cold data; lineage cross-pool projections)
Iceberg / S3-tables (sdk-analytics in P7)ClickHouse alone can't hold PB; lakehouse table format is the industry-standard answer
Event stream
(domain events; usage events; HDK sync queue)
Kafka partitioned by tenant_idPostgres LISTEN/NOTIFY does not scale; Kafka is the proven choice
Cache & coordination
(routing cache; quota state; identity projection live store; rate limits)
Redis per region (with persistence for projection store)Postgres reads would dominate latency budgets; Redis is purpose-built for sub-ms reads
Workflow state
(durable workflows; saga state; long-running jobs)
Temporal (with its own Postgres or Cassandra backend)Building durable workflows on raw Postgres is reinventing Temporal; use Temporal
Audit chain
(append-only ledger; hash-chained; per-pool)
Postgres in per-pool audit chain (durability) + S3 for long-term archivalPostgres is fine for the append rate; immutability is enforced by the hash chain + archival
Keys & secrets
(KMS-wrapped; HSM-backed)
AWS KMS / GCP KMS / HSM via sdk-secrets · sdk-vaultNever in Postgres; key material in dedicated KMS only

8B.2 · The rules

Rule 1
Postgres pools are for OLTP + PII only
Tenant data with strong-consistency requirements + RLS isolation. Anything else needs a different home.
Rule 2
Cross-pool aggregation goes to warehouse
ClickHouse for hot rollups (≤90 days); Iceberg lakehouse for cold + PB scale. Never live cross-pool joins in Postgres.
Rule 3
High-cardinality time-series → ClickHouse
Telemetry, usage events, metrics. Putting these in Postgres degrades the entire pool.
Rule 4
Blobs → S3, never Postgres BLOB
Media, evidence, documents. Postgres stores the metadata; S3 stores the bytes; sdk-vault wraps the key.
Rule 5
Vectors → pgvector with an exit ramp
pgvector works to ~10M per pool. CI tracks vector counts per pool; at 8M, plan the migration to dedicated vector store.
Rule 6
Cache state is Redis, never a Postgres table
Routing cache, quota state, identity projection live store, rate-limit counters. Postgres-as-cache is an antipattern.
Operational implication. The platform team owns more than just Postgres — Kafka, ClickHouse, OpenSearch, Redis, Iceberg, Temporal, KMS, and a vector store are all first-class. This is the cost of doing things right at PB scale. The matrix above is the architectural shield against "let's just put it in Postgres" decisions that compound into multi-month migrations.

9 · Pool Routing & Registry v3

The Pool Router resolves (tenant_id, app_id, pool_family) → connection string for every domain query. It is the most performance-critical lookup in the platform: p99 ≤ 5 ms.

9.1 · Registry data model

TABLE pool (
  pool_index            text primary key,
  pool_family           text,                 -- 'admin' | 'app' | 'evidence'
  app_id                text,                 -- only when family='app'
  region                text,
  status                text,                 -- ACTIVE | DRAINING | MAINTENANCE | RETIRED | QUARANTINE
  capacity_tenants      int,
  current_tenants       int,
  capacity_bytes        bigint,
  current_bytes         bigint,
  primary_endpoint      text,
  replica_endpoints     text[],
  kek_arn               text,
  isolation_class       text                  -- 'shared' | 'dedicated'
);

TABLE tenant_pool_map (
  tenant_id             text primary key,
  admin_pool_index      text references pool,
  evidence_pool_index   text references pool,
  app_pool_index        jsonb,
  region                text,
  status                text,
  created_at            timestamptz,
  migrated_at           timestamptz
);

9.2 · Resolution path

sequenceDiagram
  autonumber
  participant C as Client
  participant GW as API Gateway
  participant ID as Identity
  participant RT as Pool Router SDK
  participant CACHE as Redis
  participant REG as Pool Registry
  participant DB as App Pool

  C->>GW: POST /v1/encounters/E_001/notes
  GW->>ID: validate JWT, extract identity tuple
  ID-->>GW: { tenant_id, app_id=healthcare, person_id, ... }
  GW->>RT: route(tenant_id, app_id)
  RT->>CACHE: GET tenant:ten_001:pool:healthcare
  CACHE-->>RT: app-healthcare-007 (cache hit)
  RT-->>GW: dsn
  GW->>DB: query routed to app-healthcare-007 only
    

9.3 · Cache & consistency rules

9.4 · SDK usage

import { withTenant } from "@projexlight/sdk-pool-router";

const result = await withTenant({ tenantId, appId: "healthcare" }, async (db) => {
  return await db.encounters.fetch({ id: encounterId });
});

The SDK refuses to issue an untenanted query against any application pool. Cross-tenant queries go through the warehouse.

v3.1 Every typed SDK method declared with @meter(...) is auto-wrapped at build time by sdk-meter's codegen so a check() precedes the call and a report() emits the usage event. SDK authors do not write metering code by hand. See §10A.

9.5 · What lives where

EntityPool family
person (master) · MDMAdmin pool of home region
app_identity · tenant_membership · persona identity facetTenant's admin pool
Persona extension data (donor history, patient chart root, investor stake)App pool for that app
encounter · relationshipApp pool
Evidence blobs · imaging · contractsEvidence pool
Audit ledgerPer-pool audit chain + regional roll-up

10 · Multi-Level Encryption — End-to-End

v2 established the four-tier key hierarchy (root · app · tenant · person/device/org). v3.1 keeps all of it and adds two tiers: Pool KEK (per pool) and Encounter Key (per encounter).

flowchart TB
  classDef root fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef pool fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;
  classDef ten fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef per fill:#241622,stroke:#ff6b6b,color:#e6ecf5;
  classDef enc fill:#1d1830,stroke:#b88dff,color:#e6ecf5;

  ROOT["Regional Root CMK
HSM-backed (per region)"]:::root POOLK["Pool KEK (per pool) v3
wraps tenant keys held in pool"]:::pool TENK["Tenant Key (per tenant_id)
wraps memberships, personas, encounters"]:::ten PERK["Person Key (per person_id)
wraps master + secure-data + app identities"]:::per ENCK["Encounter Key (per encounter_id) v3
wraps medical/financial payloads"]:::enc DEVK["Device Key (per device_uuid)
wraps biometric templates"]:::per ORGK["Org Key (per org_id)
wraps cross-tenant rollups"]:::per ROOT --> POOLK POOLK --> TENK TENK --> ENCK ROOT --> PERK PERK --> DEVK ROOT --> ORGK

10.1 · What is encrypted where

Row / blobWrapped byPool family
Master person · alias graphPerson KeyAdmin (home region)
Credentials & MFA secretsPerson Key (biometric → Device Key)Admin
Secure Data band (DL · PAN · Aadhaar · SSN · Passport · PCI tokens)Person Key + per-field envelopeAdmin
App Identity (per-app profile/preference/notification)Person Key (envelope, per-app salt)Admin
Tenant Membership · Persona identity facetTenant KeyTenant's admin pool
Persona extension (donor history, patient chart root)Tenant KeyTenant's app pool
Encounter payloadEncounter KeyTenant's app pool
Evidence blobsEncounter Key (when tied) · else Tenant KeyEvidence pool
Relationship metadataTenant Key (intra) · Cross-tenant Relationship Key (inter)App pool
Audit ledgerPool KEK (append-only, hash chain)Per-pool

10.2 · Right-to-erasure mechanics

ShredEffect
Person KeyEvery layer below — every app identity, every tenant membership, every encounter — becomes undecryptable across every pool, every region. Global erasure.
Tenant KeyAll that tenant's memberships, personas, encounters, relationships become undecryptable. Tenant offboarding.
Encounter KeyOnly that one encounter's payload becomes undecryptable. Narrow legal-hold release or per-encounter purge.
Device KeyBiometric templates and on-device captures associated with that device become undecryptable. Used when a device is reported stolen.
Why per-encounter keys matter in healthcare and finance. Retention rules apply per encounter type (HIPAA: 6y outpatient, 25y surgical; RBI: 8y financial). With a per-encounter key, retention expiry is a key shred — the row stays for analytics counts, the payload becomes mathematically irrecoverable.

10A · Metering, Pricing & Billing v3.1

Pay-as-you-use is the platform's structural billing model. Every typed SDK call is gated, metered, and priced per-method per-tenant per-app. The implementation lives in two SDKs (sdk-meter in W1 and sdk-billing in W4) and is bolted into every other SDK via build-time codegen — SDK authors annotate methods with @meter(...) and never write metering code by hand.

Pattern
Two-phase gate (GCP Service-Control)
Phase 1 CHECK is sync, p99 ≤ 2ms: ALLOW / WARN / DENY from Redis-backed quota state. Phase 2 REPORT is async, fire-and-forget: emit usage.event.v1 to Kafka. Never blocks the request path on settlement.
Differentiator
Six-layer showback
Every usage event carries the full AIM tuple (org · app · tenant · bu · persona · encounter) from the JWT. Customers split their bill by app, BU, persona-kind, or encounter — none of AWS/GCP/Azure offer this natively because their identity is flat.
Differentiator
Customer-verifiable bills
Usage events hash-chained per (tenant, day), links into Audit. Customer hits /billing/verify?day=... and re-derives the day's total. Hyperscalers do not expose raw events.

10A.1 · Data flow

flowchart LR
  classDef sdk fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef meter fill:#1d1830,stroke:#b88dff,color:#e6ecf5;
  classDef bill fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef store fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;

  CALL["Any SDK method
annotated @meter(sku,unit,tier)"]:::sdk CHK["sdk-meter · check()
≤ 2ms sync"]:::meter RDS[("Redis
quota state + live counter")]:::store EXEC["SDK body
(actual work)"]:::sdk REP["sdk-meter · report()
async, fire-and-forget"]:::meter KFK[("Kafka
usage.events.v1
partition by tenant_id")]:::store PROC["Per-pool stream processor"]:::meter CH[("ClickHouse
hourly · daily · monthly
rollups")]:::store CHN[("Hash-chained ledger
(tenant, day) → Audit")]:::store BIL["sdk-billing · monthly
apply pricing.catalog.vN"]:::bill INV["Invoice
(per SDK · per method ·
per app · per BU · per persona)"]:::bill PAY["sdk-payment → Stripe / Razorpay"]:::sdk LIVE["Customer /billing/live
≤ 60s lag"]:::bill CALL -->|"Phase 1"| CHK CHK -->|read| RDS CHK -->|ALLOW/WARN| EXEC CHK -->|DENY → throw QuotaExceeded| CALL EXEC -->|"Phase 2"| REP REP --> KFK KFK --> PROC PROC --> CH PROC --> CHN PROC --> RDS CH --> BIL RDS --> LIVE BIL --> INV INV --> PAY

10A.2 · The @meter decorator (what SDK authors actually write)

// What an SDK author writes — once, at method definition:
@meter({ sku: 'identity.jwt.mint', unit: 'call', tier: 'core' })
async mintToken(req: MintRequest, ctx: Ctx): Promise<Token> { ... }

// What codegen produces at build time (never edited by hand):
async mintToken(req, ctx) {
  const gate = await meter.check({                        // Phase 1 — sync, ≤ 2ms p99
    sku: 'identity.jwt.mint',
    tenant_id: ctx.tenant_id, app_id: ctx.app_id, actor: ctx.actor,
  });
  if (gate.decision === 'DENY') throw new QuotaExceeded(gate.reason);

  const result = await originalMintToken(req, ctx);

  meter.report({                                          // Phase 2 — async, idempotent
    event_id: ulid(),
    sku: 'identity.jwt.mint',
    units: 1,
    dimensions: {                                         // six-layer attribution from JWT
      org_id, app_id, tenant_id, bu_id, persona_id, encounter_id, pool_index,
      actor_kind, actor_id, region, latency_ms, bytes_in, bytes_out,
    },
    occurred_at: now(),
  });
  return result;
}

10A.3 · Pricing modes

ModeUse caseExample SKU
flat_per_callCheap idempotent opsidentity.jwt.verify @ $0.00005/call
tiered_per_callMost ops; volume rewardidentity.jwt.mint — free ≤ 10k/day, $0.0001 to 100k, $0.00005 beyond
passthrough_plus_marginProvider-cost-drivenai-gateway.complete — provider cost + 15%
per_unitBytes, docs, tokensparsing.extract @ $0.05/doc · media.put @ $0.02/GB-mo
bundled_subscription + overagePredictable bill"Healthcare Tier" — 1M identity calls/mo + overage
free_internalAgent-issued calls on tenant's behalfactor.kind = 'agent' → comped or rolled to "AI action" line item

10A.4 · Catalog versioning

10A.5 · SLAs

MetricTargetHow we beat hyperscalers
Admission gatep99 ≤ 2msIn-process LRU over Redis; no hyperscaler exposes a sync gate < 5ms.
Event emission overhead≤ 0.5msAsync enqueue to local ring buffer; flushed off the request path.
End-to-end (call → dashboard)≤ 60sAWS/GCP bills lag 12–24h. We're real-time because Kafka → Redis live counter.
Invoice generationT+24h after month closeAWS is T+72h.
Reprice dry-runT+1h for any monthPossible because raw units are preserved; not a feature elsewhere.
Hash-chain verifyNightly · zero tolerance for chain breaksCustomer-visible verification — unique.

10A.6 · Pool-aware aggregation

Rollups happen per-pool (the natural shard from §9). The Admin Pool consolidates per-tenant totals. Cross-pool aggregation goes through the warehouse only — never live cross-pool joins, matching the existing v3.1 isolation guarantee. Billing rows for a tenant live in that tenant's Admin Pool.

10A.7 · Where this beats AWS / GCP / Azure / Stripe

CapabilityAWSGCPAzureStripe BillingProjexlight v3.1
Two-phase gate (check + report)✓ Service Control— (report only)✓ p99 ≤ 2ms
Per-method SKUs across the estateInconsistent per-serviceYes but driftedResource-levelCustomer-defined✓ Typed in contracts
Per-persona / per-BU showbackTags onlyTags onlyTagsFlat customer✓ Six-layer native
Per-encounter cost (e.g., one healthcare visit)✓ encounter_id in event
Real-time meter (< 60s)12–24h lag~24h lag~24h lagHours✓ < 60s
Customer-verifiable hash chain✓ /billing/verify backed by sdk-trace — customer hits the endpoint, gets back not just the hash-chain but the full timeline of identity + consent + routing + key + policy + meter behind each usage event
Reprice past months under new catalogLimited✓ Dry-run + opt-in apply
Agent-vs-human cost split✓ actor.kind first-class
Method-level kill switchService-levelService-levelSubscription✓ Per-SKU via meter
Built-in cost-optimization agentCost Explorer (read)Recommender (read)Advisor (read)✓ Cost & Safety Steward writes downgrades
The wedge. Hyperscalers retrofitted metering on top of services that already existed; their identity is flat; their bills lag by a day; raw events are not exposed. We're greenfield, identity is six-layer, every SDK call already routes through withTenant() with the full envelope. Metering becomes one typed middleware, not 44 implementations — and customers get real-time, verifiable, splittable bills no incumbent offers.

11 · Access Control Mesh — ABAC + ReBAC + Encounter Grants

Authorization in v3.1 is the conjunction of three evaluators. Every read or write passes all three or fails.

Evaluator A · ABAC
Attribute-Based v2
Reads attributes from MDM (person.kyc_status, tenant.tier, app.region, device.attested) and runs a Cedar / OPA policy. Anchors structural rules.
Evaluator B · ReBAC
Relationship-Based v3
Reads the Relationship graph. "Dr.Smith can read Patient Ravi's chart only if relationship(Dr.Smith, Ravi, kind=primary-care, status=active) exists OR Dr.Smith is on the care team of an active Encounter with Ravi." Drives healthcare and longitudinal-customer access.
Evaluator C · Encounter Grants
Time/Scope-Bounded v3
Encounter-scoped temporary grants — "Nurse X has vitals access during encounter E_001 until 09:00." Issued by an authorized persona; revocable; auditable.

11.1 · Decision flow

sequenceDiagram
  autonumber
  participant U as User · Dr.Smith
  participant GW as API Gateway
  participant POL as Policy SDK · ABAC
  participant REB as ReBAC SDK
  participant GRT as Encounter Grants
  participant DB as App pool
  participant AUD as Audit

  U->>GW: GET /v1/patients/Ravi/chart
  GW->>POL: ABAC(actor=Dr.Smith, target=Ravi.chart)
  POL-->>GW: structural OK
  GW->>REB: relationship(Dr.Smith ↔ Ravi)?
  REB-->>GW: active primary-care relationship
  GW->>GRT: time-bounded grant?
  GRT-->>GW: not required
  GW->>DB: read chart (decrypt via encounter key)
  DB-->>GW: payload
  GW->>AUD: log{actor, target, evaluators, decision, snapshot}
  GW-->>U: chart
    

11.2 · Cross-tenant access

Default: zero cross-tenant access. A doctor at Hospital A cannot see a chart from Hospital B even for the same person. Exception: explicit cross-tenant Relationship + Consent receipt. Cross-tenant reads always go through a re-encryption proxy.

Anti-pattern. "We need cross-hospital analytics so let's just share the schema across tenants." No. Cross-tenant analytics goes through the data warehouse, not the live tenant pools, and only over fields a per-tenant consent allows.

11A · Platform Control Planes & Obligation-Based Authorization v3.2

A platform-layer design discussion (gaps/Analyze1.md) and its architectural critique (gaps/Analyze2.md) proposed a platform of eight explicit control planes and warned against the failure mode of one flat "platform" carrying overlapping identity truth. v3.1 already realizes most of that model at the application layer; v3.2 makes the mapping explicit and commits to the handful of upgrades the critique correctly identifies as necessary. The full capability scoring lives in ../insignia/ProjexCloud-vs-Insignia-Reality-Report-v2.html.

Doctrine. ProjexCloud meets the eight-plane model with application-layer equivalents, not the named infra stack (no Supabase/Keycloak/SPIFFE/OPA-runtime). The objective — identity-bound, default-deny, consent-aware, fully audited — is met. v3.2 closes the four gaps where the shape of the mechanism mattered (obligations, minted principal, consent-as-input, fail-closed) and records the rest as deferred by design.

11A.1 · The eight planes → owning packages

Control planePurposeOwning packages / servicesStatus
TrustProve who/what is callingsdk-identity, sdk-api-keys, sdk-identity-resolver (principal) · service mesh deferredpartial
Session / EdgeAuthenticate, create session, map to principalsdk-identity, api-gateway, sdk-projection, identity-projectorworks
PolicyDecide what is allowedsdk-policy (ABAC), sdk-rebac, Encounter Grants · obligations added in §11A.3works → +obligations
ConsentDecide whether the purpose is permittedsdk-consent, sdk-data-rights · wired into decision in §11A.5works → +gating
MDM / Real-IdentityResolve real-world entitiessdk-identity-resolver + six-layer tables (deterministic)works (probabilistic deferred)
Event & WorkflowMake changes durable & replayablekafka-runtime, clickhouse-runtime, sdk-meter, sdk-event, sdk-workflowone Kafka log
Observability / Audit / LineageKnow what happened, why, and what it touchedsdk-audit, sdk-trace, sdk-lineage, telemetry, sdk-diagnostic-telemetryevidence portal partial
Developer Experience / ShellMake app devs use the platform correctly by default3 Next.js apps (App Shell), api-gateway (Gateway), 70+ sdk-*/hdk-* + /build planner (SDK)3 of 4 (sidecar deferred)

11A.2 · The five-identities discipline

One word, five meanings — kept separate. The critique's central warning is that "identity" is overloaded. ProjexCloud's six-layer stack already enforces the split: login identity (App Identity · L2) ≠ platform-subject identity (the resolved IdentityContext) ≠ master-data identity (Master Person · L1). Service identity (which workload is calling) is the one ProjexCloud does not cryptographically establish today — that is the Trust-Plane / service-mesh deferral in §11A.6. No plane is permitted to pretend to be another: Session authenticates, Policy authorizes, Consent permits-by-purpose, MDM resolves entities.

11A.3 · Obligation-bearing authorization v3.2 (P16)

v3.1's access mesh returned a bare verdict. That leaves field masking and row filtering to every caller — the exact drift the critique flags (Scenario 7: "API allows, UI hides field, API still leaks it"). v3.2 extends the decision to carry obligations the gateway/service enforces server-side.

// @projexlight/sdk-policy — EvaluatePolicyResult, v3.2
export interface EvaluatePolicyResult {
  decision: 'ALLOW' | 'DENY';
  reason: string;
  layers_used: string[];
  projection_version: number;
  cached: boolean;
  obligations?: {                          // ← v3.2
    mask_fields?: string[];                // e.g. ['ssn','profit_margin'] — redacted server-side
    row_filter?: Record<string, unknown>;  // e.g. { tenant_id, region: ['US','EU'] }
    audit_level?: 'standard' | 'sensitive_access';
    ttl_seconds?: number;                  // decision cache lifetime
  };
}
OC-11 (new constraint). Every read handler over governed data applies obligations through the shared enforcement helper before serialization; every mutation honors audit_level. Lint-enforced: a handler that reads an obligation-bearing decision but serializes the raw row is a CI failure. UI visibility is advisory; the wire is shaped by obligations.

11A.4 · The minted Platform Principal Token v3.2 (P17)

The resolved IdentityContext is already ProjexCloud's normalized subject identity. v3.2 has the gateway mint a signed, short-TTL, audience-bound token from it for east-west calls, so no downstream service ever trusts a forwarded header or a raw external claim.

// Minted by api-gateway after resolveIdentityContext(); verified by every service
{
  "sub": "platform-principal:person:p_123",
  "auth_assurance": "mfa",
  "app_id": "healthcare", "tenant_id": "hospital-a", "bu_id": "...",
  "root_tenant_id": "...", "reseller_id": "...",
  "persona_ids": ["persona_doctor_..."],
  "effective_scopes": ["chart:read"],
  "aud": "platform-services",       // audience-bound — not replayable elsewhere
  "iss": "projexcloud-gateway",
  "exp": 900                         // short TTL; re-mint on refresh
}

Services verify iss/aud/exp and the signature, then read the principal — they never re-derive identity from user-supplied input. (When the service mesh of §11A.6 lands, this token rides on top of mTLS workload identity; until then it is the sole internal trust anchor.)

11A.5 · Consent as a gating decision input v3.2 (P18)

sdk-consent already owns purpose registry, grants, receipts, and cross-border checks, and active consents already surface in IdentityContext.active_consents. v3.2 wires that receipt into the access decision as a first-class, purpose-gated input: for a purpose-bound resource, a missing or revoked receipt is a DENY with reason consent_absent — it fails closed. Consent remains distinct from authorization: a doctor may be authorized to read a chart for treatment yet have no consent to use it for marketing.

11A.6 · Fail-closed PDP & audited break-glass v3.2

11A.7 · Deferred by design — and why

These are recorded so "deferred" is never mistaken for "missed." Each is optional for ProjexCloud's stack and stage; rationale and the facts that would flip each are in the Reality Report v2 §8.
DeferredWhy it's optional todayFlips to necessary when…
SPIFFE/SPIRE + mTLS service mesh + gRPCApp-layer zero-trust (minted principal + JWT + RLS + Pool Router + lint boundaries) is a legitimate architecture; a mesh is an infra program, not a missing feature.Topology becomes many polyglot services on untrusted paths, or a buyer requires literal workload-identity attestation.
NATS/JetStream command bus + TemporalOne Kafka "reality log" is the disciplined choice; adding three infra systems multiplies ops burden without a concrete need.A specific long-running durable saga or internal command/control pattern Kafka+HTTP can't serve cleanly appears.
Probabilistic / AI-jury / steward-gated MDMProjexCloud's job is deterministic canonical IDs within tenants; fuzzy cross-system resolution + calibration is a large product bet.Resolving the same real-world person across independent systems ("is this the same patient?") becomes a committed use case.
Literal OPA/Cedar runtime · OpenLineage/OCSF formatsThe Cedar-shape evaluator and hash-chained audit/lineage already meet the control objective.A due-diligence buyer contractually requires the named engine or wire format — then add a translation/export adapter, don't re-platform.
Deferred ≠ denied — and the risk is conditional, not zero. Each row above carries no material architectural risk for the current target topology — that is a statement about today's shape, not an absolute. A deferred item has a lifecycle: Deferred (no trigger in sight) → Planned (the expected multi-year topology makes the trigger likely, so it earns a roadmap slot and a thin abstraction seam before implementation) → Required (trigger fires; build now). Of the four, service identity (SPIFFE/SPIRE) is by far the most likely to graduate from Deferred to Planned as service count, cross-cluster, or multi-cloud deployment grows — which is exactly why §11A.9 adds the 3-year-horizon decision (D-3). Probabilistic MDM is next-most-likely (on a committed regulated vertical); the command bus and the literal OPA/Cedar runtime are the least likely to graduate without a very specific trigger.

11A.8 · Resource Ownership Registry v3.2

The most grounded concern in gaps/Analyze1.md: infrastructure resources — droplets, clusters, databases, buckets, registries, Kafka topics — get created and deleted with no clear owner. Without ownership, platform security and cost control are impossible. v3.2 makes ownership a hard precondition for provisioning, reconciled through GitOps.

// platform.resource_registry — every provisioned resource has exactly one row
{
  "resource_id": "rds-hospital-a-app-pool-03",
  "type": "postgres" | "k8s_cluster" | "bucket" | "kafka_topic" | "registry" | "vm" | "droplet",
  "environment": "prod" | "staging" | "dev",
  "owner": "person_id_of_accountable_human",
  "team": "platform-data",
  "repo": "git@…/infra-pools",
  "terraform_module": "modules/app-pool",
  "cloud_account": "aws-prod-2",
  "cost_center": "CC-4471",
  "data_classification": "restricted" | "confidential" | "internal" | "public",
  "network_zone": "corp_vpn" | "public_edge" | "isolated",
  "created_by": "…", "approved_by": "…",
  "created_at": "2026-06-14T…", "expires_at": "2026-12-31T…" | null
}
OC-12 (new constraint). No infrastructure resource serves traffic until it has a resource_registry row with a non-null owner and approved_by. The GitOps reconciler (Terraform/OpenTofu state diff) quarantines orphan resources — anything live but unregistered, or registered but past expires_at — and raises an ownership alert. Rule: no owner = no resource. Break-glass provisioning routes through sdk-approval and back-fills the row within the audit window.

This is an operations/GitOps program, not an application SDK — it sits beside the platform rather than inside it. A thin sdk-resource-registry read API can surface ownership to the admin app, but the source of truth is GitOps-managed infrastructure state.

11A.9 · Open strategic decisions that gate the deferrals v3.2

The §11A.7 items are deferred not because they're hard but because they depend on business decisions not yet made. Recording them here makes each deferral a conscious "pending decision X," not an oversight. These are the decisions the Reality Report, gaps/Analyze3.md, and the gaps/Analyze4.md follow-up all leave open because engineering cannot answer them alone. D-1 and D-2 decide whether a deferred item becomes Required; D-3 decides whether it should be promoted to Planned ahead of that trigger.

#Decision (owner: product/leadership)OptionsWhat it unlocks / forces
D-1Which regulated verticals are committed for the next 2–3 quarters?Healthcare · Insurance · FinServ · Real-estate · Internal-tooling-onlyA committed regulated vertical makes P18 consent-gating mandatory and can make probabilistic MDM (§11A.7) a required capability rather than a deferred one. Internal-tooling-only keeps both optional.
D-2What is the final runtime topology?A: Gateway → SDKs → DB (current). B: Gateway → 100+ microservices → service mesh.Topology A keeps the minted Principal Token (§11A.4) as a sufficient internal trust anchor and leaves SPIFFE/mTLS mesh · gRPC · NATS · Temporal deferred. Topology B makes the Trust-Plane service mesh necessary, not optional.
D-3What is the expected 3-year topology & scale — independent of today's shape?Small: 10–20 services · single cloud · single region. Large: 200+ services · multi-region · multi-cloud · partner-hosted.The Small answer keeps all four §11A.7 items Deferred. The Large answer promotes service identity (SPIFFE/SPIRE) from Deferred → Planned now — it earns a roadmap slot and an abstraction seam, even though implementation still waits on D-2. Architecture roadmaps should anticipate likely evolution, not just today's need.
Build order, once decisions land. Independent of D-1/D-2/D-3, the always-necessary upgrades ship first: P16 obligations (§11A.3, highest leverage), the minted Principal Token (§11A.4), fail-closed + break-glass (§11A.6), and the resource registry (§11A.8). P18 consent-gating ships the moment D-1 names a regulated vertical. Items the D-3 horizon marks Planned (most plausibly the service mesh) get a roadmap slot and a thin abstraction seam now; their implementation still waits on D-2. The mesh and probabilistic MDM become Required only on D-2 / D-1 respectively. This sequence moves six of the critique's ten stress-test scenarios green before any infra program starts.

11A.10 · D-1 provisional resolution — Healthcare vertical (multi-source patient data) v3.2

Status: provisional. A healthcare client exists and a healthcare vertical is likely (not yet hard-committed). Recorded here so the roadmap reflects it; promote to firm on commit. The key scoping fact is settled: patient records originate from multiple independent sources (external hospitals / labs / HIEs / payers via HL7/FHIR) where the same real person arrives with no shared ID. That fact fires D-1 and — because of multi-source — also makes probabilistic identity resolution (an EMPI) a genuine requirement, not a speculative one.
CapabilityState for the healthcare pathDriver
Consent / purpose-of-use gating (P18)Required — regulatoryHIPAA treatment/payment/operations model + 42 CFR Part 2 segmented consent for substance-use records.
Obligations / field-level masking (P16, OC-11)Required — regulatoryHIPAA "minimum necessary" disclosure standard — server-side field masking + row filtering.
Probabilistic MDM / EMPIRequired (was Deferred)Multi-source patient matching; duplicate/overlaid records are a patient-safety and billing-integrity hazard.
Minted Principal Token (P17) + audit attributionStrongly recommendedHIPAA Security Rule audit controls — clean "who accessed which PHI, why." Audit already exists (sdk-audit); token sharpens service-hop attribution.
Durable workflow (Temporal)Planned — pending scopingGraduates from Deferred only if prior-authorization / referral workflows (multi-day, stateful, human-in-loop) are in scope.
Service mesh (SPIFFE/SPIRE)Still DeferredHealthcare is a regulatory trigger (D-1), not a topology one. Moves only on D-2/D-3, not on a single client.
Literal OPA/Cedar runtimeStill DeferredAuditors require explainability/consistency, not the engine name.

EMPI design note (extends sdk-identity-resolver)

The EMPI is the one large (L) build and must be its own workstream — in healthcare a false merge exposes the wrong patient's PHI and a false split fragments a record, so it is regulated-grade. It adds, behind the existing resolver interface: deterministic + probabilistic matching (name · DOB · address · phone · external IDs), confidence scores, a POSSIBLY_SAME candidate-link state (never a forced merge), a steward review queue (sdk-approval-governed adjudication), merge / unmerge as reversible compensating events (no destructive deletes), and match-quality calibration monitoring. Downstream systems continue to store the canonical ID — they never carry raw identity truth.

Already covered for HIPAA (no new build): envelope encryption + 7-tier crypto-shred erasure (sdk-vault), DSAR / right-to-erasure + certificate (sdk-data-rights), consent receipts (sdk-consent), tamper-evident audit with retention classes (sdk-audit), per-field PHI encryption (sdk-profile + vault). The healthcare-specific net-new work is the three Required rows above (EMPI, consent-gating, obligations).

11A.11 · Coverage map — analysis gaps → status → backlog v3.2

Every concern raised across gaps/Analyze1.mdAnalyze4.md, mapped to its current disposition. Read honestly: Shipped = implemented in the 91-package build today; Designed + Backlogged = design committed here (v3.2) and scheduled as Projexlight work, not yet merged code; Deferred = consciously deferred against a named decision (§11A.9).

Concern (source)StatusWhere / backlog
Five-identity separation (A2)ShippedSix-layer model §7 · §11A.2
Multi-tenant · pools · reseller hierarchy (A1/A2)Shipped§8 · §12
ABAC + ReBAC central PDP (A2)Shipped§11 access mesh
One event backbone — Kafka (A2)Shipped§11A.1 · P2
Tamper-evident audit / trace / lineage (A2)Shippedsdk-audit/sdk-trace/sdk-lineage
Obligations: mask / filter / TTL (A2/A3)Designed + Backlogged§11A.3 + OC-11 · P10·E1 (TK-3499–3504)
Minted Platform Principal Token (A2/A3)Designed + Backlogged§11A.4 + P17 · P10·E2 (TK-3505–3510)
Consent-gated authorization (A2/A3)Designed + Backlogged§11A.5 + P18 · P10·E3 (TK-3511–3516)
Fail-closed PDP + break-glass (A2)Designed + Backlogged§11A.6 · P10·E4 (TK-3517–3520)
Resource ownership registry (A1/A3)Designed + Backlogged§11A.8 + OC-12 · P10·E5 (TK-3521–3524)
Probabilistic MDM / EMPI (A2/A3 + Healthcare)Designed + Backlogged (Required)§11A.10 · P10·E6 (TK-3525–3534)
Non-breaking integration & regression hardeningDesigned + BackloggedP10·E7 (TK-3535–3540)
Observability taxonomy + telemetry portal (A2 §3.11)Designed + Backlogged§11A.1 · P10·E8 (TK-3541–3548)
Context fields: device / network-zone / purpose (report §7.10)Designed + BackloggedP10·E9 (TK-3549–3551)
Service mesh · SPIFFE/SPIRE · gRPC (A1/A2)Deferred§11A.7/§11A.9 · gated on D-2/D-3
NATS/JetStream command bus + Temporal (A2)Deferred§11A.7/§11A.9 · gated on D-2
Literal OPA/Cedar runtime · OpenLineage/OCSF (A2)Deferred§11A.7 · optional, on customer requirement
Bottom line. Of everything raised across the four analyses, the platform is either Shipped (the identity/access/evidence/event spine), Designed + Backlogged as P10 work (the six platform-hardening gaps + healthcare EMPI + observability/context), or Deferred by design (mesh / command-bus / engine-swap) against an explicit decision. Nothing remains undocumented or unscheduled — but the blue rows are committed work, not running code until P10 lands and Epic E7 proves no existing SDK regressed.

12 · Tenancy & Verticals

Two orthogonal axes. Tenant = a customer organization (Shantam, Kiana, Harmony Wellness, ContractorCo, Hospital A). Vertical = a productized domain bundle (Seva, Realty, Music, BidWork, LeadPulse, FieldOps, Healthcare, eCommerce, OneEstate). One tenant subscribes to one or more verticals; one vertical serves many tenants.

flowchart TB
  classDef plat fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef vert fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef ten fill:#241622,stroke:#ff6b6b,color:#e6ecf5;

  subgraph COMMON["projex_common · horizontal capabilities + HDK + Pool Router"]
    direction LR
    IDS["Identity"]:::plat
    POOL["Pool Router"]:::plat
    PAY["Payment"]:::plat
    GEO["Map/Geo"]:::plat
    DSP["Dispatch"]:::plat
    AGW["AI Gateway"]:::plat
    ELSE["…29 services · 12 agents · 10 HDK modules"]:::plat
  end

  subgraph SEVA["Seva"]
    DON["Donation"]:::vert
  end
  subgraph REALTY["Realty"]
    PROP["Property · Visit"]:::vert
  end
  subgraph FIELDOPS["FieldOps"]
    STM["Storm Estimation"]:::vert
    CTR["Contractor Settlement"]:::vert
  end
  subgraph MUSIC["Music"]
    CAT["Catalog · Rights"]:::vert
  end
  subgraph HC["Healthcare · new"]
    CHART["Chart · Rx · Care plan"]:::vert
  end
  subgraph EC["eCommerce · new"]
    ORD["Order · Cart · Catalog"]:::vert
  end

  T1["Shantam"]:::ten
  T2["Kiana"]:::ten
  T3["ContractorCo"]:::ten
  T4["Hospital A"]:::ten
  T5["BookStore"]:::ten

  T1 --> SEVA
  T2 --> REALTY
  T3 --> FIELDOPS
  T4 --> HC
  T5 --> EC

  SEVA --> COMMON
  REALTY --> COMMON
  FIELDOPS --> COMMON
  HC --> COMMON
  EC --> COMMON
  MUSIC --> COMMON
    

12.1 · Isolation tiers

Tier S · Standard
Shared admin + app pools · RLS within pool
Default for SMB tenants and pilots. Many tenants per pool; RLS by tenant_id within pool.
Tier P · Premium
Shared admin pool · dedicated app schema
Same shared admin pool, dedicated schema within the shared app pool. Custom retention or larger workloads. Migration path: dump rows → schema → flip routing.
Tier G · Governed
Dedicated app pool · optional region · per-tenant KMS
For FCRA / HIPAA / RBI-regulated tenants, contractor compliance workflows, white-label flagships. Tenant has its own app pool (or evidence pool) in a chosen region.

12.2 · Resolution path

flowchart LR
  classDef edge fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;
  classDef gw fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef svc fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef store fill:#241622,stroke:#ff6b6b,color:#e6ecf5;

  USER(["Browser · RN · Kiosk"]):::edge
  CDN["CDN"]:::edge
  GW["API Gateway · Kong
resolves tenant_id + vertical_id"]:::gw TEN["Tenant Mgmt
plan · tier · region · modules · pool indices"]:::svc IDP["Identity
JWT carries six-layer tuple"]:::svc POOL["Pool Router
tenant_id + app_id → dsn"]:::svc SVC["Common service
routed query against one pool"]:::svc PG[("Postgres pool · RLS within")]:::store RC[("Redis · routing cache")]:::store USER --> CDN --> GW GW --> TEN GW -->|JWT| IDP GW --> POOL POOL --> RC POOL --> SVC SVC --> PG

13 · Workspace Layout

A single pnpm + turbo workspace under projex_common/. Every service, agent, package, and HDK module is its own workspace member.

projex_common/
├── README.md
├── package.json
├── pnpm-workspace.yaml
├── turbo.json
├── tsconfig.base.json
│
├── docs/
│   ├── Architecture.html                   ← v1 (historical)
│   ├── Architecture-v2.html                ← v2 (historical)
│   ├── v3/Architecture-v3.html             ← v3 (AIM only)
│   ├── v3.1/Architecture-v3.1.html         ← THIS · canonical
│   ├── v3.1/SDK-Build-Plan-v3.1.html
│   ├── v3.1/AIM-Identity-Model-v3.1.html
│   ├── Common-Services-and-Agents.md
│   ├── Data-Design.md
│   └── Data-Request-Manifests.md
│
├── packages/                               ← TS/JS packages
│   ├── contracts/                @projexlight/contracts
│   ├── sdk-pool-router/          @projexlight/sdk-pool-router    ← v3 NEW
│   ├── sdk-secrets/              @projexlight/sdk-secrets
│   ├── sdk-vault/                @projexlight/sdk-vault
│   ├── sdk-audit/                @projexlight/sdk-audit
│   ├── sdk-tenant/               @projexlight/sdk-tenant
│   ├── sdk-identity/             @projexlight/sdk-identity
│   ├── sdk-consent/              @projexlight/sdk-consent
│   ├── sdk-policy/               @projexlight/sdk-policy
│   ├── sdk-rebac/                @projexlight/sdk-rebac           ← v3 NEW
│   ├── sdk-profile/              @projexlight/sdk-profile
│   ├── sdk-persona/              @projexlight/sdk-persona         ← v3 NEW
│   ├── sdk-device/               @projexlight/sdk-device
│   ├── sdk-geo/                  @projexlight/sdk-geo
│   ├── sdk-feature-flags/        @projexlight/sdk-feature-flags
│   ├── sdk-media/                @projexlight/sdk-media
│   ├── sdk-notification/         @projexlight/sdk-notification
│   ├── sdk-payment/              @projexlight/sdk-payment
│   ├── sdk-workflow/             @projexlight/sdk-workflow
│   ├── sdk-search/               @projexlight/sdk-search
│   ├── sdk-crm/                  @projexlight/sdk-crm
│   ├── sdk-engagement/           @projexlight/sdk-engagement      ← v3 NEW
│   ├── sdk-content/              @projexlight/sdk-content
│   ├── sdk-service-request/      @projexlight/sdk-service-request
│   ├── sdk-event/                @projexlight/sdk-event
│   ├── sdk-campaign/             @projexlight/sdk-campaign
│   ├── sdk-social/               @projexlight/sdk-social
│   ├── sdk-ai-gateway/           @projexlight/sdk-ai-gateway
│   ├── sdk-taxonomy/             @projexlight/sdk-taxonomy
│   ├── sdk-knowledge-rag/        @projexlight/sdk-knowledge-rag
│   ├── sdk-parsing/              @projexlight/sdk-parsing
│   ├── sdk-agent-runtime/        @projexlight/sdk-agent-runtime
│   ├── sdk-conversation/         @projexlight/sdk-conversation
│   ├── sdk-recommendation/       @projexlight/sdk-recommendation
│   ├── sdk-analytics/            @projexlight/sdk-analytics
│   ├── sdk-storm/                @projexlight/sdk-storm
│   ├── sdk-dispatch/             @projexlight/sdk-dispatch
│   ├── sdk-assignment/           @projexlight/sdk-assignment
│   ├── sdk-lead-scoring/         @projexlight/sdk-lead-scoring
│   ├── sdk-evidence/             @projexlight/sdk-evidence
│   ├── sdk-diagnostic-telemetry/ @projexlight/sdk-diagnostic-telemetry
│   ├── design-system/            @projexlight/design-system
│   ├── i18n/                     @projexlight/i18n
│   ├── branding/                 @projexlight/branding
│   ├── config/                   @projexlight/config
│   └── telemetry/                @projexlight/telemetry
│
├── native/                                 ← HDK native modules
│   ├── hdk-map · hdk-camera · hdk-idp · hdk-permissions · hdk-scanner
│   ├── hdk-image-editor · hdk-video-editor · hdk-measure
│   ├── hdk-watermark · hdk-diagnostic
│
├── services/                               ← horizontal microservices (29 + pool-router service)
│   ├── identity · tenant-management · user-profile · persona · engagement
│   ├── payment · notification · crm · service-request · content
│   ├── course · event · campaign · social-ingestion · analytics
│   ├── search · media · workflow · audit · ai-gateway
│   ├── knowledge-rag · conversation · recommendation · feature-flags
│   ├── map-geo · storm · dispatch · assignment · lead-scoring
│   ├── field-ops-evidence · diagnostic-telemetry · pool-registry
│
├── agents/                                 ← 12 horizontal agents (unchanged)
│
└── infra/
    ├── helm/ · terraform/ · k8s/

14 · Layered View

14.1 · Top-level stack

flowchart TB
  classDef ch fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;
  classDef gw fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef common fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef vert fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef ag fill:#241622,stroke:#ff6b6b,color:#e6ecf5;
  classDef hdk fill:#1d1830,stroke:#b88dff,color:#e6ecf5;
  classDef aim fill:#241622,stroke:#b88dff,color:#e6ecf5;

  subgraph L1["1 · Channels"]
    SW["Seva · Realty · Music · FieldOps · Healthcare · eCommerce apps"]:::ch
  end
  subgraph LHDK["2 · HDK — device-side"]
    HDK["10 native modules"]:::hdk
  end
  subgraph LGW["3 · Edge & Gateway"]
    GW["Kong API Gateway · per-vertical BFFs"]:::gw
  end
  subgraph LAIM["4 · AIM Foundation · v3"]
    AIM["Identity · Tenant · Pool Router · Persona · Engagement · ReBAC · Policy · Vault"]:::aim
  end
  subgraph LSVC["5 · Common Services"]
    SVC["29 horizontal services across 6 clusters"]:::common
  end
  subgraph LVERT["6 · Vertical Services"]
    VS["Seva · Realty · Music · FieldOps · Healthcare · eCommerce vertical services"]:::vert
  end
  subgraph LAG["7 · Agents"]
    AGN["12 horizontal agents"]:::ag
  end

  L1 --> LHDK --> LGW --> LAIM --> LSVC --> LVERT
  LAG -.calls.-> LAIM
  LAG -.calls.-> LSVC
  LAG -.calls.-> LVERT
  LSVC -.events.-> LAG
  LVERT -.events.-> LAG
    

14.2 · Common Services clusters

flowchart LR
  classDef cluster fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef new fill:#1d1830,stroke:#b88dff,color:#e6ecf5;

  subgraph IDT["Identity, Tenancy & AIM"]
    A1["Identity"]:::cluster
    A2["User Profile"]:::cluster
    A3["Tenant Mgmt"]:::cluster
    A4["Feature Flags"]:::cluster
    A5["Pool Router · v3"]:::new
    A6["Persona · v3"]:::new
    A7["Engagement · v3"]:::new
    A8["ReBAC · v3"]:::new
  end
  subgraph ENG["Engagement"]
    B1["CRM"]:::cluster
    B2["Service Request"]:::cluster
    B3["Notification"]:::cluster
    B4["Campaign"]:::cluster
    B5["Social Ingestion"]:::cluster
  end
  subgraph CCM["Commerce · Content · Media"]
    C1["Payment"]:::cluster
    C2["Content"]:::cluster
    C3["Course"]:::cluster
    C4["Event"]:::cluster
    C5["Media"]:::cluster
    C6["Search"]:::cluster
  end
  subgraph OPS["Operations"]
    D1["Workflow"]:::cluster
    D2["Audit"]:::cluster
    D3["Analytics"]:::cluster
    D4["Diagnostic-Telemetry"]:::new
  end
  subgraph FLD["Geo · Dispatch · Evidence"]
    F1["Map / Geo"]:::new
    F2["Storm"]:::new
    F3["Dispatch"]:::new
    F4["Assignment"]:::new
    F5["Lead Scoring"]:::new
    F6["Field-Ops Evidence"]:::new
  end
  subgraph AIL["AI Layer"]
    E1["AI Gateway"]:::cluster
    E2["Knowledge / RAG"]:::cluster
    E3["Conversation"]:::cluster
    E4["Recommendation"]:::cluster
  end
    

14.3 · Platform spine & data plane

flowchart LR
  classDef plat fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;
  classDef data fill:#0f1422,stroke:#5dd39e,color:#e6ecf5;
  classDef use fill:#16241c,stroke:#5dd39e,color:#e6ecf5;

  subgraph SPINE["Platform Spine"]
    BUS["Kafka
envelope-wrapped events"]:::plat TMP["Temporal
durable workflows"]:::plat OBS["OTel · Grafana · Langfuse"]:::plat SEC["Secrets · KMS · HSM"]:::plat end subgraph DATA["Data Plane · per pool"] PG[("Postgres pool · per service per pool")]:::data RD[("Redis
cache · sessions · pool routing")]:::data OS[("OpenSearch
full-text")]:::data CHC[("ClickHouse
OLAP · cross-pool warehouse")]:::data S3[("S3
media · evidence")]:::data VEC[("pgvector / Pinecone
embeddings")]:::data POSTGIS[("PostGIS
bbox · routing")]:::data end CONS["Common & vertical services"]:::use AGENTS["Agents"]:::use HDK["HDK modules · device"]:::use CONS -- emit/consume --> BUS HDK -- emit --> BUS CONS -- run --> TMP CONS --> PG CONS --> RD CONS --> OS CONS --> CHC CONS --> S3 CONS --> VEC CONS --> POSTGIS CONS -.metrics/logs/traces.-> OBS CONS -.fetch keys.-> SEC AGENTS -- consume --> BUS

15 · Worked Scenarios

End-to-end flows showing how pools, identity layers, encryption, and the access mesh compose.

Scenario A

Healthcare — patient across multiple hospitals, doctors, admissions

Ravi sees three doctors at Hospital A and one specialist at Hospital B, has two admissions at A and one outpatient visit at B.

Identity instantiation

  • L1 · one person_id = pers_ravi encrypted under his person key.
  • L2 · one app_identity for Healthcare, in his home-region admin pool.
  • L3 · two tenant_membership rows (one per hospital), each encrypted under that hospital's tenant key.
  • L4 · two Patient personas — chart roots in app-healthcare-007 and app-healthcare-002.
  • L5 · six encounters — three OP at A, two admissions at A, one OP at B. Each has its own encounter key.
  • L6 · four relationships — three PCP at A, one specialist at B.

Pool topology

person:            admin-india-007 (home)
app_identity:      admin-india-007
hospital_a:
  membership · persona (identity): admin-014
  chart, encounters:                app-healthcare-007
  evidence (scans):                 evidence-002
hospital_b:
  membership · persona (identity): admin-021
  chart, encounters:                app-healthcare-002
  evidence (scans):                 evidence-004

Access scenarios

  • Dr. Smith @ A reads Ravi's A chart — ABAC ✓, ReBAC PCP active ✓ → allowed.
  • Dr. Smith @ A reads Ravi's B chart — no cross-tenant relationship → denied, audited.
  • Ravi grants Hospital A read of his B records → cross-tenant relationship + consent → re-encryption proxy serves the data.
  • ER nurse gets time-bound vitals grant for one admission → expires at discharge.
  • Ravi requests DPDP erasure → Person Key shredded → every encounter at every hospital becomes mathematically irrecoverable.
  • 2019 outpatient retention expires → that one encounter key shredded → row remains for counts, payload irrecoverable.
Scenario B

eCommerce — one shopper across five stores

Anita registers at BookStore, ElectroMart, GroceryNow, FashionHub, GardenShed — five tenants in the eCommerce app.

  • L1 · one person_id = pers_anita.
  • L2 · one App Identity (eCommerce).
  • L3 · five tenant memberships, each in respective tenant's admin pool.
  • L4 · five Buyer personas.
  • L5 · many encounter rows (orders, returns).
  • L6 · loyalty relationships at two stores.

BookStore cannot see ElectroMart purchases. Aggregating Anita's spend across stores requires her cross-tenant consent and goes through the warehouse — never live cross-pool reads.

Scenario C

OneEstate — one investor, many funds, many properties

Suresh invests in three funds run by KianaRealty.

  • L1 · one person_id; L2 · OneEstate App Identity.
  • L3 · one tenant membership in KianaRealty.
  • L4 · three Investor personas — one per fund. Persona-extension data: K-1s, cap calls, distributions in app-onestate.
  • L5 · encounters: subscription, cap-call, distribution events.
  • L6 · advisor relationship.

Three personas in one membership keep per-fund reporting tidy without inventing fake sub-tenants.

Scenario D

Cross-domain — one human, eight apps

Priya is a doctor, yoga student, donor, investor, shopper at four stores, homeowner, and HR employee at her own clinic.

  • L1 · 1 master person. L2 · 7 App Identities. L3 · ~10 tenant memberships. L4 · one persona per membership (dual at her clinic). L5 · hundreds of encounters. L6 · ~20 active relationships.
  • One login → JWT carries person_id → as she opens each app, App Identity / Membership / Persona resolve locally. No app sees another's data without consent.

16 · Common Services Catalogue

29 horizontal services (v2 baseline) + 4 AIM services introduced by v3. Each owns its data, exposes a versioned HTTP API, emits envelope-wrapped events, and is consumed by every vertical that needs the capability.

16.1 · Drop-in services (zero-change reuse)

#ServiceOwnsKey APIsTier
1Identityidentity_db · admin poolOIDC · /authorize · /tokenP1
2Tenant Mgmttenant_db · admin poolPOST /v1/tenants · /modulesP1
3Pool Router v3pool_registryGET /v1/pool/route · /v1/pool/migrateP1
4User Profileprofile_db · L2 bandsGET/PUT /v1/profiles/:idP1
5Persona v3persona_db · L2/L3/L4POST /v1/persona/membership · /v1/persona/stackP1
6Engagement v3engagement_db · L5/L6POST /v1/engagement/encounters · /grants · /relationshipsP1
7ReBAC v3rebac_dbPOST /v1/rebac/check · /relationshipsP1
8Paymentpayment_dbPOST /v1/payments · /refundsP1
9Notificationnotif_dbPOST /v1/notifications/sendP1
10Mediamedia_db + S3POST /v1/media/upload-urlP1
11Auditaudit_db per poolGET /v1/audit · /exportP1
12Feature Flagsflags_dbGET /v1/flagsP1
13SearchOpenSearch indexes per poolGET /v1/searchP2
14WorkflowTemporal + wfl_dbPOST /v1/workflows/:typeP3
15AnalyticsClickHouse warehouse · cross-poolGET /v1/funnel · /kpi · /cohortP3
16AI Gatewayai_dbPOST /v1/ai/complete · /chat · /embedP4
17Knowledge / RAGknowledge_db + vectorPOST /v1/rag/index · /queryP4
18Conversationconv_dbPOST /v1/conversationsP4
19Recommendationrecs_dbGET /v1/recs/:user_idP4
20Map / Geogeo_db + PostGISGET /v1/geo/property/:id · /bbox · /clusterP2
21Stormstorm_db + PostGISGET /v1/storm/active · /overlay · /intensityP2
22Dispatchdispatch_dbGET /v1/dispatch/queue · WS /v1/dispatch/liveP2
23Assignmentassign_dbPOST /v1/assign/auto · GET /v1/agents/nearbyP3
24Lead Scoringscore_dbPOST /v1/score/calculate · /score/lead/:idP3
25Field-Ops Evidenceevidence_db + S3POST /v1/evidence/upload · GET /v1/evidence/:idP2
26Diagnostic-Telemetrydiag_dbPOST /v1/telemetry/crash · /telemetry/sessionP3

16.2 · Generalize-then-share (Rule of Three)

ServiceGeneralization neededPromotion trigger
CRMNeutral Contact + Lead entities keyed by persona_id; per-vertical custom_fields JSONBSeva + Realty + FieldOps in production
Service RequestTenant-configurable category + routing_rules3rd vertical needs ticketing
ContentGeneric typed-content with tenant taxonomies3rd vertical with content needs
CourseGeneric; keep schemas vertical-agnostic2nd vertical adopts
EventGeneric; ticketing / QR / check-in agnostic2nd vertical adopts
CampaignGeneric segment DSL over events3rd vertical needs journeys
Social IngestionPluggable connectors; common social.lead.captured3rd vertical with social leads
Calendar / AppointmentsGeneric resource-booking over property/agent/slot — now expressed as Engagement3rd vertical needs booking

16.3 · On-device AI policy

CapabilityWhereWhy
QR · Barcode · AprilTag detectionOn-device (hdk-scanner)Latency < 50ms; never leaves device
Scene contextOn-device (hdk-camera)Capture buffer never uploaded raw
Image auto-correctOn-device (hdk-image-editor)Works offline; instant preview
AR length measurementOn-device (hdk-measure)Millisecond latency
Roof / property AI from imageryCloud AI GatewayHeavy model + map tiles
Sentiment / lead scoringCloud AI GatewayCross-tenant signals
Transcription · summarizationCloud AI GatewayLong-form + redaction policy

17 · Permission Architecture (three layers)

Three independent layers, each enforced at a different boundary. A request only succeeds if all three say yes. Symmetric between web and mobile — only the enforcement points differ. v3 integration: Layer 2 now consults the full ABAC + ReBAC + Encounter Grants mesh, not just role checks.

flowchart TB
  classDef l1 fill:#0f1422,stroke:#6aa9ff,color:#e6ecf5;
  classDef l2 fill:#16241c,stroke:#5dd39e,color:#e6ecf5;
  classDef l3 fill:#241622,stroke:#ff6b6b,color:#e6ecf5;
  classDef store fill:#1a2234,stroke:#c9a86a,color:#e6ecf5;

  subgraph LAY1["Layer 1 · App consent"]
    C["Tenant consent + module subscription"]:::l1
  end
  subgraph LAY2["Layer 2 · Access Mesh · v3"]
    R["ABAC + ReBAC + Encounter Grants"]:::l2
  end
  subgraph LAY3["Layer 3 · Device permissions"]
    D["OS-level permissions"]:::l3
  end

  RC[("Redis permission cache")]:::store
  DEV[("On-device permission cache")]:::store

  C --> R --> D
  R -. fetches .-> RC
  R -. syncs .-> DEV
    
LayerEnforced atWhat it checksFailure mode
App consentTenant Mgmt + Feature FlagsModule subscribed? User accepted consent?403 module_not_enabled / consent_required
Access meshPolicy + ReBAC + Encounter GrantsABAC structural + ReBAC longitudinal + Encounter time-bounded403 forbidden — backend-driven
Device permissionhdk-permissions (mobile) / browser API (web)OS access to camera / GPS / biometricForce-permission flow → deep-link

17.1 · Offline behavior

18 · Common AI Agents

Twelve agents that subscribe to platform events and call platform APIs. Tenant-scoped, budget-capped, audited. v3: every agent action now resolves through ABAC + ReBAC; agents acting on behalf of a persona must respect relationships and encounter grants.

AgentTriggersCallsOutcome
Engagementidentity.user.registered · cronNotification · Content · Course · RecommendationPersonalized nudges per persona.
CRM Intelligencecrm.lead.captured · lead.scored.v1CRM · AI Gateway · AnalyticsLead scoring, NBA, follow-up prioritization.
Campaign Optimizercampaign.launched · daily metricsCampaign · Analytics · AI GatewaySend-time tuning, segment refinement.
Support Resolutionsr.opened · sr.escalatedSR · Knowledge · NotificationSummarization, suggested replies, auto-escalation.
Content Intelligencecontent.published · media.readyContent · Knowledge · SearchAuto-tagging, summaries, embeddings.
Commerce Recommenderviews · cart.convertedCommerce · RecommendationUpsell, combos, similar-property.
Event Engagementevent.registered · T-24h, T-2hEvent · NotificationReminders, attendance prediction, follow-up.
Operations MonitorSLA breach · anomalySR · Workflow · Notification · Diagnostic-Telemetry · Pool RouterCatches fulfillment delays, crash spikes, pool capacity issues.
Executive IntelligenceDaily / weekly cronAnalytics · AI GatewayKPI digests, cohort trends.
Knowledge CuratorPeriodic · new docsKnowledge / RAG · AI GatewayQuality scoring, dedup, refresh.
Onboardingtenant.provisionedTenant · CRM · Notification · Workflow · Pool RouterWalks a new tenant through configuration; verifies pool assignment.
Cost & Safety Steward v3.1sdk-meter rollups · usage.softcap.warn · usage.hardcap.exceeded · daily cronsdk-meter · sdk-billing · sdk-notification · sdk-feature-flagsReads method-level usage across every SDK (not just AI). Recommends batching, caching, model downgrade, endpoint switches; can issue per-method kill switches via meter; opens a finance ticket for tenants approaching hard caps.
Every agent must: (1) accept a tenant_id and respect tier rules; (2) have a daily token + action budget; (3) be idempotent or compensable; (4) write to Audit on every state-changing call; (5) have a kill-switch in Feature Flags; (6) emit Langfuse traces; (7) call services only through typed SDKs; v3 (8) respect ABAC + ReBAC + Encounter Grants when acting on behalf of a persona.

18A · Agent Isolation Runtime v3.1

§18 lists the 12 platform agents. This section is the runtime that makes them safely deployable at scale. Without these four primitives — capability tokens, execution TTL, deterministic replay, sandboxed memory — a single prompt-engineering mistake leaks Tenant A's context into Tenant B's agent. The leak is catastrophic and irreversible.

Why a dedicated section. Architectural review (../../Analyze2.txt #5) flagged uncontained AI agents as one of the largest future risks: "prompt leakage · tenant contamination · runaway workflows · hallucinated actions · memory bleed become existential risks at enterprise scale." v3.1's answer is the Agent Isolation Runtime — four mandatory primitives every agent invocation must use.

18A.1 · The four primitives

Primitive 1
Capability Tokens
Every tool invocation by an agent requires a signed, scope-limited, single-use capability token issued by the runtime. The token names: which agent, which persona it acts for, which exact SDK method, which arguments are pre-bound, which tenant scope. Tools refuse invocation without a valid token. Tokens are minted at the moment of planning (not at agent boot) so scope is always current. Revocable mid-flight — meter ingests revocation and denies any subsequent emission referencing the token.
Primitive 2
Execution TTL
Every agent run has a hard deadline at start — typically 30s for synchronous calls, 5min for orchestrations, 1h for long-running planners. The runtime enforces: when the TTL expires, the agent is terminated, in-flight tools cancelled, partial state rolled back if marked compensable, and the user notified. "Runaway agent" is impossible by construction. TTLs are per-agent class and can be tightened per-tenant.
Primitive 3
Deterministic Replay
Every agent run produces a content-addressed execution log capturing: prompt template version + filled values, retrieved context, model invocation parameters, tool calls with token IDs and arguments, tool responses, final action. Replaying the log against the same model snapshot produces bit-identical outputs. This enables: rolling back an agent decision within the retention window (replay the prior log; undo any state changes); reproducing production bugs; verifying that a model upgrade didn't change agent behavior.
Primitive 4
Sandboxed Memory
Hard physical partitions per tenant in the vector store layer (Pinecone namespaces or dedicated pgvector schemas) — not just logical filters. Prompt context, vector store, conversation buffers never cross tenant boundaries. Cross-tenant prompt-leakage tests run on every PR that touches agent code; any leak fails the build. At hyperscale, dedicated vector clusters per Tier-G tenant.

18A.2 · The agent invocation flow

sequenceDiagram
  participant U as User
(persona) participant AGR as sdk-agent-runtime participant POL as sdk-policy + ReBAC participant CAP as Capability Issuer
(runtime internal) participant TOOL as SDK tool
(e.g., sdk-crm) participant MET as sdk-meter participant MEM as Sandboxed Memory
(tenant namespace) participant AUD as sdk-audit participant TRC as sdk-trace U->>AGR: Trigger agent (intent, persona_id, tenant_id) AGR->>POL: Check persona may invoke this agent POL-->>AGR: ALLOW AGR->>AGR: Start TTL clock (e.g., 30s) AGR->>MEM: Load tenant-scoped context (physical namespace) AGR->>AGR: Planner produces action plan loop For each planned tool call AGR->>CAP: Mint capability token (agent_id, tool, args, scope) CAP-->>AGR: signed token AGR->>TOOL: invoke(args, token) TOOL->>MET: gate.check(token, sku, tenant) MET-->>TOOL: ALLOW (token valid, in scope) TOOL->>TOOL: execute TOOL->>AUD: state change with token id + agent_chain TOOL-->>AGR: result end AGR->>AGR: Write execution log (content-addressed) AGR->>AUD: agent run complete (log hash, deterministic) AGR->>TRC: emit trace span across the whole run AGR-->>U: result Note over AGR: If TTL expires mid-loop: terminate, cancel
in-flight tools, rollback compensable steps

18A.3 · What this prevents

Failure modePrevented by
Prompt injection tricks an agent into calling a tool outside its scopeTool refuses invocation without a valid capability token; planner cannot mint a token for an out-of-scope SKU
Runaway agent loops indefinitely consuming budgetExecution TTL terminates it; meter refunds beyond-TTL usage
Hallucinated action that takes effect and can't be undoneDeterministic replay enables rollback within retention window; sdk-approval gates irreversible actions to human approval
Cross-tenant leak where Tenant A's vector context contaminates Tenant B's agentSandboxed memory uses physical (not logical) partitions; cross-tenant prompt-leakage CI test fails closed
Agent abusing delegation by acting as a higher-privileged personaCapability token names the actual persona; meter and audit record the agent_chain; ReBAC evaluates against the persona, not the agent
Model-upgrade regression changes agent behavior silentlyDeterministic replay verifies new model produces identical outputs for past logs; regressions surface in CI before promotion
Tool author adds an over-privileged toolTool manifest enumerates the SKUs it calls; meter enforces the manifest at the gate; agent cannot invoke a tool that exceeds its declared boundary

18A.4 · Operational requirements

Bottom line. The four primitives turn AI agents from "powerful but dangerous" to "deployable at enterprise scale with audit-grade containment." None of them are optional. They are the substrate that makes the platform's 12 agents — and any future tenant-defined agents — safe to ship.

19 · Contracts & Event Envelope

The contracts package @projexlight/contracts is the keystone. Every service, every agent, every vertical, every HDK module depends on it.

19.1 · Event envelope (v3.1)

{
  "tenant_id":      "uuid",
  "vertical_id":    "seva | realty | music | bidwork | leadpulse | fieldops | healthcare | ecommerce | common",
  "pool_index":     "app-healthcare-007",       // v3 · which pool produced this
  "event_id":       "uuid",
  "event_type":     "encounter.opened.v1",
  "occurred_at":    "2026-05-20T10:15:32Z",
  "actor": {
    "type":         "user | agent | system | tenant_admin | super_admin | hdk_device",
    "person_id":    "pers_...",                  // v3 · master person
    "persona_id":   "pers_...patient",           // v3 · which hat
    "id":           "...",
    "display_name": "..."
  },
  "encounter_id":   "enc_...",                   // v3 · when within an encounter scope
  "payload":        { ... },
  "schema_version": 1,
  "correlation_id": "uuid",
  "causation_id":   "uuid",
  "device": {
    "device_id":    "uuid",
    "platform":     "ios | android",
    "app_version":  "...",
    "online":       true
  }
}

19.2 · Versioning rules

20 · What Stays Vertical (do not lift)

These services stay in their respective verticals — lifting them would smuggle domain assumptions into Common.

VerticalServiceWhy it stays
SevaDonation80G / FCRA / Anushthan logic is regulator- and culture-specific.
SevaAcharya NetworkRitual matching, geography, skill taxonomy.
SevaAsk-Guruji AgentBound to single approved corpus.
RealtyPropertyListing schema, possession, RERA fields.
RealtyVisitSite-visit lifecycle — now expressed as Engagement of kind 'site_visit'.
RealtyDocument / e-signSale-deed semantics. May lift when 3rd vertical needs e-sign.
MusicCatalog · Rights · Licensing · PlaybackMusic-industry domain logic.
BidWorkBid · Auction · SettlementAuction mechanics.
LeadPulseChannel ConnectorsChannel-specific intake.
FieldOpsStorm Estimation · Contractor Settlement · Door-to-Door · YamunaInsurance, trade-specific, sales-rep canvassing logic.
Healthcare v3Chart · Rx · Care plan · Clinical decision supportSpecialty-specific clinical content, drug interactions, ICD/CPT coding.
eCommerce v3Catalog · Cart · Order workflow · RMAIndustry-specific catalog shape, fulfillment, returns rules.
Anti-pattern. Building a "Common Donation" service before any vertical besides Seva needs contributions. Same trap: a "Common Encounter Notes" with healthcare-specific shape before eCommerce / Realty also need it. Encounter as a primitive lifts cleanly (it's just open/in-progress/closed + key); domain payload doesn't.

21 · Adoption Playbook for a New Vertical

Step 1
Subscribe — don't fork
Provision a tenant in Tenant Mgmt. Mark subscribed Common modules. Pick an isolation tier. v3 Pool indices auto-assigned by allocation policy.
Step 2
Add only new domain services
For Wellness: Practitioner + Engagement-of-kind 'session'. For Healthcare: Chart + Rx. Keep them in vertical platforms. They emit vertical.*.v1 events.
Step 3
Declare personas & encounter kinds
v3 Register persona kinds (Patient, Provider) and encounter kinds (visit, admission) in @projexlight/contracts. Persona / Engagement SDKs auto-validate.
Step 4
Theme the shared frontends
Use @projexlight/design-system + @projexlight/branding. Don't fork.
Step 5
Embed the HDK
For mobile/kiosk verticals, install relevant HDK modules in dependency order. TS facades carry contracts; native modules carry device capabilities.
Step 6
Wire vertical agents
Reuse Common agents. Add only domain-specific ones and only when truly different.
Step 7
Earn promotion (Rule of Three)
If a 3rd vertical needs your domain primitive, generalize and promote to Common.

21.1 · Sample tenant manifest · Healthcare

tenant: hospital-a
vertical: healthcare
isolation_tier: governed         # Tier G for PHI
pool_assignment:
  admin_pool_index:    admin-014   # auto-assigned
  app_pool_index:
    healthcare:        app-healthcare-007   # dedicated for Tier G
  evidence_pool_index: evidence-002
  region:              ap-south-1
modules:
  identity: enabled
  pool_router: enabled
  persona: enabled
  engagement: enabled
  rebac: enabled
  profile: enabled
  payment: enabled
  notification: enabled
  audit: enabled
  feature_flags: enabled
  search: enabled
  workflow: enabled
  analytics: enabled
  media: enabled
  ai_gateway: enabled
  field_ops_evidence: enabled       # imaging captures
  diagnostic_telemetry: enabled
  # not used in healthcare
  storm: disabled
  donation: disabled
hdk:
  hdk_idp: enabled
  hdk_permissions: enabled
  hdk_diagnostic: enabled
  hdk_camera: enabled
persona_kinds:
  - patient
  - doctor
  - nurse
  - admin
encounter_kinds:
  - visit
  - admission
  - surgery
  - er_episode
  - outpatient
branding:
  primary: "#0ea5e9"
  logo: "hospital_a.svg"
  default_lang: "en"
deployment:
  android: standard
  ios: standard
  web: enabled

22 · Pool Lifecycle & Tenant Migration v3

22.1 · Pool states

StateMeaningRouting behavior
PROVISIONINGNewly created, schema initializing.Hidden from allocator.
ACTIVEHealthy, accepting new tenants.Default. Allocator pins new tenants.
DRAININGAt capacity or being retired.Existing OK; no new pins.
MAINTENANCESchema migration in flight.Reads OK; writes briefly paused.
QUARANTINEAnomaly detected.Routing rejected; incident response.
RETIREDAll tenants migrated out.Excluded except for audit.

22.2 · Tenant migration (Standard → Premium → Governed)

  1. Mark tenant MIGRATING. Router queues writes; live reads OK on source.
  2. Snapshot source pool's rows for this tenant. Encrypted backup to target.
  3. Replay queued writes against target until lag = 0.
  4. Atomic cutover: update tenant_pool_map, fan-out invalidate router caches.
  5. Mark tenant ACTIVE on target. Source rows tombstoned for delete after retention.
  6. Audit logs both pools across the cutover.

22.3 · Disaster recovery

22A · Deployment Variants v3.1

The default deployment is Projexlight-operated multi-tenant SaaS in our regional cloud. Enterprise and regulated buyers often need stricter variants. v3.1 documents four variants so the SDK estate is built with these constraints in mind — not retrofitted under sales pressure.

22A.1 · BYOK / CMEK — Customer-Managed Encryption Keys

Tenants who require their own KMS keys as a hard policy (regulated finance, healthcare networks, government suppliers) can plug their own KMS into the Vault key hierarchy.

22A.2 · Sovereign Cloud — FedRAMP / IL5 / China PIPL / EU sovereign

For workloads that cannot run on the default commercial regions: US Federal (FedRAMP High, IL5/IL6 for DoD), China PIPL (data-must-stay-in-China + Chinese cloud), EU sovereign (no US hyperscaler control plane), Russia data localization, Saudi/UAE data localization.

22A.3 · On-Prem / Air-Gapped Deployment

For banks, defense contractors, intelligence agencies, and a small set of regulated healthcare buyers, fully on-prem deployment is a hard requirement.

22A.4 · Active-Active Multi-Region (Tier-G+)

v3 defined Tier-G as warm replica + failover. Some buyers (global banks, payment networks, life-critical healthcare) require active-active — writes accepted in multiple regions simultaneously.

Why these variants matter for the build plan. Without these named upfront, the 54-SDK estate would bake in assumptions (cloud KMS only, hyperscaler control plane, phone-home telemetry, cross-region routing) that would block enterprise deals later. By naming the four variants now, the SDK exit gates (W1 Vault must support BYOK; W4 telemetry must be in-cluster-only configurable; W6 AI gateway must run against local models) become testable from the start.

23 · Governance & Ownership

Common-Platform Working Group
One tech lead per vertical + a platform architect
Approves promotion candidates (Rule of Three), contract changes, deprecations, SDK breaking releases. Meets fortnightly.
Identity Working Group v3
Persona / encounter / relationship governance
Standing group reviewing additions to the persona registry, encounter / relationship type catalog, cross-tenant access protocol. Clinical owner (healthcare) and compliance owner included.
Pool Capacity Steward v3
Pool sizing & migration scheduling
Platform engineer accountable for utilization dashboards, allocation policy, migration scheduling. Weekly report to working group.
Quarterly Reuse Audit
Drift detection
Counts services per vertical that should have been Common. Recommends promotions or refactors.
Quarterly Pool Health Audit v3
Capacity · isolation · residency
Confirms: no pool > 90% capacity; no tenant crossed pools; PHI/PCI pools in correct region; retired pools have shredded KEKs.
Service Ownership Matrix
Primary + deputy
Every Common service and HDK module has a named owner team and deputy. On-call per service. SLO posted internally.
Contract Change Protocol
RFC → review → dual-write → cut over
Breaking changes require RFC, working-group sign-off, dual-write window, deprecation timeline.
SDK Release Cadence
Weekly · semver
TS SDKs auto-published from each service's OpenAPI on merge to main. HDK modules release behind a feature flag until both platforms reach parity.
Cost & SLO Reporting
Per tenant · per vertical · per pool
Cloud spend tagged by tenant_id, vertical_id, and pool_index. AI cost via AI Gateway. Monthly chargeback feasible from day one.
Pool Router SLO v3
p99 ≤ 5 ms
Pool resolution must stay under 5ms p99. Anything slower pages on-call.

23.1 · Service & module ownership

Names below are the current primary owners. Each named owner has a deputy.

AreaPrimary ownerNotes
Backend architecture · SDK flowsTanveerPlatform-wide architect.
Pool Router · Pool Registry v3Platform / TBDPool Capacity Steward role.
Web Map · Map / Geo · hdk-mapSatyamEnd-to-end map module.
Mobile · cross-platform · hdk-diagnostic · hdk-cameraKunalMobile lead.
Authentication · hdk-idpShoaib · KrunalOffline biometric + PIN.
hdk-image-editor · hdk-video-editorShohebImage done; video close.
Lead Scoring · Recommendation · YamunaPrashantMulti-source pipeline + scoring.
CRM · Permissions · field user dataMayurPermissions follow-up.
Persona · Engagement · ReBAC v3TBDTo be assigned alongside Identity track.
hdk-scanner · hdk-measure · hdk-watermarkTBDOpen.
Storm · Dispatch · Assignment · Field-Ops EvidenceTBDFieldOps team to nominate.

24 · Cross-Vertical Roadmap

QuarterCommon platform deliverable
Q1Identity · Tenant · Profile · Payment · Notification · Audit · Media · Feature Flags · Observability · @projexlight/contracts v1 — production for Seva P1 + Realty P1. v3 Pool Registry + sdk-pool-router v1. Tenant provisioning writes pool assignments.
Q2Content · Course · Event · Search · Order primitives generalized. CRM consolidated. Generated SDKs published. v3 Identity issues six-layer JWT; sdk-persona v1 (App Identity, Tenant Membership, Persona). Profile bands re-homed. Per-pool Vault KEK live.
Q3SR · Workflow · Campaign · Social · Analytics · Executive Dashboard. Onboarding agent. HDK v1: hdk-idp · hdk-permissions · hdk-diagnostic · hdk-camera. v3 sdk-engagement v1 (Encounter, Relationship); sdk-rebac v1. First healthcare scenario in staging.
Q4AI Gateway · Knowledge/RAG · Conversation · Recommendation · all 12 Common Agents. HDK v2: hdk-map · hdk-image-editor · hdk-watermark. Map/Geo + Storm live. v3 Pool migration pipeline v1; first pool retirement drill; eCommerce scenario in staging.
Q5FieldOps vertical launches: Dispatch · Assignment · Lead Scoring · Field-Ops Evidence. HDK v3: hdk-video-editor · hdk-measure · hdk-scanner. Kiosk template ready. v3 Cross-region replication (Tier G); cross-tenant relationship coordinator; cross-domain scenario in staging.
Q6Tier G isolation; multi-region; third HDK-consuming vertical live. Reuse audit ≤ 10% domain code. Data-Design / Data-Request manifests steady state. v3 Petabyte readiness: 30+ pools in production; automated capacity steward; full per-encounter retention live.

25 · Glossary

Vertical
A productized domain bundle (Seva, Realty, Music, BidWork, LeadPulse, FieldOps, Healthcare, eCommerce, OneEstate, Wellness).
Tenant
A customer organization that subscribes to one or more verticals.
Common service
A horizontal capability that serves all verticals from one deployment.
Vertical service
A domain capability that serves only its vertical.
HDK
Hexa Development Kit — native SDK ecosystem (Kotlin + Swift + TS facades).
COSU
Corporate-Owned, Single-Use — Android device-owner mode for kiosk deployments.
Evidence chain
End-to-end provenance trail from capture through annotation to durable storage.
Address ID / Property ID
Canonical master keys created by Map/Geo service.
Tier S/P/G
Standard / Premium / Governed isolation tiers.
Rule of Three
Promotion criterion from Vertical → Common.
Event envelope
The mandatory wrapper around every domain event. Defined in @projexlight/contracts.
RLS
Row-Level Security — Postgres policy restricting row visibility by tenant_id within a pool.
PostGIS
Postgres spatial extension. Backs Map/Geo and Storm services.
Yamuna
FieldOps-specific recommendation engine.
Pool v3
A self-contained Postgres cluster (primary + replicas + PITR). Holds many tenants without splitting any.
Pool family v3
Admin · Application · Evidence.
Pool index v3
Stable identifier of a pool — e.g., admin-014, app-healthcare-007.
Pool registry v3
Postgres-backed, Redis-cached lookup that resolves (tenant_id, app_id) → pool_index → dsn.
App Identity v3
L2 — one row per (person_id × app_id).
Tenant Membership v3
L3 — one row per (app_identity_id × tenant_id).
Persona v3
L4 — the "hat" a person wears at a tenant.
Encounter v3
L5 — a bounded interaction with time, location, participants.
Relationship v3
L6 — long-running bond between personas.
ReBAC v3
Relationship-Based Access Control.
Encounter Grant v3
A time-bounded, scope-bounded access token issued for one encounter.
Encounter Key v3
A Vault key wrapping an encounter's payload. Shredded on retention expiry.
Pool KEK v3
Per-pool key encryption key wrapping tenant keys in that pool.
Meter gate v3.1
The two-phase admission check (sync, ≤ 2ms) + usage emission (async) wrapped around every typed SDK method via build-time codegen.
Usage event v3.1
A usage.event.v1 envelope emitted by sdk-meter on every gated call. Carries SKU, units, dimensions (six-layer AIM tuple + pool_index + actor), occurred_at, event_id.
SKU (Pricing SKU) v3.1
A typed key (sdk, method, tier) referenced by every @meter decorator. Schema lives in contracts; rates live in Postgres.
Pricing catalog v3.1
Versioned bundle of SKU → pricing-mode → rate mappings. pricing.catalog.vN. Bills always reference the catalog version they were generated against.
Showback / chargeback v3.1
Splitting a tenant's bill by app, BU, persona-kind, or encounter. Enabled by the six-layer attribution carried in every usage event.
Reprice dry-run v3.1
Recomputing a past month against a different pricing catalog to preview the impact before applying.
Identity Projection v3.1
Precomputed flattened subject_view per (person, app, tenant) maintained by sdk-identity-resolver's background worker. Replaces six-layer runtime traversal on the hot path.
Conflict Resolution Model v3.1
Per-event-type policy (CRDT · LWW · merge · event-sourcing · human-review) declared in contracts and executed by hdk-sync on reconnect. See §6A.
Capability Token v3.1
Signed, scope-limited, single-use credential issued by the Agent Isolation Runtime for every tool invocation by an agent. Tools refuse without it. See §18A.
Execution TTL v3.1
Hard deadline at agent run start; runtime terminates the agent on expiry, cancels in-flight tools, rolls back compensable steps. Prevents runaway agents.
Deterministic Replay v3.1
Content-addressed agent execution log that, replayed against the same model snapshot, produces bit-identical outputs. Enables rollback, bug reproduction, and model-upgrade regression testing.
Iceberg Lakehouse v3.1
Petabyte-scale read-federation layer over S3 tables (sdk-analytics in P7). The only sanctioned home for cross-pool aggregations at PB scale. ClickHouse for hot (≤90d); Iceberg for cold + cross-pool.
Phase v3.1
Dependency-driven delivery boundary in the SDK Build Plan (P1–P8). Each phase has a hard exit gate; CI blocks any phase N+1 PR from importing unstable phase N SDKs. See SDK-Build-Plan §0A.
sdk-trace v3.1
Cross-system trace viewer. One trace_id resolves into a unified timeline of identity + consent + routing + pool + key + policy + meter + lineage events for a single request. Powers MTTR and /billing/verify.
hdk-sync v3.1
Native HDK module that owns the offline write queue, replay engine, and per-event-type conflict resolution. MUST land before hdk-camera/map/etc. so they have a sanctioned offline-write owner.
MCP (Model Context Protocol) v3.1
Open standard (Anthropic) for letting LLMs invoke tools across systems. Public MCP servers exist for Slack, GitHub, Snowflake, Postgres, file systems, and dozens more. v3.1 implements MCP bidirectionally via sdk-mcp-bridge.
sdk-mcp-bridge v3.1
The bidirectional MCP implementation. Consume side: register external MCP servers per tenant; auto-register their tools in the agent's CapabilityGraph. Expose side: surface selected ProjexCloud SDKs as MCP servers so external AI systems can call in. Same gated/metered/audited contract as internal tools.
sdk-connectors v3.1
Common framework for typed external-system connectors (Salesforce, Snowflake, M365, GWorkspace, Jira, Slack bidirectional, …). OAuth + schema mapping + bidirectional sync + rate limits + webhook ingestion + cursor state + health monitoring. Per-target packages depend on this framework.
Connector package v3.1
A @projexlight/connector-{target} package implementing the sdk-connectors framework for one external system. Roster: connector-slack (P4) · connector-salesforce, microsoft365, gworkspace, jira, linear, zendesk, hubspot, zoom (P5) · connector-snowflake (P6B) · connector-twilio-voice (P15).
sdk-sequence P14·15
Multi-touch cadence orchestration. Definition + enrollment, a send-window-gated step executor (UTC quiet-hours + weekdays, idempotent enqueue), reactive control (pause-on-reply / stop-on-optout / replace-CTA) and a frequency-cap + circuit-breaker guard with audit log. The step sender is a pluggable hook the app bridges to sdk-notification.
sdk-scheduling P14·15
Calendar, booking & no-show engine. Availability slotting (IANA-tz business hours, buffers, meeting types), double-book-safe booking, RFC5545 ICS invites, timed reminders + no-show detection/rebook, and two-way Google/Microsoft calendar sync via connectors. Public (anonymous) booking links: slug page + capability-token confirm/cancel, so a prospect books without a tenant login.
sdk-deliverability P14·15
Suppression, bounce & reply intelligence. Suppression list + opt-out tokens, pre-send enforcement API, HMAC-verified provider bounce/complaint webhooks (SES/SendGrid/Mailgun/Postmark) with auto-suppress, IMAP inbound reply sync, and a bounce-rate auto-pause + reputation guard on the send path.
sdk-offer-catalog P14·15
Versioned offer truth + feature-status matrix. Offer/version lineage with a status enum, activate/publish + resolve-current-with-fallback, a publish gate routed through sdk-approval (subject = the offer version), a feature-status REST surface, and a version-stamp API with a stale-reference rejection guard.
sdk-handoff P14·15
Sales→Delivery handoff with accept/reject. Handoff record + status lifecycle (draft→pending→accepted/rejected→completed), kickoff/prework/milestones driven as an sdk-workflow saga with compensation, and the CS accept/reject decision delegated to sdk-approval and reflected back onto the handoff lifecycle + events.
sdk-incident P14·15
Exception/incident record & evidence. Incident CRUD + status lifecycle + SLA-breach scan, and an append-only evidence timeline (detected/root-cause/recovery/verification) notarised into the sdk-audit hash chain — the entry id/seq/hash are stored on each row as an immutability receipt and UPDATE/DELETE are blocked at the database.
connector-twilio-voice P14·15
Telephony channel (call/voicemail). Tracking-number provisioning, outbound calls with statusCallback + recording + answering-machine detection, and public signed status/recording webhooks (X-Twilio-Signature) that classify AMD machine-answers as voicemail. Recording is gated on an sdk-consent decision (fails closed); finished calls/voicemails/missed-calls bridge into the sdk-crm activity timeline.