[
  {
    "id": "01-system-context",
    "title": "Search Indexing Service — System Context",
    "layout": "context",
    "colWidth": 260,
    "canvas": {
      "width": 1760
    },
    "system": {
      "label": "Search Indexing Service",
      "sub": "Index lifecycle + query"
    },
    "groups": [
      {
        "side": "left",
        "title": "People",
        "nodes": [
          {
            "id": "diner",
            "label": "Consumer",
            "kind": "actor",
            "sub": "40 M MAU",
            "rel": "searches",
            "dir": "in"
          },
          {
            "id": "merchant",
            "label": "Merchant",
            "kind": "actor",
            "sub": "180 k active",
            "rel": "edits listings",
            "dir": "in"
          },
          {
            "id": "srch",
            "label": "Search Engineer",
            "kind": "actor",
            "rel": "tunes relevance",
            "dir": "in"
          },
          {
            "id": "plat",
            "label": "Platform SRE",
            "kind": "actor",
            "rel": "reindex, rollback",
            "dir": "in"
          }
        ]
      },
      {
        "side": "top",
        "title": "Systems of record (owned elsewhere)",
        "nodes": [
          {
            "id": "inv",
            "label": "Inventory Service",
            "kind": "external",
            "sub": "DynamoDB",
            "rel": "stock",
            "dir": "in",
            "kind2": "async"
          },
          {
            "id": "cat",
            "label": "Catalogue Service",
            "kind": "external",
            "sub": "Aurora PostgreSQL",
            "rel": "stream",
            "dir": "in",
            "kind2": "async"
          },
          {
            "id": "mer",
            "label": "Merchant Service",
            "kind": "external",
            "rel": "push",
            "dir": "in",
            "kind2": "async"
          }
        ]
      },
      {
        "side": "right",
        "title": "Consuming products",
        "nodes": [
          {
            "id": "app",
            "label": "Mobile & Web Apps",
            "kind": "external",
            "rel": "query API"
          },
          {
            "id": "disc",
            "label": "Discovery & Feeds",
            "kind": "external",
            "rel": "query API"
          },
          {
            "id": "ops",
            "label": "Merchant Console",
            "kind": "external",
            "rel": "own-listing search"
          }
        ]
      },
      {
        "side": "bottom",
        "title": "Platform dependencies",
        "nodes": [
          {
            "id": "enr",
            "label": "Enrichment Services",
            "kind": "external",
            "sub": "categorise, geocode, score",
            "rel": "best-effort",
            "kind2": "error"
          },
          {
            "id": "iam",
            "label": "IAM & KMS",
            "kind": "security",
            "rel": "identity, keys"
          },
          {
            "id": "obs",
            "label": "Observability",
            "kind": "platform",
            "sub": "CloudWatch, Grafana",
            "rel": "signals"
          }
        ]
      }
    ],
    "note": "Out of scope: the search UI, semantic/embedding retrieval, the systems of record, the analytics warehouse.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "02-high-level-architecture",
    "title": "High-Level Architecture — Change to Searchable, and Index to Answer",
    "layout": "flow",
    "chain": true,
    "align": "middle",
    "canvas": {
      "width": 1760
    },
    "stages": [
      {
        "title": "Capture",
        "nodes": [
          {
            "id": "cdc",
            "label": "Change Capture",
            "kind": "integration",
            "sub": "streams + push API"
          }
        ]
      },
      {
        "title": "Change log",
        "nodes": [
          {
            "id": "log",
            "label": "Change Log",
            "kind": "queue",
            "sub": "MSK · 7 d replayable"
          }
        ]
      },
      {
        "title": "Assemble",
        "nodes": [
          {
            "id": "asm",
            "label": "Document Assembly",
            "kind": "app",
            "sub": "join · fan-out · enrich"
          },
          {
            "id": "st",
            "label": "Assembly State",
            "kind": "store",
            "sub": "DynamoDB"
          }
        ]
      },
      {
        "title": "Write",
        "nodes": [
          {
            "id": "fast",
            "label": "Fast Lane Writer",
            "kind": "app",
            "sub": "partial update"
          },
          {
            "id": "slow",
            "label": "Slow Lane Writer",
            "kind": "app",
            "sub": "whole document"
          }
        ]
      },
      {
        "title": "Index",
        "nodes": [
          {
            "id": "live",
            "label": "idx_v41 (live)",
            "kind": "store",
            "sub": "OpenSearch"
          },
          {
            "id": "bld",
            "label": "idx_v42 (building)",
            "kind": "store",
            "sub": "reindex target"
          }
        ]
      },
      {
        "title": "Alias",
        "nodes": [
          {
            "id": "al",
            "label": "Alias + Swap Gate",
            "kind": "integration",
            "sub": "the only contract"
          }
        ]
      },
      {
        "title": "Answer",
        "nodes": [
          {
            "id": "q",
            "label": "Query Service",
            "kind": "app",
            "sub": "pre-filter · cursor"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "al",
        "to": "live",
        "kind": "sync"
      },
      {
        "from": "bld",
        "to": "al",
        "label": "gated swap",
        "kind": "async"
      }
    ],
    "note": "The swap gate sits between the index and the reader: no reader ever names an index.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "03-actors-and-journeys",
    "title": "Actors and Their Core Journeys",
    "layout": "actors",
    "cardWidth": 270,
    "canvas": {
      "width": 1740
    },
    "groups": [
      {
        "title": "People who search",
        "kind": "boundary",
        "actors": [
          {
            "id": "diner",
            "label": "Consumer",
            "sub": "40 M monthly",
            "goal": "Show me things I can actually have right now, not things that existed this morning.",
            "journeys": [
              {
                "id": "j-find",
                "label": "Find something that exists",
                "sub": "15 k queries/s"
              },
              {
                "label": "Browse a filtered category"
              }
            ]
          }
        ]
      },
      {
        "title": "People who publish",
        "kind": "boundary",
        "actors": [
          {
            "id": "merchant",
            "label": "Merchant",
            "sub": "180 k active",
            "goal": "When I change my price, I want to see my own listing change — and believe it.",
            "journeys": [
              {
                "id": "j-publish",
                "label": "Publish a change",
                "sub": "p95 ≤ 2 s fast lane"
              },
              {
                "label": "Check my own listing"
              }
            ]
          },
          {
            "id": "ops",
            "label": "Catalogue Ops",
            "sub": "bulk editor",
            "goal": "Rename a brand across two million listings without breaking anyone's search.",
            "journeys": [
              {
                "label": "Run a bulk parent edit"
              }
            ]
          }
        ]
      },
      {
        "title": "People who own the index",
        "kind": "cloud",
        "actors": [
          {
            "id": "srch",
            "label": "Search Engineer",
            "sub": "relevance owner",
            "goal": "Ship a ranking change I can prove helped, and undo it in a minute if it did not.",
            "journeys": [
              {
                "id": "j-relev",
                "label": "Ship a relevance change",
                "sub": "gate + variant split"
              },
              {
                "label": "Add a judgement set"
              }
            ]
          },
          {
            "id": "sre",
            "label": "Platform SRE",
            "sub": "on call",
            "goal": "Rebuild any index inside the RTO, and never be the person who hand-edits a live one.",
            "journeys": [
              {
                "label": "Run a gated reindex"
              },
              {
                "label": "Roll back by alias"
              }
            ]
          }
        ]
      },
      {
        "title": "Machines in the cast",
        "kind": "cloud",
        "actors": [
          {
            "id": "src",
            "label": "Source Systems",
            "kind": "external",
            "sub": "4 integrated",
            "goal": "Emit my changes once and never be asked to serve a full table scan at 3am.",
            "journeys": [
              {
                "label": "Emit a change stream"
              },
              {
                "label": "Export a daily snapshot"
              }
            ]
          },
          {
            "id": "rec",
            "label": "Reconciler",
            "kind": "platform",
            "sub": "1 M docs/day",
            "goal": "Find the document nobody reported missing.",
            "journeys": [
              {
                "label": "Sample and compare"
              }
            ]
          }
        ]
      }
    ],
    "note": "The reconciler is in the cast because the platform's worst failure has no complainant.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "04-journey-find-something-that-exists",
    "title": "Journey — A Consumer Finds Something That Exists",
    "layout": "journey",
    "canvas": {
      "width": 1700
    },
    "actor": {
      "label": "Consumer",
      "sub": "mobile, 8pm",
      "goal": "Eat in forty minutes without being told no three times",
      "trigger": "Hungry, opens the app, types two words",
      "success": "Orders the thing they searched for, first try"
    },
    "phases": [
      {
        "title": "Type",
        "sub": "two words"
      },
      {
        "title": "Scan results"
      },
      {
        "title": "Filter",
        "sub": "open now"
      },
      {
        "title": "Tap",
        "moment": true
      },
      {
        "title": "Order",
        "moment": true
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "\"biryani\""
            }
          ],
          [
            {
              "label": "Reads top 10"
            }
          ],
          [
            {
              "label": "Applies filters"
            }
          ],
          [
            {
              "label": "Taps result 3"
            }
          ],
          [
            {
              "label": "Adds to basket"
            }
          ]
        ]
      },
      {
        "title": "What answers",
        "kind": "system",
        "cells": [
          [
            {
              "label": "Query service"
            }
          ],
          [
            {
              "label": "Alias → idx_v41"
            }
          ],
          [
            {
              "label": "Pre-retrieval filter"
            }
          ],
          [
            {
              "label": "Item page, live stock"
            }
          ],
          [
            {
              "label": "Basket service"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "Trusts it",
          "Fine",
          "Stops trusting"
        ],
        "points": [
          1,
          1,
          1,
          0,
          2
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [],
          [],
          [
            {
              "label": "Facet count ≠ results"
            }
          ],
          [
            {
              "label": "\"Closed\" after the tap"
            }
          ],
          []
        ]
      },
      {
        "title": "What the design owes",
        "kind": "gain",
        "cells": [
          [],
          [
            {
              "label": "Freshness on response"
            }
          ],
          [
            {
              "label": "Filter before retrieval"
            }
          ],
          [
            {
              "label": "Fast lane ≤ 2 s p95"
            }
          ],
          [
            {
              "label": "Deletion ≤ 5 s p99"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The trough is the tap: a stale availability field is caught one screen after the search that looked fine.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "05-journey-publish-a-change",
    "title": "Journey — A Merchant Publishes a Change",
    "layout": "journey",
    "canvas": {
      "width": 1700
    },
    "actor": {
      "label": "Merchant",
      "sub": "one shop, phone",
      "goal": "Drop the price before the evening rush and know it took",
      "trigger": "Quiet hour, stock to move",
      "success": "Searches their own shop, sees the new price"
    },
    "phases": [
      {
        "title": "Edit",
        "sub": "merchant console"
      },
      {
        "title": "Save"
      },
      {
        "title": "Check",
        "moment": true
      },
      {
        "title": "Wait"
      },
      {
        "title": "Believe"
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Changes price"
            }
          ],
          [
            {
              "label": "Taps save"
            }
          ],
          [
            {
              "label": "Searches own shop"
            }
          ],
          [
            {
              "label": "Refreshes"
            }
          ],
          [
            {
              "label": "Stops checking"
            }
          ]
        ]
      },
      {
        "title": "What answers",
        "kind": "system",
        "cells": [
          [
            {
              "label": "Merchant service"
            }
          ],
          [
            {
              "label": "Change log commit"
            }
          ],
          [
            {
              "label": "Owner-write overlay"
            }
          ],
          [
            {
              "label": "Fast lane writer"
            }
          ],
          [
            {
              "label": "idx_v41"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "Confident",
          "Unsure",
          "Distrusts"
        ],
        "points": [
          1,
          1,
          0,
          1,
          0
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [],
          [],
          [
            {
              "label": "Old price still shown"
            }
          ],
          [
            {
              "label": "No idea how long"
            }
          ],
          []
        ]
      },
      {
        "title": "What the design owes",
        "kind": "gain",
        "cells": [
          [],
          [
            {
              "label": "Ack on durable commit"
            }
          ],
          [
            {
              "label": "Read-your-writes ≤ 1 s"
            }
          ],
          [
            {
              "label": "Freshness in response"
            }
          ],
          [
            {
              "label": "Fast lane, not a rebuild"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The one merchant who checks sets the read-your-writes requirement — not the freshness budget for 80 M documents.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "06-journey-ship-a-relevance-change",
    "title": "Journey — A Search Engineer Ships a Relevance Change",
    "layout": "journey",
    "canvas": {
      "width": 1700
    },
    "actor": {
      "label": "Search Engineer",
      "sub": "owns relevance",
      "goal": "Make \"biryani\" rank dishes above shop names, provably",
      "trigger": "A support thread full of the same complaint",
      "success": "A measured win, live, reversible in a minute"
    },
    "phases": [
      {
        "title": "Hypothesise"
      },
      {
        "title": "Measure offline",
        "moment": true
      },
      {
        "title": "Promote"
      },
      {
        "title": "Split traffic",
        "moment": true
      },
      {
        "title": "Keep or revert"
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Edits boosts"
            }
          ],
          [
            {
              "label": "Runs judgement set"
            }
          ],
          [
            {
              "label": "Promotes version"
            }
          ],
          [
            {
              "label": "Sets 10% split"
            }
          ],
          [
            {
              "label": "Reads variant metrics"
            }
          ]
        ]
      },
      {
        "title": "What answers",
        "kind": "system",
        "cells": [
          [
            {
              "label": "Definition registry"
            }
          ],
          [
            {
              "label": "Evaluation service"
            }
          ],
          [
            {
              "label": "Swap gate"
            }
          ],
          [
            {
              "label": "Alias, two variants"
            }
          ],
          [
            {
              "label": "Engagement log"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "In control",
          "Uneasy",
          "Blocked"
        ],
        "points": [
          1,
          1,
          2,
          1,
          0
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [],
          [
            {
              "label": "No judgement set yet"
            }
          ],
          [
            {
              "label": "Analysis change = rebuild"
            }
          ],
          [],
          []
        ]
      },
      {
        "title": "What the design owes",
        "kind": "gain",
        "cells": [
          [],
          [
            {
              "label": "Offline metric vs live"
            }
          ],
          [
            {
              "label": "Says which class it is"
            }
          ],
          [
            {
              "label": "Per-variant metrics"
            }
          ],
          [
            {
              "label": "Rollback ≤ 60 s"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The trough is promotion: an index-time change is a four-hour rebuild, and the platform must say so before it is asked for.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "07-layered-architecture",
    "title": "Layered Architecture — Eight Layers and One Seam",
    "layout": "bands",
    "layerHeaderWidth": 170,
    "canvas": {
      "width": 1700
    },
    "bands": [
      {
        "name": "Sources",
        "nodes": [
          {
            "id": "cat",
            "label": "Catalogue",
            "kind": "external"
          },
          {
            "id": "inv",
            "label": "Inventory",
            "kind": "external"
          },
          {
            "id": "mer",
            "label": "Merchant",
            "kind": "external"
          },
          {
            "id": "con",
            "label": "Content",
            "kind": "external"
          }
        ]
      },
      {
        "name": "Capture",
        "nodes": [
          {
            "id": "cdc",
            "label": "Stream Capture",
            "kind": "integration",
            "sub": "DMS / Streams"
          },
          {
            "id": "push",
            "label": "Push Ingest API",
            "kind": "integration",
            "sub": "API Gateway"
          },
          {
            "id": "ded",
            "label": "Dedup + Version Guard",
            "kind": "app"
          },
          {
            "id": "pq",
            "label": "Poison Quarantine",
            "kind": "risk"
          }
        ]
      },
      {
        "name": "Change log",
        "nodes": [
          {
            "id": "log",
            "label": "Change Log — system of record for what changed",
            "kind": "queue",
            "sub": "MSK · partitioned by entity key"
          }
        ]
      },
      {
        "name": "Assembly",
        "nodes": [
          {
            "id": "join",
            "label": "Join by Declared Keys",
            "kind": "app"
          },
          {
            "id": "fan",
            "label": "Parent Fan-out",
            "kind": "app",
            "sub": "rate-limited, resumable"
          },
          {
            "id": "enr",
            "label": "Enrichment",
            "kind": "app",
            "sub": "timeout + fallback"
          }
        ]
      },
      {
        "name": "Writers",
        "nodes": [
          {
            "id": "fastw",
            "label": "Fast Lane Writer",
            "kind": "app",
            "sub": "partial update"
          },
          {
            "id": "sloww",
            "label": "Slow Lane Writer",
            "kind": "app",
            "sub": "whole document"
          },
          {
            "id": "rew",
            "label": "Reindex Writer",
            "kind": "app",
            "sub": "throttled share"
          }
        ]
      },
      {
        "name": "Indices",
        "nodes": [
          {
            "id": "live",
            "label": "idx_v41 live",
            "kind": "store"
          },
          {
            "id": "bld",
            "label": "idx_v42 building",
            "kind": "store"
          },
          {
            "id": "prev",
            "label": "idx_v40 retained 72 h",
            "kind": "store"
          }
        ]
      },
      {
        "name": "Alias + gate",
        "nodes": [
          {
            "id": "al",
            "label": "Alias",
            "kind": "integration"
          },
          {
            "id": "gate",
            "label": "Acceptance Gate",
            "kind": "decision",
            "sub": "count · diff · judgement"
          }
        ]
      },
      {
        "name": "Query",
        "nodes": [
          {
            "id": "q",
            "label": "Query Service",
            "kind": "app"
          },
          {
            "id": "ov",
            "label": "Owner-Write Overlay",
            "kind": "app"
          },
          {
            "id": "cc",
            "label": "Cost Ceiling",
            "kind": "security"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "log",
        "to": "join",
        "label": "replay",
        "kind": "async"
      },
      {
        "from": "gate",
        "to": "al",
        "label": "swap or refuse",
        "kind": "sync"
      }
    ],
    "note": "The seam: everything above the change log is about what changed; everything below is a projection of it.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "08-platform-components",
    "title": "Platform Components — One Region",
    "layout": "nested",
    "canvas": {
      "width": 1760
    },
    "boxes": [
      {
        "title": "AWS eu-west-1 — VPC, private subnets",
        "kind": "cloud",
        "dir": "col",
        "children": [
          {
            "title": "Control plane",
            "kind": "boundary",
            "nodes": [
              {
                "id": "adm",
                "label": "Admin & Definition API",
                "kind": "app",
                "sub": "ECS Fargate"
              },
              {
                "id": "reg",
                "label": "Definition Registry",
                "kind": "store",
                "sub": "Aurora PostgreSQL"
              },
              {
                "id": "orc",
                "label": "Reindex Orchestrator",
                "kind": "app",
                "sub": "Step Functions"
              },
              {
                "id": "ev",
                "label": "Evaluation Service",
                "kind": "app",
                "sub": "judgement sets"
              }
            ]
          },
          {
            "title": "Write plane",
            "kind": "boundary",
            "nodes": [
              {
                "id": "cap",
                "label": "Capture Tier",
                "kind": "integration",
                "sub": "DMS + Streams"
              },
              {
                "id": "log",
                "label": "Change Log",
                "kind": "queue",
                "sub": "MSK"
              },
              {
                "id": "asm",
                "label": "Assembly Workers",
                "kind": "app",
                "sub": "ECS Fargate"
              },
              {
                "id": "st",
                "label": "Assembly State",
                "kind": "store",
                "sub": "DynamoDB"
              },
              {
                "id": "wr",
                "label": "Index Writers",
                "kind": "app",
                "sub": "fast / slow / reindex"
              }
            ]
          },
          {
            "title": "Search plane",
            "kind": "boundary",
            "nodes": [
              {
                "id": "os",
                "label": "OpenSearch Domain",
                "kind": "store",
                "sub": "3 AZ · 220 GB · 2 replicas"
              },
              {
                "id": "al",
                "label": "Alias Manager",
                "kind": "integration"
              },
              {
                "id": "q",
                "label": "Query Service",
                "kind": "app",
                "sub": "ECS Fargate"
              },
              {
                "id": "ow",
                "label": "Recent-Writes Table",
                "kind": "store",
                "sub": "DynamoDB · TTL 60 s"
              }
            ]
          },
          {
            "title": "Assurance",
            "kind": "trust",
            "nodes": [
              {
                "id": "rec",
                "label": "Reconciler",
                "kind": "platform",
                "sub": "1 M docs/day"
              },
              {
                "id": "qz",
                "label": "Quarantine Store",
                "kind": "risk",
                "sub": "S3 · 30 d"
              },
              {
                "id": "aud",
                "label": "Audit Log",
                "kind": "security",
                "sub": "S3 Object Lock"
              }
            ]
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "src",
        "label": "Source Systems",
        "kind": "external"
      },
      {
        "id": "snap",
        "label": "Snapshot Store",
        "kind": "store",
        "sub": "S3 · daily"
      },
      {
        "id": "enr",
        "label": "Enrichment Services",
        "kind": "external"
      }
    ],
    "edges": [
      {
        "from": "src",
        "to": "cap",
        "label": "changes",
        "kind": "async"
      },
      {
        "from": "snap",
        "to": "orc",
        "label": "rebuild base",
        "kind": "batch"
      },
      {
        "from": "asm",
        "to": "enr",
        "label": "best-effort",
        "kind": "error"
      },
      {
        "from": "wr",
        "to": "os",
        "label": "bulk",
        "kind": "sync"
      },
      {
        "from": "q",
        "to": "ow",
        "label": "overlay",
        "kind": "sync"
      },
      {
        "from": "rec",
        "to": "os",
        "label": "sample",
        "kind": "batch"
      }
    ],
    "note": "Only the capture tier faces the sources, and only the query service faces callers. Twelve edges omitted; later views carry them.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "09-integration-surface",
    "title": "Integration Surface — Who Writes In, Who Reads Out",
    "layout": "hub",
    "canvas": {
      "width": 1760
    },
    "left": {
      "title": "Inbound",
      "nodes": [
        {
          "id": "cdcs",
          "label": "Source Change Streams",
          "kind": "external",
          "sub": "CDC + DynamoDB Streams",
          "rel": "stream",
          "kind2": "async"
        },
        {
          "id": "pushs",
          "label": "Push Ingest API",
          "kind": "integration",
          "sub": "signed, versioned",
          "rel": "HTTPS"
        },
        {
          "id": "snapi",
          "label": "Daily Snapshot Export",
          "kind": "store",
          "sub": "S3",
          "rel": "nightly",
          "kind2": "batch"
        },
        {
          "id": "admi",
          "label": "Definition API",
          "kind": "integration",
          "sub": "admin plane",
          "rel": "HTTPS"
        }
      ]
    },
    "centre": {
      "title": "Search Indexing Service",
      "nodes": [
        {
          "id": "core",
          "label": "Indexing & Query Platform",
          "kind": "app",
          "sub": "40 indices · 12 tenants"
        }
      ]
    },
    "right": {
      "title": "Outbound",
      "nodes": [
        {
          "id": "qapi",
          "label": "Query API",
          "kind": "integration",
          "sub": "alias-scoped",
          "rel": "HTTPS",
          "dir": "out"
        },
        {
          "id": "enro",
          "label": "Enrichment Calls",
          "kind": "external",
          "sub": "timeout + fallback",
          "rel": "best-effort",
          "dir": "out",
          "kind2": "error"
        },
        {
          "id": "eng",
          "label": "Engagement Log Sink",
          "kind": "store",
          "sub": "Firehose to S3",
          "rel": "sampled",
          "dir": "out",
          "kind2": "batch"
        },
        {
          "id": "audo",
          "label": "Audit Sink",
          "kind": "security",
          "sub": "Object Lock",
          "rel": "audit",
          "dir": "out"
        }
      ]
    },
    "note": "Four inbound surfaces with three different authorisation stories; the alias-swap privilege is not among them.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "10-indexing-data-flow",
    "title": "Data Flow — One Change, Seven States",
    "layout": "flow",
    "chain": true,
    "align": "top",
    "canvas": {
      "width": 1800
    },
    "stages": [
      {
        "title": "Committed",
        "nodes": [
          {
            "id": "s1",
            "label": "Source commit",
            "kind": "external",
            "sub": "authoritative"
          }
        ]
      },
      {
        "title": "Captured",
        "nodes": [
          {
            "id": "s2",
            "label": "Change event",
            "kind": "integration",
            "sub": "key + version"
          },
          {
            "id": "s2b",
            "label": "Rejected",
            "kind": "risk",
            "sub": "poison / drift"
          }
        ]
      },
      {
        "title": "Logged",
        "nodes": [
          {
            "id": "s3",
            "label": "Log record",
            "kind": "queue",
            "sub": "durable, acked"
          }
        ]
      },
      {
        "title": "Assembled",
        "nodes": [
          {
            "id": "s4",
            "label": "Document",
            "kind": "app",
            "sub": "joined + enriched"
          },
          {
            "id": "s4b",
            "label": "Degraded",
            "kind": "risk",
            "sub": "stale enrichment"
          }
        ]
      },
      {
        "title": "Written",
        "nodes": [
          {
            "id": "s5",
            "label": "Indexed",
            "kind": "store",
            "sub": "fast or slow lane"
          }
        ]
      },
      {
        "title": "Visible",
        "nodes": [
          {
            "id": "s6",
            "label": "Searchable",
            "kind": "store",
            "sub": "behind the alias"
          }
        ]
      },
      {
        "title": "Verified",
        "nodes": [
          {
            "id": "s7",
            "label": "Reconciled",
            "kind": "platform",
            "sub": "sampled vs source"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "s2",
        "to": "s2b",
        "label": "quarantine",
        "kind": "error"
      },
      {
        "from": "s4",
        "to": "s4b",
        "kind": "error"
      },
      {
        "from": "s7",
        "to": "s3",
        "kind": "batch",
        "route": "gutter"
      }
    ],
    "note": "Only two of the seven are authoritative: the source commit and the log record. The dotted return is the reconciler re-emitting a key it found missing.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "11-storage-zones",
    "title": "Storage Zones — Owned, Replayable, Rebuildable, Cold",
    "layout": "nested",
    "canvas": {
      "width": 1760
    },
    "boxes": [
      {
        "title": "Owned elsewhere — never backed up here",
        "kind": "onprem",
        "nodes": [
          {
            "id": "z1a",
            "label": "Catalogue DB",
            "kind": "external"
          },
          {
            "id": "z1b",
            "label": "Inventory Store",
            "kind": "external"
          },
          {
            "id": "z1c",
            "label": "Merchant DB",
            "kind": "external"
          }
        ]
      },
      {
        "title": "Replayable — the platform's own system of record",
        "kind": "boundary",
        "dir": "row",
        "children": [
          {
            "title": "Change log",
            "kind": "plain",
            "nodes": [
              {
                "id": "z2a",
                "label": "Change Log",
                "kind": "queue",
                "sub": "MSK · 7 d hot"
              },
              {
                "id": "z2b",
                "label": "Log Archive",
                "kind": "store",
                "sub": "S3 · 90 d"
              }
            ]
          },
          {
            "title": "Rebuild base",
            "kind": "plain",
            "nodes": [
              {
                "id": "z2c",
                "label": "Source Snapshots",
                "kind": "store",
                "sub": "S3 · daily, 30 d"
              }
            ]
          }
        ]
      },
      {
        "title": "Strongly consistent and precious — backed up, PITR",
        "kind": "trust",
        "nodes": [
          {
            "id": "z3a",
            "label": "Definition Registry",
            "kind": "store",
            "sub": "Aurora · PITR"
          },
          {
            "id": "z3b",
            "label": "Aliases & Promotions",
            "kind": "store",
            "sub": "Aurora"
          },
          {
            "id": "z3c",
            "label": "Judgement Sets",
            "kind": "store",
            "sub": "Aurora"
          },
          {
            "id": "z3d",
            "label": "Audit Log",
            "kind": "security",
            "sub": "S3 Object Lock"
          }
        ]
      },
      {
        "title": "Rebuildable — not backed up, by decision",
        "kind": "boundary",
        "nodes": [
          {
            "id": "z4a",
            "label": "idx_v41 live",
            "kind": "store",
            "sub": "OpenSearch"
          },
          {
            "id": "z4b",
            "label": "idx_v40 retained",
            "kind": "store",
            "sub": "72 h rollback"
          },
          {
            "id": "z4c",
            "label": "Assembly State",
            "kind": "store",
            "sub": "DynamoDB"
          },
          {
            "id": "z4d",
            "label": "Enrichment Cache",
            "kind": "store",
            "sub": "DynamoDB"
          },
          {
            "id": "z4e",
            "label": "Recent Writes",
            "kind": "store",
            "sub": "TTL 60 s"
          }
        ]
      },
      {
        "title": "Cold — evidence and evaluation",
        "kind": "plain",
        "nodes": [
          {
            "id": "z5a",
            "label": "Query & Engagement Log",
            "kind": "store",
            "sub": "S3 · 400 d"
          },
          {
            "id": "z5b",
            "label": "Quarantined Payloads",
            "kind": "risk",
            "sub": "S3 · 30 d"
          },
          {
            "id": "z5c",
            "label": "Retired Index Archive",
            "kind": "store",
            "sub": "S3 Glacier"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "z2c",
        "to": "z4a",
        "label": "rebuild",
        "kind": "batch"
      },
      {
        "from": "z2a",
        "to": "z4a",
        "label": "catch-up",
        "kind": "async"
      }
    ],
    "note": "A search index is deliberately in the rebuildable zone: snapshots of it would be a recovery-time optimisation, never a durability claim.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "12-data-model",
    "title": "Data Model — Definitions, Documents and Evidence",
    "layout": "er",
    "canvas": {
      "width": 1740,
      "cols": 4
    },
    "rowGap": 240,
    "entities": [
      {
        "id": "tenant",
        "name": "tenant",
        "kind": "store",
        "row": 0,
        "col": 0,
        "attrs": [
          "tenant_id  PK",
          "quota_docs",
          "quota_index_rate",
          "placement  shared|dedicated"
        ]
      },
      {
        "id": "idxdef",
        "name": "index_definition",
        "kind": "store",
        "row": 0,
        "col": 1,
        "attrs": [
          "definition_id  PK",
          "tenant_id  FK -> tenant",
          "version  immutable",
          "document_shape",
          "analysis_config",
          "freshness_classes",
          "relevance_config"
        ]
      },
      {
        "id": "source",
        "name": "source_binding",
        "kind": "store",
        "row": 1,
        "col": 1,
        "attrs": [
          "binding_id  PK",
          "definition_id  FK",
          "source_name",
          "join_key",
          "capture_mode",
          "quiet_period_s"
        ]
      },
      {
        "id": "idx",
        "name": "index_version",
        "kind": "store",
        "row": 0,
        "col": 3,
        "attrs": [
          "index_name  PK",
          "definition_id  FK",
          "state  building|live|retained",
          "doc_count",
          "built_from_snapshot",
          "catchup_log_offset"
        ]
      },
      {
        "id": "alias",
        "name": "alias",
        "kind": "store",
        "row": 0,
        "col": 2,
        "attrs": [
          "alias_name  PK",
          "index_name  FK -> index_version",
          "variant_split",
          "swapped_at",
          "swapped_by"
        ]
      },
      {
        "id": "doc",
        "name": "document",
        "kind": "store",
        "row": 1,
        "col": 3,
        "attrs": [
          "entity_key  PK",
          "index_name  FK",
          "assembly_version",
          "source_versions  map",
          "degraded_flags",
          "assembled_at"
        ]
      },
      {
        "id": "ent",
        "name": "entity_state",
        "kind": "store",
        "row": 2,
        "col": 0,
        "attrs": [
          "entity_key  PK",
          "source_name  PK",
          "applied_version",
          "parent_key",
          "enrichment_ref"
        ]
      },
      {
        "id": "change",
        "name": "change_event",
        "kind": "store",
        "row": 1,
        "col": 0,
        "attrs": [
          "source_name  PK",
          "entity_key  PK",
          "source_version  PK",
          "change_type",
          "committed_at",
          "logged_at"
        ]
      },
      {
        "id": "fan",
        "name": "fanout_job",
        "kind": "store",
        "row": 2,
        "col": 1,
        "attrs": [
          "job_id  PK",
          "parent_key  FK -> entity_state",
          "children_total",
          "children_done",
          "rate_limit"
        ]
      },
      {
        "id": "job",
        "name": "reindex_job",
        "kind": "store",
        "row": 2,
        "col": 3,
        "attrs": [
          "job_id  PK",
          "index_name  FK -> index_version",
          "checkpoints  per partition",
          "gate_result",
          "started_at"
        ]
      },
      {
        "id": "jud",
        "name": "judgement_set",
        "kind": "store",
        "row": 2,
        "col": 2,
        "attrs": [
          "set_id  PK",
          "definition_id  FK",
          "query",
          "entity_key",
          "grade"
        ]
      },
      {
        "id": "qlog",
        "name": "query_event",
        "kind": "store",
        "row": 1,
        "col": 2,
        "attrs": [
          "query_id  PK",
          "alias_name  FK -> alias",
          "index_name",
          "relevance_version",
          "results",
          "engagement"
        ]
      }
    ],
    "relations": [
      {
        "from": "tenant",
        "to": "idxdef",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "idxdef",
        "to": "alias",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "alias",
        "to": "idx",
        "label": "N : 1",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "idxdef",
        "to": "source",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "alias",
        "to": "qlog",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "idx",
        "to": "doc",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "source",
        "to": "change",
        "label": "1 : N",
        "from_side": "w",
        "to_side": "e"
      },
      {
        "from": "change",
        "to": "ent",
        "label": "N : 1",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "ent",
        "to": "fan",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "qlog",
        "to": "jud",
        "label": "sampled",
        "from_side": "s",
        "to_side": "n",
        "kind": "optional"
      },
      {
        "from": "job",
        "to": "doc",
        "label": "1 : N",
        "from_side": "n",
        "to_side": "s"
      }
    ],
    "note": "The composite key (source, entity_key, source_version) is what makes redelivery a primary-key collision rather than a regression. Checkpoint and quota tables are omitted.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "13-critical-flow-change-to-searchable",
    "title": "Critical Flow — A Price Change Becomes Searchable",
    "layout": "sequence",
    "canvas": {
      "width": 1760
    },
    "lifelines": [
      {
        "id": "src",
        "label": "Inventory Source",
        "kind": "external"
      },
      {
        "id": "cap",
        "label": "Capture Tier",
        "kind": "integration"
      },
      {
        "id": "log",
        "label": "Change Log",
        "kind": "queue"
      },
      {
        "id": "asm",
        "label": "Assembly",
        "kind": "app"
      },
      {
        "id": "st",
        "label": "Assembly State",
        "kind": "store"
      },
      {
        "id": "wr",
        "label": "Fast Lane Writer",
        "kind": "app"
      },
      {
        "id": "os",
        "label": "idx_v41",
        "kind": "store"
      },
      {
        "id": "q",
        "label": "Query Service",
        "kind": "app"
      }
    ],
    "messages": [
      {
        "from": "src",
        "to": "cap",
        "label": "price changed, v812",
        "kind": "async"
      },
      {
        "from": "cap",
        "to": "cap",
        "label": "schema check",
        "kind": "self"
      },
      {
        "from": "cap",
        "to": "st",
        "label": "applied version?",
        "kind": "call"
      },
      {
        "from": "st",
        "to": "cap",
        "label": "v811",
        "kind": "return"
      },
      {
        "from": "cap",
        "to": "log",
        "label": "append (key, v812)",
        "kind": "call"
      },
      {
        "from": "log",
        "to": "cap",
        "label": "committed",
        "kind": "return"
      },
      {
        "from": "cap",
        "to": "src",
        "label": "ack",
        "kind": "return"
      },
      {
        "from": "log",
        "to": "asm",
        "label": "fast-lane consume",
        "kind": "async"
      },
      {
        "from": "asm",
        "to": "st",
        "label": "guard + record v812",
        "kind": "call"
      },
      {
        "from": "asm",
        "to": "wr",
        "label": "partial update",
        "kind": "call"
      },
      {
        "from": "wr",
        "to": "os",
        "label": "bulk upsert",
        "kind": "call"
      },
      {
        "from": "os",
        "to": "wr",
        "label": "refreshed",
        "kind": "return"
      },
      {
        "from": "q",
        "to": "os",
        "label": "search via alias",
        "kind": "call"
      },
      {
        "from": "os",
        "to": "q",
        "label": "hits + index version",
        "kind": "return"
      },
      {
        "from": "q",
        "to": "q",
        "label": "attach freshness",
        "kind": "self"
      }
    ],
    "note": "Message 7 is the acknowledgement: the source is free once the change is durable, not once it is searchable.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "14-reindex-and-swap",
    "title": "Reindex and Swap — Build Beside, Gate, Move the Alias",
    "layout": "flow",
    "chain": true,
    "align": "top",
    "canvas": {
      "width": 1800
    },
    "stages": [
      {
        "title": "Trigger",
        "nodes": [
          {
            "id": "r1",
            "label": "Breaking definition change",
            "kind": "decision"
          },
          {
            "id": "r1b",
            "label": "Scheduled rehearsal",
            "kind": "platform"
          }
        ]
      },
      {
        "title": "Plan",
        "nodes": [
          {
            "id": "r2",
            "label": "Dry Run",
            "kind": "app",
            "sub": "duration · storage · cost"
          },
          {
            "id": "r2b",
            "label": "Budget Ack",
            "kind": "decision",
            "sub": "above threshold"
          }
        ]
      },
      {
        "title": "Build",
        "nodes": [
          {
            "id": "r3",
            "label": "Snapshot Replay",
            "kind": "app",
            "sub": "≥ 8 k docs/s"
          },
          {
            "id": "r3b",
            "label": "Partition Checkpoints",
            "kind": "store",
            "sub": "resume, not restart"
          }
        ]
      },
      {
        "title": "Catch up",
        "nodes": [
          {
            "id": "r4",
            "label": "Log Catch-up",
            "kind": "app",
            "sub": "to fast-lane budget"
          }
        ]
      },
      {
        "title": "Gate",
        "nodes": [
          {
            "id": "r5",
            "label": "Doc Count",
            "kind": "decision"
          },
          {
            "id": "r5b",
            "label": "Sampled Diff",
            "kind": "decision"
          },
          {
            "id": "r5c",
            "label": "Judgement Score",
            "kind": "decision"
          }
        ]
      },
      {
        "title": "Swap",
        "nodes": [
          {
            "id": "r6",
            "label": "Alias Move",
            "kind": "integration",
            "sub": "atomic per reader"
          }
        ]
      },
      {
        "title": "Settle",
        "nodes": [
          {
            "id": "r7",
            "label": "idx_v40 retained 72 h",
            "kind": "store"
          },
          {
            "id": "r7b",
            "label": "Rollback = alias move",
            "kind": "opportunity",
            "sub": "RTO 1 min"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "r5",
        "to": "r3",
        "label": "refuse, resume",
        "kind": "error"
      },
      {
        "from": "r4",
        "to": "r4",
        "label": "lag > budget: hold",
        "kind": "error"
      }
    ],
    "note": "Reindex writes take a reserved share of cluster capacity: a rebuild may not raise query p99 by more than 15%.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "15-freshness-lanes",
    "title": "Freshness Lanes — Two Budgets Through One Pipeline",
    "layout": "swimlane",
    "canvas": {
      "width": 1780
    },
    "laneHeaderWidth": 180,
    "stages": [
      "Capture",
      "Assemble",
      "Write",
      "Visible",
      "Budget"
    ],
    "lanes": [
      {
        "title": "Fast lane — caught instantly",
        "cells": [
          [
            {
              "label": "Stock, price, hours",
              "kind": "integration"
            }
          ],
          [
            {
              "label": "Partial update",
              "kind": "app",
              "sub": "no re-enrichment"
            }
          ],
          [
            {
              "label": "Fast Lane Writer",
              "kind": "app"
            }
          ],
          [
            {
              "label": "idx_v41",
              "kind": "store"
            }
          ],
          [
            {
              "label": "p95 ≤ 2 s",
              "kind": "opportunity"
            }
          ]
        ]
      },
      {
        "title": "Suppression — no budget",
        "cells": [
          [
            {
              "label": "Delete, moderation",
              "kind": "integration"
            }
          ],
          [
            {
              "label": "No join needed",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Priority write",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Removed from candidates",
              "kind": "store"
            }
          ],
          [
            {
              "label": "p99 ≤ 5 s",
              "kind": "opportunity"
            }
          ]
        ]
      },
      {
        "title": "Slow lane — invisible for a minute",
        "cells": [
          [
            {
              "label": "Titles, attributes",
              "kind": "integration"
            }
          ],
          [
            {
              "label": "Full assembly + enrich",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Slow Lane Writer",
              "kind": "app"
            }
          ],
          [
            {
              "label": "idx_v41",
              "kind": "store"
            }
          ],
          [
            {
              "label": "p95 ≤ 60 s",
              "kind": "opportunity"
            }
          ]
        ]
      },
      {
        "title": "Parent fan-out — tracked job",
        "cells": [
          [
            {
              "label": "Brand, category rename",
              "kind": "integration"
            }
          ],
          [
            {
              "label": "Resolve children",
              "kind": "app",
              "sub": "rate-limited"
            }
          ],
          [
            {
              "label": "Batched writes",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Progress + ETA",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "2 M children ≤ 30 min",
              "kind": "opportunity"
            }
          ]
        ]
      },
      {
        "title": "Reindex — reserved capacity",
        "cells": [
          [
            {
              "label": "Snapshot + log",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Deterministic rebuild",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Throttled writer",
              "kind": "app"
            }
          ],
          [
            {
              "label": "idx_v42, not yet read",
              "kind": "store"
            }
          ],
          [
            {
              "label": "38 M docs ≤ 4 h",
              "kind": "opportunity"
            }
          ]
        ]
      }
    ],
    "note": "The lanes do not share a queue: a four-hour rebuild and a 4x burst of slow-lane edits cannot touch the fast lane's budget.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "16-deployment-architecture",
    "title": "Deployment — One Write Region, Two Read Regions",
    "layout": "nested",
    "canvas": {
      "width": 1780
    },
    "boxes": [
      {
        "title": "eu-west-1 — write region",
        "kind": "cloud",
        "dir": "row",
        "children": [
          {
            "title": "AZ-a",
            "kind": "boundary",
            "nodes": [
              {
                "id": "a1",
                "label": "Capture + Assembly",
                "kind": "app",
                "sub": "Fargate tasks"
              },
              {
                "id": "a2",
                "label": "MSK broker",
                "kind": "queue"
              },
              {
                "id": "a3",
                "label": "OpenSearch data node",
                "kind": "store"
              }
            ]
          },
          {
            "title": "AZ-b",
            "kind": "boundary",
            "nodes": [
              {
                "id": "b1",
                "label": "Capture + Assembly",
                "kind": "app"
              },
              {
                "id": "b2",
                "label": "MSK broker",
                "kind": "queue"
              },
              {
                "id": "b3",
                "label": "OpenSearch data node",
                "kind": "store"
              }
            ]
          },
          {
            "title": "AZ-c",
            "kind": "boundary",
            "nodes": [
              {
                "id": "c1",
                "label": "Query Service",
                "kind": "app",
                "sub": "provisioned for peak"
              },
              {
                "id": "c2",
                "label": "MSK broker",
                "kind": "queue"
              },
              {
                "id": "c3",
                "label": "OpenSearch data node",
                "kind": "store"
              }
            ]
          },
          {
            "title": "Regional services",
            "kind": "plain",
            "nodes": [
              {
                "id": "r1",
                "label": "Aurora registry",
                "kind": "store",
                "sub": "multi-AZ, PITR"
              },
              {
                "id": "r2",
                "label": "Step Functions",
                "kind": "platform",
                "sub": "reindex"
              },
              {
                "id": "r3",
                "label": "S3 snapshots",
                "kind": "store"
              }
            ]
          }
        ]
      },
      {
        "title": "eu-central-1 / us-east-1 — read regions",
        "kind": "cloud",
        "dir": "row",
        "children": [
          {
            "title": "Read replica stack",
            "kind": "boundary",
            "nodes": [
              {
                "id": "d1",
                "label": "Query Service",
                "kind": "app"
              },
              {
                "id": "d2",
                "label": "OpenSearch follower",
                "kind": "store",
                "sub": "declared staleness"
              }
            ]
          },
          {
            "title": "Failover posture",
            "kind": "trust",
            "nodes": [
              {
                "id": "e1",
                "label": "Stale but honest",
                "kind": "opportunity",
                "sub": "RTO 15 min"
              },
              {
                "id": "e2",
                "label": "No local writes",
                "kind": "risk",
                "sub": "indexing resumes from log"
              }
            ]
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "x1",
        "label": "Route 53 + CloudFront",
        "kind": "integration"
      },
      {
        "id": "x2",
        "label": "Source Systems",
        "kind": "external"
      }
    ],
    "edges": [
      {
        "from": "x1",
        "to": "c1",
        "label": "query",
        "kind": "sync"
      },
      {
        "from": "x1",
        "to": "d1",
        "label": "failover",
        "kind": "error"
      },
      {
        "from": "x2",
        "to": "a1",
        "label": "changes",
        "kind": "async"
      },
      {
        "from": "a2",
        "to": "d2",
        "label": "replicate",
        "kind": "async"
      }
    ],
    "note": "One write region, because two regions assembling the same entity produce two documents that no alias reconciles.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "17-observability",
    "title": "Observability — Signal by Pipeline Stage",
    "layout": "grid",
    "canvas": {
      "width": 1800
    },
    "laneHeaderWidth": 170,
    "columns": [
      "Capture",
      "Log",
      "Assembly",
      "Index write",
      "Query",
      "Lifecycle"
    ],
    "rows": [
      {
        "title": "Lag & freshness",
        "cells": [
          [
            {
              "label": "Source commit → log",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Partition lag",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Consumer lag per lane",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Bulk queue depth",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Observed freshness served",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Catch-up lag before swap",
              "kind": "platform"
            }
          ]
        ]
      },
      {
        "title": "Correctness",
        "cells": [
          [
            {
              "label": "Rejected / quarantined",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "Dup + out-of-order rate",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Degraded-enrichment share",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "Unmapped-field errors",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "Partial-result rate",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "Divergence rate",
              "kind": "risk",
              "sub": "the alarm that matters"
            }
          ]
        ]
      },
      {
        "title": "Latency & load",
        "cells": [
          [
            {
              "label": "Accept p99",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Produce p99",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Fan-out backlog",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Indexing throughput",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Query p50 / p95 / p99",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Rebuild docs/s",
              "kind": "platform"
            }
          ]
        ]
      },
      {
        "title": "Silence detectors",
        "cells": [
          [
            {
              "label": "Source quiet-period alarm",
              "kind": "risk",
              "sub": "no signal is a signal"
            }
          ],
          [
            {
              "label": "Empty partition alarm",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "Schema-drift alarm",
              "kind": "risk"
            }
          ],
          [],
          [],
          [
            {
              "label": "Rehearsal not run",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Cost",
        "cells": [
          [],
          [],
          [
            {
              "label": "Enrichment cost share",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Cost per M events",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Cost per M queries",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Query : write ratio",
              "kind": "opportunity"
            }
          ]
        ]
      }
    ],
    "note": "The silence row exists because this platform's worst failure — a document that never arrived — produces no error anywhere else on this grid.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "18-index-lifecycle",
    "title": "Index Lifecycle — The Loop That Has to Close",
    "layout": "cycle",
    "centre": {
      "label": "Index Lifecycle"
    },
    "rx": 440,
    "ry": 215,
    "nodes": [
      {
        "id": "l1",
        "label": "Define",
        "kind": "app",
        "sub": "versioned, validated"
      },
      {
        "id": "l2",
        "label": "Dry run",
        "kind": "decision",
        "sub": "duration · cost"
      },
      {
        "id": "l3",
        "label": "Build beside",
        "kind": "app",
        "sub": "checkpointed"
      },
      {
        "id": "l4",
        "label": "Catch up",
        "kind": "queue",
        "sub": "from the log"
      },
      {
        "id": "l5",
        "label": "Gate",
        "kind": "decision",
        "sub": "count · diff · judgement"
      },
      {
        "id": "l6",
        "label": "Swap alias",
        "kind": "integration",
        "sub": "atomic"
      },
      {
        "id": "l7",
        "label": "Reconcile",
        "kind": "platform",
        "sub": "sampled vs source"
      }
    ],
    "ringLabels": [
      "estimate",
      "approve",
      "replay",
      "lag ok",
      "pass or refuse",
      "serve",
      "divergence"
    ],
    "note": "The loop only closes because the gate can refuse and the reconciler can disagree; without either, a rebuild is a hope.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "19-security-trust-zones",
    "title": "Security — Trust Zones and What Crosses Them",
    "layout": "zones",
    "canvas": {
      "width": 1760
    },
    "zones": [
      {
        "title": "Internet",
        "kind": "trust",
        "nodes": [
          {
            "id": "cli",
            "label": "Consumer app",
            "kind": "external"
          },
          {
            "id": "mcon",
            "label": "Merchant console",
            "kind": "external"
          },
          {
            "id": "adm",
            "label": "Admin console",
            "kind": "external"
          }
        ]
      },
      {
        "title": "Edge",
        "kind": "trust",
        "nodes": [
          {
            "id": "waf",
            "label": "WAF + CloudFront",
            "kind": "security"
          },
          {
            "id": "agw",
            "label": "API Gateway",
            "kind": "integration",
            "sub": "authn, quotas"
          }
        ]
      },
      {
        "title": "Query zone — read only",
        "kind": "trust",
        "nodes": [
          {
            "id": "qsvc",
            "label": "Query Service",
            "kind": "app"
          },
          {
            "id": "acl",
            "label": "Mandatory ACL Filter",
            "kind": "security",
            "sub": "from identity, pre-retrieval"
          },
          {
            "id": "cost",
            "label": "Cost Ceiling",
            "kind": "security"
          }
        ]
      },
      {
        "title": "Write zone — no caller reaches it",
        "kind": "trust",
        "nodes": [
          {
            "id": "cap",
            "label": "Capture Tier",
            "kind": "integration"
          },
          {
            "id": "asm",
            "label": "Assembly Workers",
            "kind": "app"
          },
          {
            "id": "wr",
            "label": "Index Writers",
            "kind": "app"
          }
        ]
      },
      {
        "title": "Control zone — the swap privilege",
        "kind": "trust",
        "nodes": [
          {
            "id": "defn",
            "label": "Definition API",
            "kind": "integration",
            "sub": "change a definition"
          },
          {
            "id": "swap",
            "label": "Alias Swap",
            "kind": "risk",
            "sub": "changes what everyone sees"
          },
          {
            "id": "aud",
            "label": "Audit Log",
            "kind": "security",
            "sub": "Object Lock"
          }
        ]
      },
      {
        "title": "Data zone",
        "kind": "trust",
        "nodes": [
          {
            "id": "os",
            "label": "OpenSearch indices",
            "kind": "store"
          },
          {
            "id": "reg",
            "label": "Definition Registry",
            "kind": "store"
          },
          {
            "id": "kms",
            "label": "KMS tenant keys",
            "kind": "security"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "cli",
        "to": "waf",
        "label": "TLS",
        "kind": "sync"
      },
      {
        "from": "waf",
        "to": "agw",
        "label": "signed",
        "kind": "sync"
      },
      {
        "from": "agw",
        "to": "qsvc",
        "label": "token",
        "kind": "sync"
      },
      {
        "from": "qsvc",
        "to": "os",
        "label": "filtered read",
        "kind": "sync"
      },
      {
        "from": "adm",
        "to": "defn",
        "label": "admin role",
        "kind": "sync"
      },
      {
        "from": "defn",
        "to": "swap",
        "label": "separate grant",
        "kind": "error"
      },
      {
        "from": "swap",
        "to": "aud",
        "label": "actor + reason",
        "kind": "sync"
      },
      {
        "from": "cap",
        "to": "asm",
        "label": "internal",
        "kind": "async"
      }
    ],
    "note": "Four privileges, deliberately split: query, write a source, change a definition, move an alias. Only the last changes what 40 M people see in one call.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "20-query-authorisation-flow",
    "title": "Identity and Access — One Filtered Query",
    "layout": "sequence",
    "canvas": {
      "width": 1740
    },
    "lifelines": [
      {
        "id": "u",
        "label": "Merchant",
        "kind": "actor"
      },
      {
        "id": "gw",
        "label": "API Gateway",
        "kind": "integration"
      },
      {
        "id": "idp",
        "label": "Identity Provider",
        "kind": "security"
      },
      {
        "id": "q",
        "label": "Query Service",
        "kind": "app"
      },
      {
        "id": "reg",
        "label": "Definition Registry",
        "kind": "store"
      },
      {
        "id": "ow",
        "label": "Recent Writes",
        "kind": "store"
      },
      {
        "id": "os",
        "label": "Alias → idx_v41",
        "kind": "store"
      }
    ],
    "messages": [
      {
        "from": "u",
        "to": "gw",
        "label": "GET /search?q=…",
        "kind": "call"
      },
      {
        "from": "gw",
        "to": "idp",
        "label": "validate token",
        "kind": "call"
      },
      {
        "from": "idp",
        "to": "gw",
        "label": "tenant + principal",
        "kind": "return"
      },
      {
        "from": "gw",
        "to": "q",
        "label": "scoped request",
        "kind": "call"
      },
      {
        "from": "q",
        "to": "reg",
        "label": "alias for tenant?",
        "kind": "call"
      },
      {
        "from": "reg",
        "to": "q",
        "label": "alias + relevance v",
        "kind": "return"
      },
      {
        "from": "q",
        "to": "q",
        "label": "derive ACL filter",
        "kind": "self"
      },
      {
        "from": "q",
        "to": "q",
        "label": "cost ceiling check",
        "kind": "self"
      },
      {
        "from": "q",
        "to": "os",
        "label": "query + mandatory filter",
        "kind": "call"
      },
      {
        "from": "os",
        "to": "q",
        "label": "hits + index version",
        "kind": "return"
      },
      {
        "from": "q",
        "to": "ow",
        "label": "own pending writes?",
        "kind": "call"
      },
      {
        "from": "ow",
        "to": "q",
        "label": "1 overlay doc",
        "kind": "return"
      },
      {
        "from": "q",
        "to": "u",
        "label": "results + freshness",
        "kind": "return"
      },
      {
        "from": "q",
        "to": "gw",
        "label": "over ceiling: typed 429",
        "kind": "error"
      }
    ],
    "note": "The ACL filter is derived at message 7 from the identity, never taken from the request — a caller cannot omit it.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  },
  {
    "id": "21-failure-classes",
    "title": "Failure Classes, Their Answers and the Residual",
    "layout": "grid",
    "canvas": {
      "width": 1800
    },
    "laneHeaderWidth": 210,
    "columns": [
      "Detected by",
      "Structural answer",
      "Accepted residual"
    ],
    "rows": [
      {
        "title": "Source lag or outage",
        "cells": [
          [
            {
              "label": "Quiet-period alarm",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Declared degraded freshness",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Stale answers, honestly labelled",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Lost change event",
        "cells": [
          [
            {
              "label": "Sampled reconciliation",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Targeted re-emit from snapshot",
              "kind": "app"
            }
          ],
          [
            {
              "label": "≤ 0.01% divergent",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Duplicate or reordered",
        "cells": [
          [
            {
              "label": "Version guard",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Discard older source version",
              "kind": "app"
            }
          ],
          [
            {
              "label": "None — model-level",
              "kind": "opportunity"
            }
          ]
        ]
      },
      {
        "title": "Poison document",
        "cells": [
          [
            {
              "label": "Mapping error",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Quarantine, partition continues",
              "kind": "app"
            }
          ],
          [
            {
              "label": "One entity absent until released",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Schema drift in a source",
        "cells": [
          [
            {
              "label": "Definition mismatch",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Quarantine + alarm",
              "kind": "app"
            }
          ],
          [
            {
              "label": "A field pauses, never drops",
              "kind": "opportunity"
            }
          ]
        ]
      },
      {
        "title": "Enrichment failure",
        "cells": [
          [
            {
              "label": "Timeout rate",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Previous value, marked degraded",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Ranking signal goes stale",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Bad mapping or relevance",
        "cells": [
          [
            {
              "label": "Swap gate, variant metrics",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Refuse swap; rollback by alias",
              "kind": "app"
            }
          ],
          [
            {
              "label": "72 h rollback window only",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Cluster saturation on rebuild",
        "cells": [
          [
            {
              "label": "Query p99 regression",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Reserved capacity + throttle",
              "kind": "app"
            }
          ],
          [
            {
              "label": "≤ 15% p99 rise accepted",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Region loss",
        "cells": [
          [
            {
              "label": "Health checks",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Read region serves, stale",
              "kind": "app"
            }
          ],
          [
            {
              "label": "No indexing until log resumes",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Tenant abuse or hot index",
        "cells": [
          [
            {
              "label": "Quota + cost ceiling",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Typed rejection, dedicated move",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Migration is not instant",
              "kind": "risk"
            }
          ]
        ]
      }
    ],
    "note": "Two classes would change the design: a source that cannot emit a comparable digest, and a tenant whose residency forbids a shared cluster.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture"
    }
  }
]
