{"slug":"architecture/SPINE_MODEL","title":"The Spine — Canonical Model","section":"architecture","sectionLabel":"Architecture","status":"unclassified","type":"document","path":"architecture/SPINE_MODEL.mdx","bytes":11052,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n> **Status:** Canonical architecture doctrine (constitutional reference)\n> **Date:** June 12, 2026\n> **Authority:** Nirmal (Founder)\n> **Companion docs:** `USER_SYSTEM_JOURNEY_BLUEPRINT.md` (layers/stages), `AGENTS.md` (locked decisions)\n> **Supersedes:** Spine descriptions scattered across session logs and status docs. Those remain\n> valid as history; this doc is the single authoritative model. When a doc contradicts this file,\n> this file wins.\n\n**Canonical Reference:** [CANONICAL_PLATFORM_ARCHITECTURE.md](./CANONICAL_PLATFORM_ARCHITECTURE.md)\n\n> This document is downstream of the Canonical Platform Architecture. When this document contradicts the canonical architecture, the canonical architecture wins.\n\n---\n\n## 0. The One-Line Truth\n\n```text\nOne Spine. Many projections. The Spine is the source of truth; every surface is a view of it.\n```\n\nThe Spine is the normalized, governed, tenant-isolated context substrate that sits behind every\nconnector, tool, AI, and session. It is the product moat. Everything the user sees (workbenches,\nbriefs, the Twin) is a **projection** of the Spine — never a raw tool table, never an ETL copy.\n\nThis document defines **what the Spine is made of**. It is deliberately pointer-based: the\nexhaustive lists live in code (cited below) so this doc cannot drift out of sync. Read the model\nhere; trust the code for the enumerations.\n\n---\n\n## 1. The Four Founding Pieces (August 2025 — immutable)\n\nThe Spine is the third of four axioms (see `AGENTS.md`). They are not redesigned, replaced, or\nrouted around:\n\n```text\nLOADER       Universal intake membrane. MCP-native. Tracks provenance. Never reasons.\nNORMALIZER   Eight-stage cognitive pipeline (LLM-in-the-loop at stages 2,3,4,6).\n             Output = MCP tool calls, not JSON blobs. Normalization paid ONCE per entity.\nSPINE        Context substrate across all connected tools (THIS DOCUMENT).\nTRAIT + RESOURCE TYPE  18 core traits, 7 canonical resource types. Identity by nature, not label.\n```\n\nThe Spine's job: turn many tools' overlapping, conflicting records into **one canonical entity per\nreal-world thing**, connect them in a relationship graph, and emit signals when they change.\n\n---\n\n## 2. What the Spine Holds\n\nThe Spine is composed of four planes. All four are tenant-isolated (`tenant_id` throughout).\n\n```text\n2.1 ENTITIES        Canonical records (one Person, one Account, …) resolved across all tools.\n2.2 RELATIONSHIPS   The graph that connects entities (exists nowhere else).\n2.3 SIGNALS         change → Think → HITL → Act → signal → loop.\n2.4 MEMORY          conversational_memory · org_memory · personal_memory (continuity layer).\n```\n\n| Plane                      | Source of truth                                                     | Code                                                         |\n| -------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------ |\n| Entities                   | Neon tenant-scoped entity tables through Governed Spine Writers     | `services/spine/`, `services/pipeline/`                      |\n| Relationships / Entity 360 | assembled on read                                                   | `services/pipeline/src/spine/entity360-assembler.ts`         |\n| Signals                    | signal cache + signal partition                                     | `packages/types/src/signal-analyzer.ts`, `services/pipeline` |\n| Memory                     | D1 / KV / AI Search (CF-native; legacy Supabase being migrated off) | `services/continuity`, `services/intelligence`               |\n\n---\n\n## 3. The Entity Model\n\n### 3.1 Canonical entity types\n\nEvery record is normalized to a **canonical entity type**. The complete universe of valid types is\ncomputed in code — do not hand-maintain a list here:\n\n- Universe: `ALL_CANONICAL_ENTITY_TYPES` — `packages/types/src/schema.ts`\n- Aliases (provider-native, plurals, legacy → canonical): `CANONICAL_ENTITY_TYPE_ALIASES`\n- Resolution: `resolveEntityTypeAlias()` → `validateEntityType()` → `isCanonicalEntityType()`\n\nThis is the mechanism that makes:\n\n```text\nHubSpot Contact  =  Salesforce Lead  =  Jira Reporter  =  one canonical Person\nHubSpot Company  =  Salesforce Account  =  one canonical Account\n```\n\nA new tool is absorbed by: **trait detection → resource type → schema → pool → neutralized.**\nNo per-tool special-casing in the Spine.\n\n### 3.2 Logical domains (12 department configs)\n\nEntity types are organized into 12 department domains, each with its own entity set and\npriority/field policies. Defined in `DOMAIN_SPINE_CONFIG` (`packages/types/src/schema.ts`):\n\n```text\nCUSTOMER_SUCCESS · REVOPS · SALES · MARKETING · PRODUCT_ENGINEERING · FINANCE\nSERVICE · PROCUREMENT · IT_ADMIN · STUDENT_TEACHER · BIZOPS · PERSONAL\n```\n\nDepartment-to-config mapping: `DEPARTMENT_TO_CONFIG_KEY`. Industry overlays:\n`INDUSTRY_SPINE_BASE` (cross-industry extras). Cross-domain types: `CROSS_DOMAIN_ENTITY_TYPES`.\n\n### 3.3 Physical partitions (5 D1 tables)\n\nLogical domains are written to **five physical D1 partitions**. The mapping is a pure function —\nreads and writes use the SAME resolver, so they can never split-brain:\n\n```text\ndecide_data   strategy & commitments   okr, strategic_objective, business_context, kpi, decision, commitment\nbuild_data    work & artifacts         task, workflow, document, blocker, calendar_event\ngrow_data     revenue & customers      account, contact, opportunity, ticket, renewal, risk\nrun_data      operations               ops_metric(s)\ncross_data    everything else          signals, episodes, learnings, generated insights (default)\n```\n\nResolver: `getDomainForType()` in `services/pipeline/src/spine/index.ts`.\nQuery expansion across aliases: `getMatchingTypesForQuery()`. Typed-column extraction per domain:\n`extractTypedFields()`. (DECISION 21 — D1-direct workspace projections.)\n\n---\n\n## 4. The Fortress (write path)\n\nUnder DECISION 22 the product plane is **100% Cloudflare**. There is no Supabase and no second\nstore — a single Cloudflare plane.\n\n```text\nConnector / Webhook / MCP / API\n        ↓  (S1 Connectivity → S2 Loader → S3 Normalizer → S4 Entity Resolution)\nPipeline (Governed Spine Writer) ──writes──▶ Neon tenant entity tables\n        ↓                                       │\n   pipeline-process queue                       └── D1/KV bounded cache + derived search index\n```\n\n- The pipeline is the **only** writer to canonical partitions: `services/pipeline/src/spine/index.ts`.\n- The Twin is **READ-ONLY** to the Spine. Memory writes go via the continuity pipeline only.\n- Every Spine access is audit-logged (`spine_audit_log`, see `AGENTS.md` Rule 9).\n\n> ⚠️ Migration honesty: doctrine = Cloudflare-only; code still references Supabase in ~70 files\n> (tracked in `docs/migrations/DE_SUPABASE_MIGRATION.md`). Do not claim \"Supabase removed\" until\n> the code is migrated. Do not add new Supabase usage (enforced by `scripts/check-doctrine.mjs`).\n\n---\n\n## 5. Projections (read path)\n\nThe frontend and Twin **never** read raw tool tables. They read projections of the Spine:\n\n```text\nSpine (D1 partitions)\n   ├── /api/v1/workspace/*            workspace-spine.ts        → L1 User Workbench\n   ├── /api/v1/pipeline/entities[...]  spine/index.ts            → grids, counts, batches\n   ├── Entity 360 (assembled on read)  entity360-assembler.ts    → L2 Intelligence Overlay\n   ├── Signals                         signal-analyzer.ts        → L5 Operations Workbench\n   └── Memory / Knowledge              continuity / knowledge    → L3 Twin, L4 Knowledge Workbench\n```\n\nServed D1-direct by the gateway (`services/gateway/src/workspace-spine.ts`, DECISION 21) — no\nSupabase-backed BFF hop. Projections mirror the same partitions the pipeline writes.\n\n**Principle:** a projection is a _view_, computed from the Spine. If a surface needs data, it\nasks the Spine for a projection — it never gets its own store.\n\n---\n\n## 6. Governance & Continuity (the hard gate)\n\n```text\nSignal/change → Intelligence (Think) → Proposal → S8 Governance (HARD GATE) → Act → writeback → signal\n```\n\n- No execution without an approval token (`x-approval-token`). HITL is mandatory for writes-back.\n- Promotion to `org_memory` is human-approved (L7 Governance Workbench).\n- Continuity Bridge (`services/continuity`) carries normalized, governed context across every AI,\n  tool, and session — this IS the product (IW Continuity Bridge, DECISION 23).\n\n---\n\n## 7. The Moat, Stated Plainly\n\n```text\nN tools × M tools integrations  →  N + M (each tool speaks to the Spine once)\n```\n\n- Normalization is paid **once per entity**; every connected tool compounds the same Spine.\n- Entity resolution + the relationship graph + the signal loop exist **in the Spine**, not in any\n  single tool — that is the defensible center.\n- Other AIs/tools (Claude, ChatGPT, Cursor, Perplexity) integrate via MCP/AI-provider/Nango/API and\n  become **surfaces onto the Spine** — they are not the product runtime.\n\n---\n\n## 8. Source-of-Truth Index (read the code, not a copy)\n\n| Concept                                              | Authoritative source                                                      |\n| ---------------------------------------------------- | ------------------------------------------------------------------------- |\n| Canonical types, aliases, domains, industry overlays | `packages/types/src/schema.ts`                                            |\n| Type resolution functions                            | `resolveEntityTypeAlias` / `validateEntityType` / `isCanonicalEntityType` |\n| Physical partition resolver                          | `getDomainForType` — `services/pipeline/src/spine/index.ts`               |\n| Spine writer                                         | `services/pipeline/src/spine/index.ts`                                    |\n| Entity 360 assembly                                  | `services/pipeline/src/spine/entity360-assembler.ts`                      |\n| Workspace projections                                | `services/gateway/src/workspace-spine.ts`                                 |\n| Signals                                              | `packages/types/src/signal-analyzer.ts`                                   |\n| Memory / continuity                                  | `services/continuity`, `services/intelligence`                            |\n| Layer/stage doctrine                                 | `docs/architecture/USER_SYSTEM_JOURNEY_BLUEPRINT.md`                      |\n| Locked decisions                                     | `AGENTS.md` (DECISIONS 18–23)                                             |\n\n---\n\n_This file is the constitutional reference for the Spine. It is pointer-based by design: when the\ncode changes, update the pointers, never fork the lists. When in doubt — halt, ask Nirmal._\n"}