{"slug":"architecture/ADAPTIVE_SPINE_MODEL_v1","title":"Adaptive Spine — Canonical Model v1.0 (FROZEN)","section":"architecture","sectionLabel":"Architecture","status":"current","type":"document","path":"architecture/ADAPTIVE_SPINE_MODEL_v1.mdx","bytes":23248,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n**Status:** FROZEN — 2026-07-17\n**Model version:** `spine-model/1.3.1`\n**Scope:** the canonical operational database of the IntegrateWise platform (Phase 6).\n\nThis document freezes the Adaptive Spine's entity model, relationships, identity\nscheme, lifecycle, versioning, timeline, provenance, and projection metadata.\nEvery MCP (Provider, Integration, Task, Workspace, Knowledge, Governance,\nIntelligence) targets these contracts. Nothing below changes without a model\nversion bump (§7) and an entry in the timeline of this document (§12).\n\nContract-layer field names are `camelCase`; the storage layer (D1) uses\n`snake_case`. The conversion is mechanical and total — no field exists in one\nlayer without a counterpart in the other.\n\n---\n\n## 1. Entity model\n\nThe Spine has two tiers. **Platform entities** describe the machinery: who is\nconnected to what, through which adapter, moving which shapes. **Operational\nentities** are tenant business data and what the platform has learned about it.\n\n| Domain        | Tier        | ID prefix | Owner service              | Status                             |\n| ------------- | ----------- | --------- | -------------------------- | ---------------------------------- |\n| Tenant        | platform    | `ten`     | Spine Service              | model frozen, impl pending         |\n| Workspace     | platform    | `wsp`     | Spine Service              | model frozen, impl pending         |\n| User          | platform    | `usr`     | Spine Service              | model frozen, impl pending         |\n| Provider      | platform    | `prv`     | Provider Management MCP    | model frozen, impl pending         |\n| Application   | platform    | `app`     | Provider Management MCP    | model frozen, impl pending         |\n| Connection    | platform    | `con`     | Provider Management MCP    | landed (`packages/spine-entities`) |\n| Connector     | platform    | `cnr`     | Integration Management MCP | landed                             |\n| Capability    | platform    | `cap`     | MCP Pool                   | landed                             |\n| SyncJob       | platform    | `syn`     | Integration Management MCP | landed                             |\n| Webhook       | platform    | `wbk`     | Integration Management MCP | landed                             |\n| Schema        | platform    | `sch`     | Integration Management MCP | landed                             |\n| Environment   | platform    | `env`     | Deployment MCP             | model frozen, impl pending         |\n| Release       | platform    | `rel`     | Deployment MCP             | model frozen, impl pending         |\n| Deployment    | platform    | `dep`     | Deployment MCP             | model frozen, impl pending         |\n| Entity        | operational | `ent`     | Entity Service             | model frozen, impl pending         |\n| TimelineEvent | operational | `evt`     | Timeline Service           | landed                             |\n| Memory        | operational | `mem`     | Memory Service             | model frozen, impl pending         |\n| Knowledge     | operational | `knw`     | Knowledge Service          | model frozen, impl pending         |\n| Policy        | operational | `pol`     | Governance MCP             | model frozen, impl pending         |\n| Approval      | operational | `apr`     | Governance MCP             | model frozen, impl pending         |\n| Audit         | operational | `aud`     | Governance MCP             | model frozen, impl pending         |\n| Signal        | operational | `sig`     | Intelligence MCP           | model frozen, impl pending         |\n| Intelligence  | operational | `int`     | Intelligence MCP           | model frozen, impl pending         |\n\n`Entity` is the canonical business object (account, contact, deal, ticket,\nproject, invoice, vendor, …). Its `entityType` vocabulary is the existing\ncanonical set in `packages/types` (`schema.ts` DOMAIN_SPINE_CONFIG +\nCROSS_DOMAIN_ENTITY_TYPES) — this document does not fork that vocabulary.\n\nThe deployment domains make shipping the platform part of the platform.\nAn **Environment** is a promotion stage (development → integration → qa →\nstaging → production); a **Release** is a versioned, promotable unit; a\n**Deployment** is one execution of a release into an environment\n(`environment`, `service`, `version`, `gitCommit`, `buildNumber`,\n`rollbackVersion`, `health`, `metrics`, `artifacts`). Two scoping rules are\npart of the freeze: deployment-domain records belong to the\n**platform-operator tenant** (the envelope's tenant invariant holds — there is\nno tenant-less record), and **secret material is never a spine record** —\n`secrets.*` capabilities operate against the Cloudflare secret store while the\nspine records only rotation and validation events on the timeline.\n\n**Coding agents are deployment clients, never deployment systems.** Claude\nCode, Codex, Gemini CLI, Cursor, and any future agent deploy by invoking\n`deployments.*` capabilities (`deployment.create({service, environment,\nversion})`) and consuming the result; the Deployment MCP owns build, gates,\nmigrations, provider adapters, health verification, spine recording, and\ntimeline emission. Direct provider deploys from an agent (`wrangler deploy`,\ndashboard pushes, per-service CI auto-deploys) are out-of-band and retired\nonce the Deployment MCP is live. The rule is enforced by credential\nplacement, not convention: production provider credentials are held by the\nDeployment MCP alone — agents never carry them. Adding a deployment target\n(Kubernetes, AWS, on-prem) adds an adapter inside the Deployment MCP;\nno client changes.\n\n`Signal` and `Intelligence` are distinct and both canonical. A **Signal** is a\ndetected condition on an entity (renewal*risk, sla_breach, deal_stalled —\nthe existing `signalTypes` vocabulary in `spine-schema.ts`): high-volume,\nshort-lived, always tied to a subject entity. **Intelligence** is a derived\nartifact (prediction, recommendation, score, forecast) computed \\_from* signals,\ntimeline, and memory: lower-volume, longer-lived, versioned.\n\n### 1.1 Common record envelope\n\nEvery Spine record, regardless of domain, carries this envelope. Domain fields\nextend it; nothing replaces it.\n\n```ts\ninterface SpineRecord {\n  id: string; // §3 — prefixed ULID, immutable\n  tenantId: string; // §2 — isolation wall; only Tenant itself omits this\n  workspaceId?: string; // present when the record is workspace-scoped\n  status: string; // §4 — value from the domain's state machine\n  version: number; // §5 — record version, optimistic concurrency\n  schemaVersion: string; // §5 — contract version of the domain, semver\n  dataClass: \"public\" | \"internal\" | \"confidential\" | \"pii\"; // §8\n  provenance: Provenance; // §7 — mandatory on every write\n  createdAt: string; // ISO-8601 UTC\n  updatedAt: string; // ISO-8601 UTC\n  archivedAt?: string; // set if and only if status is archival/terminal\n  metadata: Record<string, unknown>; // free-form, never load-bearing\n}\n```\n\nDomain-specific fields already landed in `packages/spine-entities` are part of\nthe freeze: Connection (`authorizationRef`, `status`, `health`), Connector\n(`capabilities`, `config`, `supportedEntities`), SyncJob (`mode`, `cursor`,\n`errors`, `metrics`), Webhook (statistics), Schema (field mappings), Capability\n(governance policies), TimelineEvent (§6 envelope).\n\n---\n\n## 2. Relationships\n\nOwnership is a tree; everything else is a reference edge.\n\n```text\nTenant\n ├── Workspace ──── User (membership, role-scoped)\n ├── Connection ──→ Application ──→ Provider   (authorizationRef binds them)\n │     └── Connector                  (executes over one Connection)\n │           ├── SyncJob              (execution records)\n │           ├── Webhook              (event subscriptions)\n │           └── Schema               (discovered + mapped shapes)\n ├── Capability ──→ Connector/MCP     (registry entry → implementation)\n ├── Entity ──→ sourceRefs            (produced by SyncJobs via Schema mappings)\n │     ├── TimelineEvent (subject)\n │     ├── Signal (subject entity)\n │     ├── Memory (entityRefs)\n │     ├── Knowledge (entityRefs)\n │     └── Intelligence (entityRefs)\n ├── Policy ── Approval ── Audit      (governance chain)\n └── Environment ── Release ── Deployment   (platform-operator tenant only)\n```\n\nRules — all mandatory:\n\n1. **References are by ID only.** No record embeds another record. Consumers\n   resolve edges through the owning service.\n2. **`tenantId` is a hard wall.** A record may never reference a record in\n   another tenant. Enforced at the Spine Service boundary, not left to callers.\n3. **Ownership implies lifecycle coupling.** Archiving a parent archives its\n   subtree (soft cascade, §4.2). References (non-ownership edges) do not\n   cascade; they dangle-safe by ID and resolve to `gone` after archival.\n4. **Entity relationships** (account→contacts, deal→account, …) are edges on\n   the Entity record (`relationships: {type, targetId}[]`), not join tables in\n   consumer services. Entity360 reads them; it never defines them.\n\n---\n\n## 3. Identity\n\n**Format:** `{prefix}_{ulid}` — e.g. `con_01J2ZK7M8QW3R9T5V6X7Y8Z9AB`.\nPrefixes are the table in §1. ULIDs are 26-char Crockford base32,\nlexicographically sortable by creation time.\n\n1. IDs are assigned by the owning service at creation. Never client-supplied,\n   never reused, never mutated. The ID is the only canonical identity.\n2. **Source identity is an alias, not an identity.** External records carry\n   `sourceRefs: {sourceSystem, sourceId}[]`. The pair\n   `(tenantId, entityType, sourceSystem, sourceId)` is unique and is the upsert\n   key for sync ingestion: match → update canonical record + append sourceRef\n   if new; no match → create. Two source systems pointing at the same\n   real-world object merge into one Entity with two sourceRefs.\n3. Merges preserve the older canonical ID; the newer ID is tombstoned with a\n   `mergedInto` pointer and a timeline event. Splits are new creations.\n\n---\n\n## 4. Lifecycle\n\n### 4.1 State machines (frozen)\n\n```text\nApplication: registered → configured → active ⇄ suspended → archived\nConnection: pending → authorized → active ⇄ degraded → expired | revoked\nConnector:  installed → configured → enabled ⇄ disabled → archived\nCapability: registered → active ⇄ deprecated → retired\nSyncJob:    queued → running → succeeded | failed | cancelled     (terminal)\nWebhook:    registered → active ⇄ paused → failed → archived\nSchema:     discovered → mapped → approved → active → superseded\nEnvironment: provisioned → active ⇄ frozen → destroyed\nRelease:    draft → candidate → released → superseded | rolled_back\nDeployment: queued → building → deploying → verifying → live | failed ;\n            live → superseded | rolled_back\nEntity:     active ⇄ stale → archived\nSignal:     detected → active ⇄ acknowledged → resolved | expired\nMemory:     proposed → approved | rejected ; approved → promoted → archived\nApproval:   pending → approved | rejected | expired               (terminal)\nPolicy:     draft → active ⇄ suspended → retired\n```\n\n- SyncJob retries are **new attempts** (attempt counter on the job), never a\n  transition out of a terminal state.\n- Memory confidence thresholds prioritize review and may reject weak\n  candidates. They never confer promotion authority: every canonical memory\n  promotion requires the governed record and applicable human approval.\n- Every transition above **must** emit exactly one TimelineEvent (§6). A state\n  change without an event is a contract violation.\n\n### 4.2 Deletion doctrine\n\nSoft delete only: terminal/archival status + `archivedAt`. Hard deletes exist\nsolely as **governed purge** (tenant offboarding, compliance erasure), execute\nthrough the Governance MCP, and always leave an Audit record. No service issues\n`DELETE` outside the purge path.\n\n---\n\n## 5. Versioning\n\nThree planes, none optional:\n\n| Plane    | Field                    | Semantics                                                                                      |\n| -------- | ------------------------ | ---------------------------------------------------------------------------------------------- |\n| Record   | `version` (int)          | +1 on every mutation; optimistic concurrency — writes carry expected version, mismatch rejects |\n| Contract | `schemaVersion` (semver) | version of the domain's shape the record was written under                                     |\n| Model    | `spine-model/1.0.0`      | this document; the whole vocabulary                                                            |\n\nEvolution rules: adding optional fields or new entity domains = **minor**;\nremoving, renaming, or changing the semantics of a field, or changing a state\nmachine = **major**, requiring a migration plan and a dual-read window.\nHistory is never rewritten: TimelineEvents and Audit records are never\nmigrated in place — readers interpret them by their recorded `schemaVersion`.\n\n---\n\n## 6. Timeline\n\nThe timeline is the append-only, immutable record of everything that happened.\nIt is written by services, never by clients, and never updated or deleted\n(compaction, below, is the only exception).\n\n```ts\ninterface TimelineEvent {\n  id: string; // evt_<ulid> — recording order\n  tenantId: string;\n  eventType: string; // \"{domain}.{action}\": connection.authorized,\n  // sync.completed, entity.merged, memory.promoted…\n  subject: { entityType: string; entityId: string };\n  occurredAt: string; // when it happened in the world\n  recordedAt: string; // when the spine recorded it\n  actor: Actor; // §7\n  provenance: Provenance; // §7\n  payload: Record<string, unknown>; // domain summary / field diff\n  correlationId?: string; // groups one logical operation across services\n  causationId?: string; // the event that caused this one\n  schemaVersion: string;\n}\n```\n\n- **Ordering:** ULID order = recording order per tenant. Consumers must not\n  assume ordering across tenants or between `occurredAt` and `recordedAt`.\n- **Retention:** platform-tier events are audit-grade and kept indefinitely.\n  High-volume operational events may be compacted after 90 days into rollup\n  events, with originals archived to object storage — never silently dropped.\n- The timeline is the source for Entity360's activity layer and the Governance\n  Workbench's audit view; neither maintains a parallel history.\n\n---\n\n## 7. Provenance\n\nEvery write — record mutation or timeline event — carries provenance. The Spine\nService rejects writes without it.\n\n```ts\ninterface Actor {\n  type: \"user\" | \"agent\" | \"system\";\n  id: string; // usr_… | agent id | service name\n}\n\ninterface Provenance {\n  sourceSystem: string; // provider key (\"hubspot\", \"descope\") or \"internal\"\n  sourceId?: string; // id in the source system, if externally sourced\n  capabilityId?: string; // cap_… that performed the write\n  syncJobId?: string; // syn_… when written by a sync run\n  webhookId?: string; // wbk_… when written by an event delivery\n  trustLevel: \"source_of_record\" | \"user_asserted\" | \"model_inferred\";\n  evidenceRefs: string[]; // evidence ids supporting the write\n}\n```\n\n`trustLevel` reuses the existing vocabulary (`evidence_refs.trust_level`).\nModel-inferred writes (Memory, Intelligence) can never carry\n`source_of_record`; sync-ingested provider data always does.\n\n**Field-level provenance (Entity only).** Merged multi-source Entities may\nadditionally carry `fieldProvenance`: a per-field map of\n`{sourceSystem, confidence, updatedBy, updatedAt, resolution}` recording which\nsource won each field and why — the contract form of the existing\n`merge-fields` resolution machinery in `packages/types`. Record-level\nprovenance stays mandatory everywhere; field-level provenance is required\nwhenever an Entity has more than one sourceRef.\n\n---\n\n## 8. Projection metadata\n\nThe Spine is never read raw. Every consumer — MCP tool, workbench, Twin —\nreceives a **projection**: a named, per-domain field subset resolved against\nwho is asking.\n\n1. **`dataClass`** on every record (`public | internal | confidential | pii`)\n   is the redaction unit. A projection lists fields; resolution drops fields\n   whose dataClass exceeds the caller's clearance.\n2. **Named projections** per domain: `summary` (lists, tiles), `detail`\n   (single-record views), `timeline` (activity), plus domain-specific ones.\n   Projections are registered alongside the domain contract in\n   `packages/spine-entities` — not defined ad hoc by consumers.\n3. **Resolution inputs:** tenant spine config (allowed entity types, connected\n   connectors), subscription tier, RBAC role. This is the existing\n   `tenant_spine_config` doctrine — AI clients never see table shape, column\n   names, or unconfigured entity types.\n4. **Entity360 is a composed read-side projection** — truth, context, signals,\n   memory, goals, relationships layers per `packages/types/entity360.ts` —\n   assembled at read time from Entity + TimelineEvent + Memory + Knowledge +\n   Intelligence. It is never stored as canonical state and is implemented only\n   after the underlying entities exist.\n\n---\n\n## 9. Core services\n\n| Service           | Owns                                            | Writes               |\n| ----------------- | ----------------------------------------------- | -------------------- |\n| Spine Service     | envelope enforcement, CRUD, projections         | all platform domains |\n| Entity Service    | canonical Entity, source-identity upsert, merge | Entity               |\n| Timeline Service  | append-only event log                           | TimelineEvent        |\n| Memory Service    | proposal → governance → promotion               | Memory               |\n| Knowledge Service | documents, graph, search                        | Knowledge            |\n\nAll five enforce: tenant wall (§2), envelope (§1.1), provenance (§7),\none-event-per-transition (§4.1), projection-only reads (§8).\n\n### 9.1 Spine SDK\n\nMCPs never write to spine storage directly — all access goes through the Spine\nSDK, the single typed client over the services above. Frozen surface:\n\n```ts\nspine.create(domain, record); // envelope + provenance enforced\nspine.update(domain, id, patch, expectedVersion);\nspine.archive(domain, id); // soft delete only (§4.2)\nspine.get(domain, id, projection);\nspine.search(domain, filter, projection);\nspine.timeline(subject, range); // read the event log\nspine.relationships(id); // resolve reference edges\nspine.events.emit(event); // service-side only\n```\n\nThe SDK is the conformance boundary: everything in §11 is enforced inside it,\nso an MCP that only uses the SDK is conformant by construction.\n\n---\n\n## 10. Execution backlog\n\nFrozen implementation sequence. Within P0, entity contracts land in the order\nConnection → Connector → Capability → SyncJob → Webhook → Schema — each with\nits projections and timeline events before the next begins.\n\n| Priority | Deliverable                                  | Outcome                          |\n| -------- | -------------------------------------------- | -------------------------------- |\n| P0       | Freeze Adaptive Spine schema (this document) | Stable platform contracts        |\n| P1       | Spine SDK (§9.1)                             | Unified read/write API           |\n| P2       | Timeline Engine (§6)                         | Immutable event history          |\n| P3       | Relationship Graph (§2)                      | Canonical links between entities |\n| P4       | Entity360                                    | Unified operational view         |\n| P5       | Projection Registry (§8)                     | Schema-driven UI                 |\n| P6       | Adaptive Workbench Runtime                   | Runtime-generated workbenches    |\n| P7       | Governance MCP                               | Policy and approval engine       |\n| P8       | Knowledge & Memory                           | Organizational intelligence      |\n| P9       | Hermes Runtime                               | Autonomous orchestration         |\n\nEntity360 (P4) composes; it must not precede what it composes (P0–P3).\nGovernance (P7) consumes Spine entities; it owns no parallel state.\n\nThe Deployment platform (Deployment MCP, environment manager, Cloudflare\nadapters, migration/secret managers, rollback engine, deployment workbench)\nenters **after P1**: its entities are frozen here in P0, and the MCP is built\nexclusively on the Spine SDK — the first MCP conformant by construction. Every\ngate stage (typecheck → … → traffic shift) emits a `deployment.*` timeline\nevent per §6.\n\n**Platform Foundation is complete** — and the repository is tagged\n`v1-platform-foundation` — when all of the following hold:\n\n- Gateway, Identity, OAuth, and MCP Pool are stable.\n- Provider, Integration, and Task MCPs operate exclusively through the Spine SDK.\n- The Adaptive Spine schema is frozen and versioned (this document).\n- Every entity has a timeline and relationship graph.\n- Workbenches are projections generated from Spine metadata, not hardcoded pages.\n- Governance operates on canonical entities.\n- Hermes plans and executes via the Capability Fabric and Spine, never\n  provider-specific logic.\n\n## 11. Conformance checklist (for every MCP)\n\n- [ ] Reads go through named projections; no raw table access\n- [ ] Writes carry the envelope, provenance, and expected `version`\n- [ ] Every state transition emits exactly one TimelineEvent\n- [ ] No cross-tenant references; no client-supplied IDs\n- [ ] Soft delete only; purge via Governance MCP\n- [ ] Contract changes follow §5 (semver + migration for majors)\n\n## 12. Document timeline\n\n| Date       | Change                                                                                                                               | Model version       |\n| ---------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------- |\n| 2026-07-17 | Initial freeze                                                                                                                       | `spine-model/1.0.0` |\n| 2026-07-17 | Add Signal domain; Spine SDK surface (§9.1); replace build order with P0–P9 backlog + foundation-complete definition                 | `spine-model/1.1.0` |\n| 2026-07-17 | Add Deployment, Environment, Release domains (platform-operator tenant scope; secrets never stored); Deployment MCP slotted after P1 | `spine-model/1.2.0` |\n| 2026-07-17 | Add Application domain (Connection → Application → Provider chain); field-level provenance for multi-source Entities                 | `spine-model/1.3.0` |\n| 2026-07-17 | Doctrine: coding agents are deployment clients (deployments.\\* only; credentials live with the Deployment MCP)                       | `spine-model/1.3.1` |\n"}