{"slug":"internal/architecture/REPOSITORY_TOPOLOGY_AND_MIGRATION_SPEC","title":"Repository Topology and Migration","section":"internal","sectionLabel":"Internal","status":"unclassified","type":"document","path":"internal/architecture/REPOSITORY_TOPOLOGY_AND_MIGRATION_SPEC.mdx","bytes":19711,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n**Status:** Proposed\n**Document type:** Specification (records decision **D8**)\n**Authority:** Subordinate to [`INTEGRATEWISE_ARCHITECTURE.md`](../../architecture/INTEGRATEWISE_ARCHITECTURE.md)\n**Canonical sections implemented:** §8 (Truth) · §15.5 (Create once, deploy anywhere) · §16.7 (Product/Platform ownership) · §17 (Environments)\n**Owner:** Founder + Platform\n**Version:** 1.0\n**Last verified against:** HEAD `d941a422`\n**Last verified date:** 2026-07-31\n**Supersedes:** the three-repo proposal of 2026-07-31\n\n---\n\n## 1. Decision\n\n> **Two repositories, split by write authority — not by distribution channel.**\n>\n> **Platform** owns canonical truth and everything authorised to write it.\n> **Product** owns operational state, agent working memory, and every surface — as adapters\n> over one domain.\n\nThree profiles — `development`, `customer_zero`, `external` — apply to **both** repositories\nas runtime data, never as branches, directories or build variants (§4).\n\n### 1.1 Why not split by channel\n\nThe earlier proposal placed the Plugin Marketplace and MCP Marketplace in separate\nrepositories. They are not two products; they are two adapters over one domain\n(architecture §15.5: _domain logic is built once; hosts are adapters_).\n\nA repository boundary between them makes them peers, and peers drift. The onboarding state\nmachine is the concrete case: `consent_required → binding → hydrating → active` must be\nbyte-identical across channels, and a git boundary between the channels converts that\nrequirement from a compiler guarantee into a discipline. It also makes every future host —\nSlack, Microsoft, embedded — a new repository rather than a new folder.\n\nSplitting by write authority gets the separation the proposal wanted (platform vs surface)\nwithout institutionalising the channel fork.\n\n### 1.2 What each repository may write\n\nThis table is the boundary. Everything else follows from it.\n\n| Concern                                                                                           | Owner        | Write authority                                      |\n| ------------------------------------------------------------------------------------------------- | ------------ | ---------------------------------------------------- |\n| Canonical Spine entities, relationships, lineage, promotion records, audit                        | **Platform** | Pipeline promotion, sole writer                      |\n| Operational Spine — connections, connectors, sync jobs, webhooks, schemas, capabilities, timeline | **Platform** | The service owning the runtime object                |\n| Organisational memory                                                                             | **Platform** | Promotion gate — governance lives with the gate      |\n| Model providers, models, capability registry, agent **runtime**                                   | **Platform** | Platform                                             |\n| Operational store, active context, projection cache                                               | **Product**  | Writes freely — this is its state                    |\n| Personal · agent · conversational memory                                                          | **Product**  | Writes freely; **proposes** to organisational memory |\n| Agent **contracts** and invocation, host adapters, Workbench UI                                   | **Product**  | Product                                              |\n| Projections                                                                                       | **Product**  | **Derived — never a write target**                   |\n\n**Synchronisation is one-way with a gate.** Operational state promotes to canonical through\nthe existing path (`Continuity Bridge → Promotion`). There is no bidirectional merge, and\nthere is no second canonical writer. If the Product repo needs something to be true, it\nproposes; the Platform repo commits.\n\n**Organisational memory stays with Platform** because it is governed. Memory that requires\nthe promotion gate lives where the gate lives. Personal, agent and conversational memory are\nevidence (§8.2c) and belong with the surfaces that generate them.\n\n---\n\n## 2. Repository contents\n\n### 2.1 `integratewise-platform`\n\n```\nservices/          gateway · pipeline · spine · connector · connector-sync\n                   mcp-connector · knowledge · continuity · intelligence\n                   workflow · hermes · mcp-pool · marketplace-installation\npackages/          spine-entities · spine-schema · types · connector-contracts\n                   connectors · lib · rbac · tenancy · projection-engine · sdk\nmigrations/        canonical schema — one root, one sequence\ninfrastructure/    connector catalog · models · MCP tools registry · ADK\napps/              marketing                  ← no truth authority, no runtime coupling\ndocs/              architecture · specifications · adr · runbooks · evidence · changelog\n```\n\nPublishes `@integratewise/sdk` and `@integratewise/spine-schema`. Nothing else is publishable\n(architecture S12 — 16 packages currently omit `private`; fix during the split, not after).\n\n`apps/marketing` stays here because it carries no truth authority and no\nruntime coupling. Moving it buys nothing and costs a deployment path.\n\n### 2.2 `integratewise-product`\n\n```\npackages/\n  domain/                application services; consumes canonical contracts, defines none\n  projections/           projection consumers\n  adk/                   agent contracts — not runtime\n  workbench-ui/          composition\n  ui-kit/                primitives\n  host-contracts/        adapter interface\nadapters/\n  web/  mcp/  plugin/    ← the three channels. Adapters, not repositories.\n  slack/  microsoft/  embedded/     ← future: folders, not repositories\napps/\n  web/                   browser Workbench\n  mcp-server/            IW-Spine-Network MCP\n  plugin-app/            IW-Spine-Network Plugin\n  preview/\n```\n\nConsumes `@integratewise/sdk` and `@integratewise/spine-schema`. **One** operational store.\n**One** agent-memory implementation. Three adapters over them.\n\n**No adapter may redefine canonical entities, governance policy or projection semantics.**\nThe falsifiable test: the same `packages/domain` serves all three apps, and an adapter\ncontains no policy and no canonical schema.\n\n### 2.3 Agents — resolving the ambiguity\n\nThe original proposal placed agents in both the monorepo and each frontend. That cannot hold:\ntwo Twin implementations is a Twin Law violation.\n\n| Concern                                                                       | Repo         | Reason                                                 |\n| ----------------------------------------------------------------------------- | ------------ | ------------------------------------------------------ |\n| Agent **runtime** (reasoning, tool invocation, model routing)                 | **Platform** | Needs Spine access and sits behind the governance gate |\n| Agent **contracts** (Twin · Triage · Governance · Entity Resolver · Evidence) | **Product**  | Consumed as types; defined once                        |\n| Agent **working memory** and session state                                    | **Product**  | Operational, high-churn, session-scoped                |\n| Model providers and model selection                                           | **Platform** | Policy decision, not a surface decision                |\n\nIn `plugin_host` the platform ships **no inference at all** — the host's model reasons, and\nIntegrateWise supplies tools, truth, memory, governance and UI. The agent runtime in Platform\nserves the `web` and `mcp_workbench` channels.\n\n---\n\n## 3. The SDK is not a boundary yet\n\nVerified at HEAD: `@integratewise/sdk` has **zero dependencies** and **six consumers, all\ninside `services/gateway`**. Nothing in `apps/web` imports it.\n\nMaking an unexercised interface the contract between two repositories is how contracts get\nfrozen wrong. Therefore:\n\n1. **Before the split** — make `apps/web` consume the SDK for at least one real path\n   (`/api/v1/workspace/discovery` is the obvious candidate; it is already the first canonical\n   read). If the SDK cannot serve that path, the split has found a gap and the gap is the\n   work.\n2. **During the split** — publish `@integratewise/sdk` and `@integratewise/spine-schema` at\n   **`0.x`, explicitly unstable**, with a note that the contract is not frozen until S0 closes.\n3. **After S0 closes** — freeze to `1.0`. Not before. A `1.0` around a canonical store that\n   does not persist is a promise about behaviour nobody has observed.\n\nConsume via workspace link or a local registry during the transition; publish to npm only\nonce the registry authorisation gate (architecture step 2) has passed.\n\n---\n\n## 4. Profiles are runtime data, not repository structure\n\n`development` · `customer_zero` · `external` apply within both repositories. They are\n**not** branches, directories, build variants or separate deployments of the same code.\n\n```\nProfile   ×   Surface   =   deployment configuration\n                            (not a codebase, not a build)\n\nper repo:  one build per surface (dev · test · prod)\n           profile resolved server-side at the Gateway\n           returned in the capability manifest\n```\n\nOnly five modules vary by profile — MCP Pool administration, Capability Manager,\nAdministration, Billing, Deployments (architecture §15.1). Everything else varies by _tenant\nscope_, which RBAC already handles.\n\n**If profile becomes a build variant you get nine artifacts to keep in sync and eighteen new\ndrift sites** — precisely the outcome §15.1 exists to prevent. The frontend never computes\nthe profile table and never receives the definitions of modules its profile excludes.\n\nEnvironment isolation is unchanged and now spans two repos: no `env.test` target may equal\nany `env.prod` target, for any binding class, in either repository.\n\n---\n\n## 5. Migration sequence\n\nDecision of 2026-07-31: **split now, repair inside the new structure.** That is workable, but\nthe ordering below is not negotiable — step 0 exists because the window between split and\nrepair is the dangerous part.\n\n| #     | Step                                                                                                                                                   | Why here                                                                                                                                                                                                                                                                                 |\n| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **0** | **Land the S0 hard-fail in the split commit.** Replace the `console.warn` swallow so a failed or skipped canonical write cannot return `success: true` | **Non-negotiable.** During the transition the Product repo builds against canonical persistence it cannot see. Today that path reports success and writes nothing. Split without this and the new repo receives silent lies instead of errors — with the Platform code no longer in view |\n| 1     | Freeze the shared contract surface: `spine-schema`, `types`, `contracts/shared-workbench`. Version at `0.x` unstable                                   | These become a cross-repo API the moment the split lands                                                                                                                                                                                                                                 |\n| 2     | Make `apps/web` consume the SDK on one real path                                                                                                       | Proves the seam before it becomes a boundary (§3)                                                                                                                                                                                                                                        |\n| 3     | Add `\"private\": true` to the 16 unmarked packages                                                                                                      | Cheaper now than after; prevents accidental publish from either repo                                                                                                                                                                                                                     |\n| 4     | Create `integratewise-product`; move `apps/web`, UI packages, adapters. Preserve git history (`git subtree split` or `filter-repo`)                    | The move itself                                                                                                                                                                                                                                                                          |\n| 5     | Wire Product → Platform via workspace link, then published `0.x`                                                                                       |                                                                                                                                                                                                                                                                                          |\n| 6     | Repair S0 fully — route canonical writes through `SPINE` to Neon; delete `CANONICAL_SPINE_DB`                                                          | In Platform, where it lives                                                                                                                                                                                                                                                              |\n| 7     | Resolve S8 — one surviving Spine writer; retire `pipeline/src/spine/`                                                                                  |                                                                                                                                                                                                                                                                                          |\n| 8     | Wire Hermes; add `spine` to `CORE_SERVICES`                                                                                                            |                                                                                                                                                                                                                                                                                          |\n| 9     | Repair the 15 dangling bindings and 5 test/prod leaks **in both repos**; extend `validate-platform-deployment.sh`                                      | Now a two-repo invariant                                                                                                                                                                                                                                                                 |\n| 10    | Consolidate the three memory scopes into one Product implementation; add `agent_memory` to D1 **before** retiring `pipeline/src/spine/`                | Sole definition of `agent_memory` is inside the file being deleted                                                                                                                                                                                                                       |\n| 11    | Prove one connector lifecycle and one governed action end to end                                                                                       | Architecture Appendix K, 13–14                                                                                                                                                                                                                                                           |\n| 12    | Freeze contracts to `1.0`                                                                                                                              | Only now is there observed behaviour to promise                                                                                                                                                                                                                                          |\n\n### 5.1 Risk this sequence accepts\n\nSplitting before repair means that between steps 4 and 6, the Product repo is built against a\ncanonical store that does not persist. Step 0 converts that from silent to loud, which is the\nwhole mitigation. It does not eliminate the risk — it makes it visible on the first failing\nwrite instead of the first missing record months later.\n\nThe second accepted risk: cross-repo changes during steps 6–10 require coordinated commits.\nFor a team of one to three, that cost is real. It is the price of the chosen sequencing and\nshould be spent deliberately, not discovered.\n\n---\n\n## 6. Invariants\n\n1. Exactly **one** canonical writer, in Platform. Product proposes; Platform commits\n2. Synchronisation operational → canonical is **one-way, through the promotion gate**\n3. No adapter redefines canonical entities, governance policy or projection semantics\n4. The same `packages/domain` serves web, MCP and plugin apps\n5. Profile is resolved server-side and never becomes a build variant\n6. Only `@integratewise/sdk` and `@integratewise/spine-schema` are publishable, from Platform\n7. No `env.test` target equals any `env.prod` target, in either repository, for any binding class\n8. A canonical write that fails or is skipped **never** returns success\n9. Neither repository contains a second credential store, provider-execution path or canonical database\n\n---\n\n## 7. Open questions\n\n| #   | Question                                                                  | Blocks                                                                  |\n| --- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------- |\n| R1  | Does `apps/marketing` stay in Platform, or move to its own deployment?    | Low-risk either way; default is stay                                    |\n| R2  | Workspace link or published `0.x` during steps 4–11?                      | Link is faster; published is closer to the end state                    |\n| R3  | Do `apps/mobile` and `apps/desktop` (10 files combined) move, or archive? | Architecture Tier 5 already asks for a verdict                          |\n| R4  | Who owns `contracts/shared-workbench` after the split?                    | Currently the only versioned cross-surface contract outside `packages/` |\n\n---\n\n**Related:** [Architecture §8, §15.5, §16.7](../../architecture/INTEGRATEWISE_ARCHITECTURE.md) ·\n[Host-Aware Continuity Runtime Spec §19](../../architecture/HOST_AWARE_CONTINUITY_RUNTIME_SPEC.md) ·\n[Marketplace Channels and Data Flow Spec](../surfaces/MARKETPLACE_CHANNELS_AND_DATA_FLOW_SPEC.md)\n"}