[
  {
    "id": "01-system-context",
    "title": "Feature Store — System Context",
    "layout": "context",
    "canvas": {
      "width": 1720
    },
    "colWidth": 260,
    "system": {
      "label": "Feature Store",
      "sub": "1,400 features · 45 models"
    },
    "groups": [
      {
        "side": "left",
        "title": "People",
        "nodes": [
          {
            "id": "ds",
            "label": "Data scientist",
            "kind": "actor",
            "sub": "60, 9 teams",
            "rel": "defines",
            "dir": "in"
          },
          {
            "id": "mle",
            "label": "ML engineer",
            "kind": "actor",
            "rel": "onboards",
            "dir": "in"
          },
          {
            "id": "own",
            "label": "Feature group owner",
            "kind": "actor",
            "rel": "owns",
            "dir": "in"
          },
          {
            "id": "gov",
            "label": "Data governance",
            "kind": "actor",
            "rel": "classifies",
            "dir": "in"
          },
          {
            "id": "sre",
            "label": "Platform SRE",
            "kind": "actor",
            "rel": "operates",
            "dir": "in"
          }
        ]
      },
      {
        "side": "right",
        "title": "Sources — read, never written",
        "nodes": [
          {
            "id": "ord",
            "label": "Order & payment events",
            "kind": "external",
            "sub": "Kinesis",
            "rel": "events",
            "dir": "in",
            "kind2": "async"
          },
          {
            "id": "cour",
            "label": "Courier telemetry",
            "kind": "external",
            "sub": "1.4M ev/s peak",
            "rel": "telemetry",
            "dir": "in",
            "kind2": "async"
          },
          {
            "id": "click",
            "label": "Clickstream",
            "kind": "external",
            "rel": "sessions",
            "dir": "in",
            "kind2": "async"
          },
          {
            "id": "wh",
            "label": "Analytics warehouse",
            "kind": "external",
            "sub": "Redshift",
            "rel": "dimensions",
            "dir": "in",
            "kind2": "batch"
          },
          {
            "id": "wx",
            "label": "Weather & traffic feed",
            "kind": "external",
            "rel": "conditions",
            "dir": "in",
            "kind2": "batch"
          }
        ]
      },
      {
        "side": "top",
        "title": "Consumers",
        "nodes": [
          {
            "id": "eta",
            "label": "ETA model service",
            "kind": "external",
            "sub": "p99 25 ms",
            "rel": "reads"
          },
          {
            "id": "fraud",
            "label": "Payment risk model",
            "kind": "external",
            "rel": "vector read"
          },
          {
            "id": "rank",
            "label": "Store ranking",
            "kind": "external",
            "sub": "500 keys/call",
            "rel": "batch keys"
          },
          {
            "id": "surge",
            "label": "Surge pricing",
            "kind": "external",
            "rel": "vector read"
          },
          {
            "id": "train",
            "label": "Training jobs",
            "kind": "external",
            "sub": "SageMaker",
            "rel": "datasets",
            "kind2": "batch"
          }
        ]
      },
      {
        "side": "bottom",
        "title": "Out of scope",
        "nodes": [
          {
            "id": "mr",
            "label": "Model registry",
            "kind": "external",
            "rel": "not owned"
          },
          {
            "id": "bi",
            "label": "BI reporting",
            "kind": "external",
            "rel": "not owned"
          }
        ]
      }
    ],
    "note": "The platform reads every source and writes to none of them. Model training and serving sit outside the boundary.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "02-high-level-architecture",
    "title": "Feature Store — High-Level Architecture",
    "layout": "flow",
    "chain": true,
    "canvas": {
      "width": 1760
    },
    "stages": [
      {
        "title": "Sources",
        "nodes": [
          {
            "id": "ev",
            "label": "Event streams",
            "kind": "external",
            "sub": "Kinesis"
          },
          {
            "id": "tbl",
            "label": "Warehouse tables",
            "kind": "external",
            "sub": "Redshift"
          }
        ]
      },
      {
        "title": "Define",
        "nodes": [
          {
            "id": "repo",
            "label": "Definition repo",
            "kind": "external",
            "sub": "Git, reviewed"
          },
          {
            "id": "comp",
            "label": "Compiler",
            "kind": "app",
            "sub": "one source, two plans"
          },
          {
            "id": "reg",
            "label": "Registry",
            "kind": "store",
            "sub": "Aurora PostgreSQL"
          }
        ]
      },
      {
        "title": "Materialise",
        "nodes": [
          {
            "id": "flink",
            "label": "Stream processor",
            "kind": "app",
            "sub": "Managed Flink"
          },
          {
            "id": "emr",
            "label": "Batch engine",
            "kind": "app",
            "sub": "EMR Serverless"
          },
          {
            "id": "guard",
            "label": "Contract guard",
            "kind": "security",
            "sub": "quarantine on drift"
          }
        ]
      },
      {
        "title": "Store",
        "nodes": [
          {
            "id": "off",
            "label": "Offline store",
            "kind": "store",
            "sub": "S3 + Iceberg"
          },
          {
            "id": "on",
            "label": "Online store",
            "kind": "store",
            "sub": "DynamoDB, latest only"
          }
        ]
      },
      {
        "title": "Serve",
        "nodes": [
          {
            "id": "api",
            "label": "Serving API",
            "kind": "app",
            "sub": "gRPC on EKS"
          },
          {
            "id": "od",
            "label": "On-demand runtime",
            "kind": "app",
            "sub": "≤ 2 ms p99"
          },
          {
            "id": "ts",
            "label": "Training-set service",
            "kind": "app",
            "sub": "as-of join"
          }
        ]
      },
      {
        "title": "Prove",
        "nodes": [
          {
            "id": "log",
            "label": "Serving log",
            "kind": "store",
            "sub": "1% sample"
          },
          {
            "id": "skew",
            "label": "Skew replay",
            "kind": "app",
            "sub": "nightly"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "comp",
        "to": "flink",
        "label": "online",
        "kind": "batch"
      },
      {
        "from": "comp",
        "to": "emr",
        "label": "offline",
        "kind": "batch",
        "route": "gutter"
      },
      {
        "from": "off",
        "to": "on",
        "label": "rebuild",
        "kind": "batch",
        "route": "gutter"
      },
      {
        "from": "api",
        "to": "log",
        "label": "sample",
        "kind": "async"
      },
      {
        "from": "skew",
        "to": "off",
        "label": "replay",
        "kind": "batch",
        "route": "gutter"
      }
    ],
    "note": "The compiler is the only place a feature is described. Everything to its right is a materialisation of what it emitted.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "03-actors-and-journeys",
    "title": "Who the Feature Store is For, and What They Get To Do",
    "layout": "actors",
    "canvas": {
      "width": 1740
    },
    "cardWidth": 270,
    "groups": [
      {
        "title": "Producers and consumers",
        "kind": "boundary",
        "actors": [
          {
            "id": "ds",
            "label": "Data scientist",
            "sub": "60 across 9 teams",
            "goal": "Find the feature that already exists before I build a fourth copy of it — and when I do have to build one, ship it today rather than next sprint.",
            "journeys": [
              {
                "id": "j-ship",
                "label": "Define and ship a feature",
                "sub": "~40 / month"
              },
              {
                "label": "Assemble a training set"
              },
              {
                "label": "Search the catalogue"
              }
            ]
          },
          {
            "id": "mle",
            "label": "ML engineer",
            "sub": "45 models in production",
            "goal": "Read the vector my model needs in under 25 ms, and know which values are stale before my accuracy tells me.",
            "journeys": [
              {
                "id": "j-stale",
                "label": "Respond to stale features"
              },
              {
                "label": "Onboard a model"
              },
              {
                "label": "Read the skew report"
              }
            ]
          }
        ]
      },
      {
        "title": "Accountability",
        "kind": "trust",
        "actors": [
          {
            "id": "own",
            "label": "Feature group owner",
            "sub": "120 groups",
            "goal": "Know who depends on my feature before I change it, and hear about a freshness breach from the platform rather than from a model owner.",
            "journeys": [
              {
                "label": "Approve a breaking change"
              },
              {
                "label": "Answer a freshness alert"
              }
            ]
          },
          {
            "id": "gov",
            "label": "Data governance",
            "sub": "2 people, 1.1M entities",
            "goal": "Be certain a restricted column has not quietly become an unclassified feature that somebody logs at 100% sampling.",
            "journeys": [
              {
                "label": "Classify a feature group"
              },
              {
                "label": "Run an erasure request"
              }
            ]
          },
          {
            "id": "sre",
            "label": "Platform SRE",
            "sub": "on call 24×7",
            "goal": "Rebuild the online store before any model notices it was gone, and keep a backfill from taking serving with it.",
            "journeys": [
              {
                "label": "Rebuild the online store"
              },
              {
                "label": "Drain a backfill"
              }
            ]
          }
        ]
      },
      {
        "title": "Machines in the cast",
        "kind": "cloud",
        "actors": [
          {
            "id": "msvc",
            "label": "Online model service",
            "kind": "external",
            "sub": "320k reads/s peak",
            "goal": "Get the vector, or a clear reason why not — never a silent zero dressed up as a real value.",
            "journeys": [
              {
                "label": "Read a feature vector"
              }
            ]
          },
          {
            "id": "sched",
            "label": "Materialisation scheduler",
            "kind": "platform",
            "sub": "120 groups",
            "goal": "Land every batch group before the models wake up, and say so loudly when I cannot.",
            "journeys": [
              {
                "label": "Run the 05:00 batch wave"
              }
            ]
          },
          {
            "id": "proc",
            "label": "Stream processor",
            "kind": "platform",
            "sub": "checkpointed",
            "goal": "Stay inside five seconds of the event, or declare myself behind rather than look fresh.",
            "journeys": [
              {
                "label": "Aggregate a 30-minute window"
              }
            ]
          }
        ]
      }
    ],
    "note": "Three of the eight actors are machines. Two of them are expected to fail in specific, designed-for ways.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "04-journey-ship-a-feature",
    "title": "Journey — A Data Scientist Ships a Feature",
    "layout": "journey",
    "actor": {
      "label": "Data scientist",
      "sub": "ETA team",
      "goal": "Ship \"orders at this store in the last 15 minutes\" today, and never build it twice",
      "trigger": "The ETA model under-predicts by four minutes at dinner peak",
      "success": "Readable online inside 30 minutes, and the training set that uses it is point-in-time correct"
    },
    "phases": [
      {
        "title": "Search",
        "sub": "before building"
      },
      {
        "title": "Define"
      },
      {
        "title": "Validate"
      },
      {
        "title": "Backfill",
        "moment": true
      },
      {
        "title": "Consume",
        "moment": true
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Search the catalogue"
            },
            {
              "label": "Read adoption count"
            }
          ],
          [
            {
              "label": "Write the definition"
            },
            {
              "label": "Open a PR"
            }
          ],
          [
            {
              "label": "Compile both plans"
            },
            {
              "label": "Preview values"
            }
          ],
          [
            {
              "label": "Estimate the cost"
            },
            {
              "label": "Run 13 months"
            }
          ],
          [
            {
              "label": "Generate a training set"
            },
            {
              "label": "Read it online"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "Confident",
          "Fine",
          "Blocked"
        ],
        "points": [
          1,
          2,
          2,
          0,
          2
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [
            {
              "label": "Four near-duplicates"
            }
          ],
          [],
          [],
          [
            {
              "label": "6 h run, live SLOs at risk"
            }
          ],
          []
        ]
      },
      {
        "title": "What answers it",
        "kind": "gain",
        "cells": [
          [
            {
              "label": "Owner + consumer count"
            }
          ],
          [
            {
              "label": "One artefact, two plans"
            }
          ],
          [
            {
              "label": "Contract guard preview"
            }
          ],
          [
            {
              "label": "Budgeted, pre-emptible pool"
            }
          ],
          [
            {
              "label": "As-of join + manifest"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The trough is backfill, not authoring. Most of the platform's operational design exists to make that phase survivable.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "05-journey-stale-features",
    "title": "Journey — A Model's Features Go Stale at Peak",
    "layout": "journey",
    "actor": {
      "label": "ML engineer, on call",
      "sub": "ETA model, dinner peak",
      "goal": "Keep the ETA model honest when a feature stops arriving",
      "trigger": "Freshness SLO breach on store_orders_15m at 19:40 on a Friday",
      "success": "The model degrades visibly and recovers, and no wrong ETA reaches a customer as if it were right"
    },
    "phases": [
      {
        "title": "Alert",
        "sub": "19:40"
      },
      {
        "title": "Triage"
      },
      {
        "title": "Attribute"
      },
      {
        "title": "Mitigate",
        "moment": true
      },
      {
        "title": "Recover"
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Take the page"
            }
          ],
          [
            {
              "label": "Open feature health"
            },
            {
              "label": "Check group age"
            }
          ],
          [
            {
              "label": "Data drift or pipeline?"
            }
          ],
          [
            {
              "label": "Accept degraded mode"
            }
          ],
          [
            {
              "label": "Replay from the log"
            },
            {
              "label": "Confirm freshness"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "In control",
          "Fine",
          "Exposed"
        ],
        "points": [
          1,
          1,
          0,
          1,
          2
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [],
          [],
          [
            {
              "label": "Drift looks like a deploy"
            }
          ],
          [
            {
              "label": "Silent zero → wrong ETA"
            }
          ],
          []
        ]
      },
      {
        "title": "What answers it",
        "kind": "gain",
        "cells": [
          [
            {
              "label": "Stale flagged in 60 s"
            }
          ],
          [
            {
              "label": "Per-consumer health view"
            }
          ],
          [
            {
              "label": "Version stamp per value"
            }
          ],
          [
            {
              "label": "Reason code + default"
            }
          ],
          [
            {
              "label": "7-day stream log replay"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "Attribution is the trough: telling a changed world from a changed pipeline is the question the version stamp exists to answer.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "06-layered-architecture",
    "title": "Feature Store — Layered Architecture",
    "layout": "bands",
    "canvas": {
      "width": 1740
    },
    "layerHeaderWidth": 160,
    "bands": [
      {
        "name": "Experience",
        "nodes": [
          {
            "id": "cat",
            "label": "Catalogue & search",
            "kind": "app"
          },
          {
            "id": "health",
            "label": "Feature health view",
            "kind": "app"
          },
          {
            "id": "skewr",
            "label": "Skew report",
            "kind": "app"
          },
          {
            "id": "regapi",
            "label": "Registry API",
            "kind": "integration"
          }
        ]
      },
      {
        "name": "Access",
        "nodes": [
          {
            "id": "api",
            "label": "Serving API",
            "kind": "app",
            "sub": "gRPC"
          },
          {
            "id": "sdk",
            "label": "Client SDK",
            "kind": "app",
            "sub": "batching, no value cache"
          },
          {
            "id": "od",
            "label": "On-demand runtime",
            "kind": "app"
          },
          {
            "id": "tss",
            "label": "Training-set service",
            "kind": "app"
          },
          {
            "id": "quota",
            "label": "Quotas & criticality",
            "kind": "security"
          }
        ]
      },
      {
        "name": "Stores",
        "nodes": [
          {
            "id": "on",
            "label": "Online store",
            "kind": "store",
            "sub": "latest value"
          },
          {
            "id": "off",
            "label": "Offline store",
            "kind": "store",
            "sub": "full history"
          },
          {
            "id": "art",
            "label": "Training-set artefacts",
            "kind": "store"
          },
          {
            "id": "slog",
            "label": "Serving log",
            "kind": "store"
          }
        ]
      },
      {
        "name": "Materialisation",
        "nodes": [
          {
            "id": "flink",
            "label": "Stream processor",
            "kind": "app"
          },
          {
            "id": "batch",
            "label": "Batch engine",
            "kind": "app"
          },
          {
            "id": "bf",
            "label": "Backfill runner",
            "kind": "app",
            "sub": "isolated pool"
          },
          {
            "id": "guard",
            "label": "Contract guard",
            "kind": "security"
          }
        ]
      },
      {
        "name": "Definition",
        "nodes": [
          {
            "id": "repo",
            "label": "Definition repo",
            "kind": "external",
            "sub": "Git"
          },
          {
            "id": "comp",
            "label": "Compiler",
            "kind": "app"
          },
          {
            "id": "reg",
            "label": "Registry",
            "kind": "store"
          },
          {
            "id": "lin",
            "label": "Lineage graph",
            "kind": "store"
          },
          {
            "id": "dup",
            "label": "Duplicate detector",
            "kind": "security"
          }
        ]
      },
      {
        "name": "Observability",
        "nodes": [
          {
            "id": "fresh",
            "label": "Freshness SLOs",
            "kind": "platform"
          },
          {
            "id": "replay",
            "label": "Skew replay",
            "kind": "platform"
          },
          {
            "id": "drift",
            "label": "Drift monitors",
            "kind": "platform"
          },
          {
            "id": "cost",
            "label": "Cost attribution",
            "kind": "platform"
          }
        ]
      },
      {
        "name": "Sources",
        "nodes": [
          {
            "id": "ev",
            "label": "Event streams",
            "kind": "external"
          },
          {
            "id": "wh",
            "label": "Warehouse",
            "kind": "external"
          },
          {
            "id": "cour",
            "label": "Courier telemetry",
            "kind": "external"
          },
          {
            "id": "wx",
            "label": "Weather & traffic",
            "kind": "external"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "comp",
        "to": "guard",
        "label": "compiled plans",
        "kind": "batch"
      },
      {
        "from": "flink",
        "to": "on",
        "label": "latest value"
      },
      {
        "from": "batch",
        "to": "off",
        "label": "append"
      },
      {
        "from": "api",
        "to": "on",
        "label": "read"
      },
      {
        "from": "tss",
        "to": "off",
        "label": "as-of read",
        "kind": "batch"
      },
      {
        "from": "replay",
        "to": "slog",
        "label": "sampled vectors",
        "kind": "batch"
      }
    ],
    "note": "Definition sits below materialisation because materialisation reads a compiled plan, never a live definition.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "07-platform-components",
    "title": "Feature Store — Containers and Components",
    "layout": "nested",
    "canvas": {
      "width": 1760
    },
    "boxes": [
      {
        "title": "AWS eu-west-1 — Feature Store",
        "kind": "cloud",
        "dir": "col",
        "children": [
          {
            "title": "Control plane",
            "kind": "boundary",
            "nodes": [
              {
                "id": "regapi",
                "label": "Registry API",
                "kind": "app"
              },
              {
                "id": "comp",
                "label": "Compiler",
                "kind": "app",
                "sub": "offline + online plan"
              },
              {
                "id": "cat",
                "label": "Catalogue UI",
                "kind": "app"
              },
              {
                "id": "reg",
                "label": "Registry",
                "kind": "store",
                "sub": "Aurora PostgreSQL"
              },
              {
                "id": "lin",
                "label": "Lineage graph",
                "kind": "store",
                "sub": "Neptune"
              }
            ]
          },
          {
            "title": "Data plane — serving",
            "kind": "boundary",
            "nodes": [
              {
                "id": "api",
                "label": "Serving API",
                "kind": "app",
                "sub": "gRPC, EKS"
              },
              {
                "id": "od",
                "label": "On-demand runtime",
                "kind": "app",
                "sub": "sandboxed"
              },
              {
                "id": "cache",
                "label": "Read cache",
                "kind": "store",
                "sub": "ElastiCache, short TTL"
              },
              {
                "id": "on",
                "label": "Online store",
                "kind": "store",
                "sub": "DynamoDB"
              },
              {
                "id": "slogger",
                "label": "Serving logger",
                "kind": "queue",
                "sub": "Firehose"
              }
            ]
          },
          {
            "title": "Data plane — materialisation",
            "kind": "boundary",
            "nodes": [
              {
                "id": "flink",
                "label": "Stream processor",
                "kind": "app",
                "sub": "Managed Flink"
              },
              {
                "id": "batch",
                "label": "Batch engine",
                "kind": "app",
                "sub": "EMR Serverless"
              },
              {
                "id": "bf",
                "label": "Backfill runner",
                "kind": "app",
                "sub": "isolated pool"
              },
              {
                "id": "guard",
                "label": "Contract guard",
                "kind": "security"
              }
            ]
          },
          {
            "title": "Data plane — offline",
            "kind": "boundary",
            "nodes": [
              {
                "id": "off",
                "label": "Offline store",
                "kind": "store",
                "sub": "S3 + Iceberg"
              },
              {
                "id": "glue",
                "label": "Table catalog",
                "kind": "store",
                "sub": "AWS Glue"
              },
              {
                "id": "tss",
                "label": "Training-set service",
                "kind": "app",
                "sub": "EMR Spark"
              },
              {
                "id": "art",
                "label": "Training-set artefacts",
                "kind": "store",
                "sub": "S3"
              }
            ]
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "kin",
        "label": "Event streams",
        "kind": "external",
        "sub": "Kinesis"
      },
      {
        "id": "wh",
        "label": "Analytics warehouse",
        "kind": "external",
        "sub": "Redshift"
      },
      {
        "id": "msvc",
        "label": "Model services",
        "kind": "external"
      },
      {
        "id": "sm",
        "label": "SageMaker training",
        "kind": "external"
      }
    ],
    "edges": [
      {
        "from": "comp",
        "to": "reg",
        "label": "publish version"
      },
      {
        "from": "kin",
        "to": "flink",
        "label": "consume",
        "kind": "async"
      },
      {
        "from": "flink",
        "to": "on",
        "label": "latest"
      },
      {
        "from": "batch",
        "to": "off",
        "label": "append"
      },
      {
        "from": "sm",
        "to": "art",
        "label": "read",
        "kind": "batch"
      }
    ],
    "note": "Four stores because there are four mutabilities. Serving and materialisation never share capacity. Warehouse reads and the online rebuild are omitted here — views 09 and 10 carry them.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "08-integration-surface",
    "title": "Feature Store — Integration Surface",
    "layout": "hub",
    "canvas": {
      "width": 1700
    },
    "left": {
      "title": "Consumers",
      "nodes": [
        {
          "id": "msvc",
          "label": "Online model services",
          "kind": "external",
          "sub": "4 at peak",
          "rel": "gRPC read"
        },
        {
          "id": "bscore",
          "label": "Batch scoring",
          "kind": "external",
          "rel": "Iceberg",
          "kind2": "batch"
        },
        {
          "id": "sm",
          "label": "Training jobs",
          "kind": "external",
          "sub": "SageMaker",
          "rel": "datasets",
          "kind2": "batch"
        },
        {
          "id": "users",
          "label": "Catalogue users",
          "kind": "actor",
          "rel": "HTTPS"
        },
        {
          "id": "ci",
          "label": "CI pipeline",
          "kind": "external",
          "sub": "GitHub Actions",
          "rel": "publish"
        }
      ]
    },
    "centre": {
      "title": "Feature Store",
      "nodes": [
        {
          "id": "api",
          "label": "Serving API",
          "kind": "app",
          "sub": "gRPC, VPC only"
        },
        {
          "id": "regapi",
          "label": "Registry API",
          "kind": "integration",
          "sub": "REST"
        },
        {
          "id": "tss",
          "label": "Training-set service",
          "kind": "app"
        }
      ]
    },
    "right": {
      "title": "Dependencies",
      "nodes": [
        {
          "id": "kin",
          "label": "Kinesis streams",
          "kind": "queue",
          "rel": "consume",
          "dir": "out",
          "kind2": "async"
        },
        {
          "id": "wh",
          "label": "Analytics warehouse",
          "kind": "external",
          "rel": "nightly",
          "dir": "out",
          "kind2": "batch"
        },
        {
          "id": "lf",
          "label": "Lake Formation",
          "kind": "security",
          "rel": "",
          "dir": "out"
        },
        {
          "id": "iam",
          "label": "IAM / IRSA + KMS",
          "kind": "security",
          "rel": "",
          "dir": "out"
        }
      ]
    },
    "note": "Five consumer surfaces, one write surface, and nothing written back to any system the platform reads. Team ownership is resolved from the org directory out of band.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "09-feature-data-flow",
    "title": "Feature Store — Data Flow",
    "layout": "flow",
    "chain": true,
    "canvas": {
      "width": 1780
    },
    "stages": [
      {
        "title": "Emit",
        "nodes": [
          {
            "id": "ord",
            "label": "Order events",
            "kind": "external"
          },
          {
            "id": "cour",
            "label": "Courier telemetry",
            "kind": "external"
          },
          {
            "id": "tbl",
            "label": "Warehouse tables",
            "kind": "external"
          }
        ]
      },
      {
        "title": "Land",
        "nodes": [
          {
            "id": "log",
            "label": "Stream log",
            "kind": "queue",
            "sub": "Kinesis, 7 days"
          },
          {
            "id": "raw",
            "label": "Raw landing",
            "kind": "store",
            "sub": "S3, as given"
          }
        ]
      },
      {
        "title": "Compute",
        "nodes": [
          {
            "id": "flink",
            "label": "Stream aggregates",
            "kind": "app",
            "sub": "Flink, 1 m – 24 h"
          },
          {
            "id": "batch",
            "label": "Batch transforms",
            "kind": "app",
            "sub": "EMR Serverless"
          },
          {
            "id": "guard",
            "label": "Contract guard",
            "kind": "security",
            "sub": "quarantine"
          }
        ]
      },
      {
        "title": "Materialise",
        "nodes": [
          {
            "id": "off",
            "label": "Offline store",
            "kind": "store",
            "sub": "event + ingest ts"
          },
          {
            "id": "on",
            "label": "Online store",
            "kind": "store",
            "sub": "latest value + ts"
          }
        ]
      },
      {
        "title": "Serve",
        "nodes": [
          {
            "id": "vec",
            "label": "Vector read",
            "kind": "app",
            "sub": "p99 15 ms"
          },
          {
            "id": "pit",
            "label": "Point-in-time join",
            "kind": "app",
            "sub": "as-of spine"
          }
        ]
      },
      {
        "title": "Prove",
        "nodes": [
          {
            "id": "slog",
            "label": "Serving log",
            "kind": "store",
            "sub": "1% sample"
          },
          {
            "id": "replay",
            "label": "Skew replay",
            "kind": "app",
            "sub": "nightly verdict"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "guard",
        "to": "off",
        "label": "pass",
        "kind": "batch"
      },
      {
        "from": "off",
        "to": "on",
        "label": "rebuild",
        "kind": "batch"
      },
      {
        "from": "vec",
        "to": "slog",
        "label": "sample",
        "kind": "async"
      },
      {
        "from": "replay",
        "to": "off",
        "label": "as-of compare",
        "kind": "batch",
        "route": "gutter"
      }
    ],
    "note": "The only loop closes left: sampled serving vectors are replayed against the offline path to prove the two agree.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "10-storage-durability-zones",
    "title": "Feature Store — Storage Zones by Durability",
    "layout": "nested",
    "canvas": {
      "width": 1760
    },
    "boxes": [
      {
        "title": "Authoritative — loss is unrecoverable",
        "kind": "trust",
        "nodes": [
          {
            "id": "reg",
            "label": "Registry",
            "kind": "store",
            "sub": "RPO 0, RTO 1 h"
          },
          {
            "id": "repo",
            "label": "Definition repo",
            "kind": "store",
            "sub": "Git, reviewed"
          },
          {
            "id": "aud",
            "label": "Audit log",
            "kind": "store",
            "sub": "Object Lock, 7 yrs"
          }
        ]
      },
      {
        "title": "Re-derivable from sources",
        "kind": "boundary",
        "nodes": [
          {
            "id": "off",
            "label": "Offline store",
            "kind": "store",
            "sub": "RPO 15 min, 25 mo"
          },
          {
            "id": "raw",
            "label": "Raw landing",
            "kind": "store",
            "sub": "as given"
          },
          {
            "id": "man",
            "label": "Training-set manifest",
            "kind": "store",
            "sub": "kept forever"
          }
        ]
      },
      {
        "title": "Derived and disposable",
        "kind": "boundary",
        "nodes": [
          {
            "id": "on",
            "label": "Online store",
            "kind": "store",
            "sub": "rebuild ≤ 90 min"
          },
          {
            "id": "cache",
            "label": "Read cache",
            "kind": "store",
            "sub": "seconds"
          },
          {
            "id": "art",
            "label": "Materialised sets",
            "kind": "store",
            "sub": "13 mo, regenerable"
          }
        ]
      },
      {
        "title": "In flight and evidential",
        "kind": "boundary",
        "nodes": [
          {
            "id": "log",
            "label": "Stream log",
            "kind": "queue",
            "sub": "7 days, replayable"
          },
          {
            "id": "slog",
            "label": "Serving log",
            "kind": "store",
            "sub": "90 days"
          },
          {
            "id": "drift",
            "label": "Drift & skew record",
            "kind": "store",
            "sub": "13 months"
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "src",
        "label": "Source systems",
        "kind": "external",
        "sub": "the real archive"
      }
    ],
    "edges": [
      {
        "from": "off",
        "to": "on",
        "label": "rebuild",
        "kind": "batch"
      },
      {
        "from": "src",
        "to": "raw",
        "label": "re-fetch",
        "kind": "batch"
      },
      {
        "from": "man",
        "to": "art",
        "label": "regenerate",
        "kind": "batch"
      }
    ],
    "note": "The hottest and largest store has the weakest durability requirement. The smallest store is the only irreplaceable one.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "11-data-model",
    "title": "Feature Store — Registry and Value Data Model",
    "layout": "er",
    "canvas": {
      "width": 1740,
      "cols": 4
    },
    "rowGap": 260,
    "entities": [
      {
        "id": "ent",
        "name": "entity_type",
        "kind": "store",
        "row": 0,
        "col": 0,
        "attrs": [
          "entity_type_id  PK",
          "name  (user, store, courier…)",
          "key_format",
          "registered_at"
        ]
      },
      {
        "id": "grp",
        "name": "feature_group",
        "kind": "store",
        "row": 0,
        "col": 1,
        "attrs": [
          "group_id  PK",
          "entity_type_id  FK",
          "owner_team",
          "cadence",
          "sensitivity_class",
          "freshness_slo_s"
        ]
      },
      {
        "id": "feat",
        "name": "feature",
        "kind": "store",
        "row": 0,
        "col": 2,
        "attrs": [
          "feature_id  PK",
          "group_id  FK",
          "name",
          "dtype",
          "default_value",
          "online / offline flags"
        ]
      },
      {
        "id": "ver",
        "name": "feature_version",
        "kind": "store",
        "row": 0,
        "col": 3,
        "attrs": [
          "version_id  PK",
          "feature_id  FK",
          "transform_hash",
          "window_spec",
          "lifecycle_state",
          "published_at"
        ]
      },
      {
        "id": "grant",
        "name": "access_grant",
        "kind": "store",
        "row": 1,
        "col": 0,
        "attrs": [
          "grant_id  PK",
          "group_id  FK",
          "principal",
          "purpose",
          "expires_at"
        ]
      },
      {
        "id": "run",
        "name": "materialisation_run",
        "kind": "store",
        "row": 1,
        "col": 1,
        "attrs": [
          "run_id  PK",
          "group_id  FK",
          "version_id  FK",
          "engine",
          "window_closed_at",
          "status"
        ]
      },
      {
        "id": "voff",
        "name": "feature_value_offline",
        "kind": "store",
        "row": 1,
        "col": 2,
        "attrs": [
          "entity_key  PK",
          "feature_id  PK",
          "event_ts  PK",
          "ingest_ts",
          "value",
          "version_id  FK",
          "run_id  FK"
        ]
      },
      {
        "id": "von",
        "name": "feature_value_online",
        "kind": "store",
        "row": 1,
        "col": 3,
        "attrs": [
          "entity_key  PK",
          "group_id  PK",
          "value_map",
          "event_ts",
          "version_id  FK",
          "ttl"
        ]
      },
      {
        "id": "skew",
        "name": "skew_measurement",
        "kind": "store",
        "row": 2,
        "col": 1,
        "attrs": [
          "measure_id  PK",
          "feature_id  FK",
          "consumer_model",
          "sampled_at",
          "disagreement_rate",
          "verdict"
        ]
      },
      {
        "id": "tset",
        "name": "training_set",
        "kind": "store",
        "row": 2,
        "col": 2,
        "attrs": [
          "set_id  PK",
          "spine_uri",
          "snapshot_id",
          "lookback_s",
          "version_ids[]",
          "generated_at"
        ]
      },
      {
        "id": "pin",
        "name": "consumer_pin",
        "kind": "store",
        "row": 2,
        "col": 3,
        "attrs": [
          "pin_id  PK",
          "version_id  FK",
          "consumer_model",
          "criticality",
          "absence_policy"
        ]
      }
    ],
    "relations": [
      {
        "from": "ent",
        "to": "grp",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "grp",
        "to": "feat",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "feat",
        "to": "ver",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "grp",
        "to": "grant",
        "label": "1 : N",
        "from_side": "s1",
        "to_side": "n"
      },
      {
        "from": "grp",
        "to": "run",
        "label": "1 : N",
        "from_side": "s3",
        "to_side": "n"
      },
      {
        "from": "feat",
        "to": "voff",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "ver",
        "to": "von",
        "label": "stamps",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "run",
        "to": "voff",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "voff",
        "to": "von",
        "label": "projects",
        "from_side": "e",
        "to_side": "w",
        "kind": "optional"
      },
      {
        "from": "voff",
        "to": "tset",
        "label": "as-of",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "voff",
        "to": "skew",
        "label": "replayed",
        "from_side": "s1",
        "to_side": "n"
      },
      {
        "from": "von",
        "to": "pin",
        "label": "read by",
        "from_side": "s",
        "to_side": "n"
      }
    ],
    "note": "Two timestamps on every offline value, one on every online value. That asymmetry is the whole point-in-time guarantee. Lineage is a graph, not a table, and lives in its own store.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "12-online-read-sequence",
    "title": "Critical Flow — An ETA Request Reads a Feature Vector",
    "layout": "sequence",
    "canvas": {
      "width": 1720
    },
    "lifelines": [
      {
        "id": "eta",
        "label": "ETA model service",
        "kind": "external"
      },
      {
        "id": "sdk",
        "label": "Client SDK",
        "kind": "app"
      },
      {
        "id": "api",
        "label": "Serving API",
        "kind": "app"
      },
      {
        "id": "cache",
        "label": "Read cache",
        "kind": "store"
      },
      {
        "id": "on",
        "label": "Online store",
        "kind": "store"
      },
      {
        "id": "od",
        "label": "On-demand runtime",
        "kind": "app"
      },
      {
        "id": "log",
        "label": "Serving logger",
        "kind": "queue"
      }
    ],
    "messages": [
      {
        "from": "eta",
        "to": "sdk",
        "label": "GetVector(order, store, courier)",
        "kind": "call"
      },
      {
        "from": "sdk",
        "to": "api",
        "label": "gRPC, 5 groups, 180 features",
        "kind": "call"
      },
      {
        "from": "api",
        "to": "api",
        "label": "compiled plan from local cache",
        "kind": "self"
      },
      {
        "from": "api",
        "to": "cache",
        "label": "get hot store keys",
        "kind": "call"
      },
      {
        "from": "cache",
        "to": "api",
        "label": "hit: store_orders_15m",
        "kind": "return"
      },
      {
        "from": "api",
        "to": "on",
        "label": "BatchGetItem, 3 groups",
        "kind": "call"
      },
      {
        "from": "on",
        "to": "api",
        "label": "values + event_ts + version",
        "kind": "return"
      },
      {
        "from": "api",
        "to": "od",
        "label": "distance(courier, store)",
        "kind": "call"
      },
      {
        "from": "od",
        "to": "api",
        "label": "computed value",
        "kind": "return"
      },
      {
        "from": "api",
        "to": "api",
        "label": "age vs freshness SLO",
        "kind": "self"
      },
      {
        "from": "on",
        "to": "api",
        "label": "group 5 unavailable",
        "kind": "error"
      },
      {
        "from": "api",
        "to": "eta",
        "label": "vector + per-feature status",
        "kind": "return"
      },
      {
        "from": "api",
        "to": "eta",
        "label": "group 5: STALE, default applied",
        "kind": "error"
      },
      {
        "from": "api",
        "to": "log",
        "label": "1% sampled vector",
        "kind": "async"
      }
    ],
    "note": "Total budget 25 ms client-observed. The plan cache, the batch read and the reason codes are what keeps it inside that.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "13-materialisation-by-modality",
    "title": "Materialisation — One Definition, Four Paths",
    "layout": "swimlane",
    "canvas": {
      "width": 1740
    },
    "laneHeaderWidth": 170,
    "stages": [
      "Define",
      "Compute",
      "Write offline",
      "Write online",
      "Serve"
    ],
    "lanes": [
      {
        "title": "Batch features",
        "cells": [
          [
            {
              "label": "Definition + cadence",
              "kind": "app"
            }
          ],
          [
            {
              "label": "EMR Serverless",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Iceberg append",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Materialise down",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Latest value",
              "kind": "store"
            }
          ]
        ]
      },
      {
        "title": "Streaming features",
        "cells": [
          [
            {
              "label": "Definition + window",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Managed Flink",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Iceberg append",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Direct write",
              "kind": "app"
            }
          ],
          [
            {
              "label": "p99 ≤ 5 s",
              "kind": "store"
            }
          ]
        ]
      },
      {
        "title": "On-demand features",
        "cells": [
          [
            {
              "label": "Same artefact",
              "kind": "app"
            }
          ],
          [],
          [
            {
              "label": "Replayed at join",
              "kind": "app"
            }
          ],
          [],
          [
            {
              "label": "In path, ≤ 2 ms",
              "kind": "app"
            }
          ]
        ]
      },
      {
        "title": "Backfill",
        "cells": [
          [
            {
              "label": "Bounded window",
              "kind": "decision"
            }
          ],
          [
            {
              "label": "Isolated pool",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Rewrite partitions",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Only if read online",
              "kind": "decision"
            }
          ],
          [
            {
              "label": "No SLO impact",
              "kind": "opportunity"
            }
          ]
        ]
      }
    ],
    "note": "The two blank cells are the design: an on-demand feature has no precomputed value, so parity depends entirely on sharing the artefact.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "14-training-set-assembly",
    "title": "Point-in-Time Training Set Assembly",
    "layout": "flow",
    "chain": true,
    "canvas": {
      "width": 1760
    },
    "stages": [
      {
        "title": "Request",
        "nodes": [
          {
            "id": "spine",
            "label": "Entity–timestamp spine",
            "kind": "external",
            "sub": "500M rows"
          },
          {
            "id": "list",
            "label": "Feature list",
            "kind": "app",
            "sub": "200 features"
          },
          {
            "id": "lb",
            "label": "Lookback",
            "kind": "app",
            "sub": "72 h default"
          }
        ]
      },
      {
        "title": "Pin",
        "nodes": [
          {
            "id": "snap",
            "label": "Snapshot resolver",
            "kind": "app",
            "sub": "Iceberg snapshot id"
          },
          {
            "id": "vres",
            "label": "Version resolver",
            "kind": "app",
            "sub": "feature versions"
          }
        ]
      },
      {
        "title": "Join",
        "nodes": [
          {
            "id": "asof",
            "label": "As-of join",
            "kind": "app",
            "sub": "EMR Spark, p95 45 min"
          },
          {
            "id": "filt",
            "label": "Lookback filter",
            "kind": "app",
            "sub": "reason-coded nulls"
          },
          {
            "id": "leak",
            "label": "Leakage detector",
            "kind": "security",
            "sub": "ingest lag > horizon"
          }
        ]
      },
      {
        "title": "Emit",
        "nodes": [
          {
            "id": "set",
            "label": "Training set",
            "kind": "store",
            "sub": "S3, immutable"
          },
          {
            "id": "man",
            "label": "Manifest",
            "kind": "store",
            "sub": "spine + versions + snapshot"
          }
        ]
      },
      {
        "title": "Consume",
        "nodes": [
          {
            "id": "sm",
            "label": "SageMaker training",
            "kind": "external"
          },
          {
            "id": "eval",
            "label": "Evaluation harness",
            "kind": "external"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "man",
        "to": "asof",
        "label": "regenerate",
        "kind": "batch",
        "route": "gutter"
      },
      {
        "from": "leak",
        "to": "set",
        "label": "warning on dataset",
        "kind": "error"
      }
    ],
    "note": "Every value joined is the one whose ingestion timestamp was at or before the spine row's own timestamp. There is no other rule.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "15-deployment-architecture",
    "title": "Feature Store — Deployment Architecture",
    "layout": "nested",
    "canvas": {
      "width": 1780
    },
    "boxes": [
      {
        "title": "AWS eu-west-1 — active",
        "kind": "cloud",
        "dir": "col",
        "children": [
          {
            "title": "Ingress and identity",
            "kind": "boundary",
            "nodes": [
              {
                "id": "nlb",
                "label": "Internal NLB",
                "kind": "integration",
                "sub": "VPC only"
              },
              {
                "id": "alb",
                "label": "Catalogue ALB",
                "kind": "integration",
                "sub": "WAF + OIDC"
              },
              {
                "id": "iam",
                "label": "IAM / IRSA",
                "kind": "security"
              },
              {
                "id": "kms",
                "label": "KMS",
                "kind": "security",
                "sub": "customer keys"
              }
            ]
          },
          {
            "title": "AZ-a",
            "kind": "boundary",
            "nodes": [
              {
                "id": "p1",
                "label": "Serving pods",
                "kind": "app",
                "sub": "EKS, gRPC"
              },
              {
                "id": "f1",
                "label": "Flink task managers",
                "kind": "app"
              },
              {
                "id": "c1",
                "label": "Cache node",
                "kind": "store"
              }
            ]
          },
          {
            "title": "AZ-b",
            "kind": "boundary",
            "nodes": [
              {
                "id": "p2",
                "label": "Serving pods",
                "kind": "app",
                "sub": "EKS, gRPC"
              },
              {
                "id": "f2",
                "label": "Flink task managers",
                "kind": "app"
              },
              {
                "id": "c2",
                "label": "Cache node",
                "kind": "store"
              }
            ]
          },
          {
            "title": "AZ-c",
            "kind": "boundary",
            "nodes": [
              {
                "id": "p3",
                "label": "Serving pods",
                "kind": "app",
                "sub": "EKS, gRPC"
              },
              {
                "id": "f3",
                "label": "Flink job manager",
                "kind": "app"
              },
              {
                "id": "aur",
                "label": "Aurora writer",
                "kind": "store"
              }
            ]
          },
          {
            "title": "Regional services",
            "kind": "boundary",
            "nodes": [
              {
                "id": "ddb",
                "label": "DynamoDB",
                "kind": "store",
                "sub": "on-demand"
              },
              {
                "id": "s3",
                "label": "S3 + Iceberg",
                "kind": "store"
              },
              {
                "id": "kin",
                "label": "Kinesis",
                "kind": "queue",
                "sub": "7-day retention"
              },
              {
                "id": "emr",
                "label": "EMR Serverless",
                "kind": "app",
                "sub": "2 pools"
              },
              {
                "id": "fh",
                "label": "Firehose",
                "kind": "queue"
              }
            ]
          }
        ]
      },
      {
        "title": "AWS eu-central-1 — standby",
        "kind": "cloud",
        "nodes": [
          {
            "id": "sp",
            "label": "Serving pods",
            "kind": "app",
            "sub": "warm at 10%"
          },
          {
            "id": "gt",
            "label": "DynamoDB global table",
            "kind": "store",
            "sub": "replica"
          },
          {
            "id": "crr",
            "label": "S3 replica",
            "kind": "store",
            "sub": "cross-region"
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "msvc",
        "label": "Model services",
        "kind": "external",
        "sub": "same VPC"
      },
      {
        "id": "gha",
        "label": "GitHub Actions",
        "kind": "external"
      }
    ],
    "edges": [
      {
        "from": "msvc",
        "to": "nlb",
        "label": "gRPC"
      },
      {
        "from": "ddb",
        "to": "gt",
        "label": "replicate",
        "kind": "async"
      }
    ],
    "note": "Three AZs for serving, a warm second region at 10% capacity. S3 replicates cross-region on the same path as DynamoDB; RTO 15 min is met by rebuilding the online store, not by failing state over.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "16-definition-promotion-pipeline",
    "title": "Definition Promotion Pipeline",
    "layout": "flow",
    "chain": true,
    "canvas": {
      "width": 1780
    },
    "stages": [
      {
        "title": "Author",
        "nodes": [
          {
            "id": "pr",
            "label": "Definition PR",
            "kind": "external",
            "sub": "GitHub"
          },
          {
            "id": "local",
            "label": "Local compile",
            "kind": "app"
          }
        ]
      },
      {
        "title": "Build",
        "nodes": [
          {
            "id": "comp",
            "label": "Compiler",
            "kind": "app",
            "sub": "both plans or fail"
          },
          {
            "id": "dup",
            "label": "Duplicate detector",
            "kind": "security"
          },
          {
            "id": "lint",
            "label": "Contract lint",
            "kind": "security",
            "sub": "types, nulls, range"
          }
        ]
      },
      {
        "title": "Gates",
        "nodes": [
          {
            "id": "g1",
            "label": "Both plans compile?",
            "kind": "decision"
          },
          {
            "id": "g2",
            "label": "Owner approval?",
            "kind": "decision"
          },
          {
            "id": "g3",
            "label": "Backfill in budget?",
            "kind": "decision"
          }
        ]
      },
      {
        "title": "Promote",
        "nodes": [
          {
            "id": "pub",
            "label": "Registry publish",
            "kind": "app",
            "sub": "new version"
          },
          {
            "id": "life",
            "label": "experimental → production",
            "kind": "app"
          }
        ]
      },
      {
        "title": "Environments",
        "nodes": [
          {
            "id": "stg",
            "label": "Staging feature store",
            "kind": "external",
            "sub": "1% traffic shadow"
          },
          {
            "id": "prd",
            "label": "Production",
            "kind": "external",
            "sub": "≤ 30 min from merge"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "g1",
        "to": "pr",
        "label": "rejected",
        "kind": "error",
        "route": "gutter"
      },
      {
        "from": "g3",
        "to": "pr",
        "label": "over budget",
        "kind": "error",
        "route": "gutter"
      },
      {
        "from": "pub",
        "to": "stg",
        "label": "shadow first",
        "kind": "batch"
      }
    ],
    "note": "A definition that compiles only one of the two plans never reaches the registry. That single gate is the parity guarantee.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "17-observability",
    "title": "Observability — Signal by Stage",
    "layout": "grid",
    "canvas": {
      "width": 1780
    },
    "laneHeaderWidth": 160,
    "stages": [
      "Ingest",
      "Materialise",
      "Store",
      "Serve",
      "Consume"
    ],
    "lanes": [
      {
        "title": "Metrics",
        "cells": [
          [
            {
              "label": "Stream lag",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Run duration",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Partition skew",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "p99 read latency",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Vector error rate",
              "kind": "platform"
            }
          ]
        ]
      },
      {
        "title": "Logs",
        "cells": [
          [
            {
              "label": "Quarantine events",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Run audit",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Rebuild log",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Reason codes",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Sampled vectors",
              "kind": "store"
            }
          ]
        ]
      },
      {
        "title": "Traces",
        "cells": [
          [],
          [
            {
              "label": "Run → partition",
              "kind": "app"
            }
          ],
          [],
          [
            {
              "label": "SDK → DynamoDB",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Model → feature",
              "kind": "app"
            }
          ]
        ]
      },
      {
        "title": "Data quality",
        "cells": [
          [
            {
              "label": "Null rate, range",
              "kind": "security"
            }
          ],
          [
            {
              "label": "Freshness SLO",
              "kind": "security"
            }
          ],
          [
            {
              "label": "Completeness",
              "kind": "security"
            }
          ],
          [
            {
              "label": "Staleness flag",
              "kind": "security"
            }
          ],
          [
            {
              "label": "Skew replay verdict",
              "kind": "security"
            }
          ]
        ]
      },
      {
        "title": "Cost",
        "cells": [
          [
            {
              "label": "Shard hours",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "DPU hours by group",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "GB-month by group",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "$ per M reads",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Online, zero reads",
              "kind": "risk"
            }
          ]
        ]
      }
    ],
    "note": "The bottom-right cell is the one that pays for the platform: a feature materialised online that nobody has read in 30 days.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "18-feature-lifecycle-loop",
    "title": "The Feature Lifecycle Loop",
    "layout": "cycle",
    "canvas": {
      "width": 1500
    },
    "centre": {
      "label": "Feature lifecycle"
    },
    "nodes": [
      {
        "id": "def",
        "label": "Define",
        "kind": "app",
        "sub": "one artefact"
      },
      {
        "id": "mat",
        "label": "Materialise",
        "kind": "app",
        "sub": "two plans"
      },
      {
        "id": "srv",
        "label": "Serve",
        "kind": "app",
        "sub": "value + age + status"
      },
      {
        "id": "obs",
        "label": "Observe",
        "kind": "platform",
        "sub": "skew + drift"
      },
      {
        "id": "att",
        "label": "Attribute",
        "kind": "decision",
        "sub": "data or pipeline?"
      },
      {
        "id": "rev",
        "label": "Revise or retire",
        "kind": "app",
        "sub": "new version, pins notified"
      }
    ],
    "ringLabels": [
      "compiled plans",
      "version-stamped values",
      "1% sampled vectors",
      "verdict",
      "cause",
      "new version"
    ],
    "rx": 430,
    "ry": 215,
    "note": "The loop only closes because every served value carries the definition version that produced it.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "19-security-trust-zones",
    "title": "Feature Store — Security Trust Zones",
    "layout": "zones",
    "canvas": {
      "width": 1740
    },
    "zones": [
      {
        "title": "Corporate network",
        "kind": "trust",
        "nodes": [
          {
            "id": "ds",
            "label": "Data scientist",
            "kind": "actor"
          },
          {
            "id": "idp",
            "label": "Corporate IdP",
            "kind": "external",
            "sub": "OIDC"
          }
        ]
      },
      {
        "title": "Perimeter",
        "kind": "trust",
        "nodes": [
          {
            "id": "alb",
            "label": "Catalogue ALB",
            "kind": "integration",
            "sub": "WAF + OIDC"
          },
          {
            "id": "regapi",
            "label": "Registry API",
            "kind": "integration",
            "sub": "token-scoped"
          },
          {
            "id": "nopub",
            "label": "No public serving endpoint",
            "kind": "risk",
            "sub": "VPC only, by design"
          }
        ]
      },
      {
        "title": "Application — private VPC",
        "kind": "trust",
        "nodes": [
          {
            "id": "api",
            "label": "Serving API",
            "kind": "app",
            "sub": "mTLS, IRSA"
          },
          {
            "id": "od",
            "label": "On-demand runtime",
            "kind": "app",
            "sub": "sandboxed, 2 ms"
          },
          {
            "id": "comp",
            "label": "Compiler",
            "kind": "app"
          },
          {
            "id": "tss",
            "label": "Training-set service",
            "kind": "app"
          }
        ]
      },
      {
        "title": "Data — private endpoints",
        "kind": "trust",
        "nodes": [
          {
            "id": "on",
            "label": "Online store",
            "kind": "store",
            "sub": "KMS CMK"
          },
          {
            "id": "off",
            "label": "Offline store",
            "kind": "store",
            "sub": "Lake Formation grants"
          },
          {
            "id": "reg",
            "label": "Registry",
            "kind": "store"
          },
          {
            "id": "aud",
            "label": "Audit log",
            "kind": "store",
            "sub": "Object Lock"
          }
        ]
      },
      {
        "title": "Restricted",
        "kind": "trust",
        "nodes": [
          {
            "id": "pii",
            "label": "PII-derived groups",
            "kind": "store",
            "sub": "purpose-limited"
          },
          {
            "id": "slog",
            "label": "Serving log",
            "kind": "store",
            "sub": "inherits max class"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "ds",
        "to": "idp"
      },
      {
        "from": "ds",
        "to": "alb",
        "label": "HTTPS + id token"
      },
      {
        "from": "alb",
        "to": "regapi",
        "label": "scoped session"
      },
      {
        "from": "regapi",
        "to": "reg",
        "label": "group ACL check"
      },
      {
        "from": "api",
        "to": "on",
        "label": "scoped read"
      },
      {
        "from": "tss",
        "to": "off",
        "label": "grant",
        "kind": "batch"
      },
      {
        "from": "off",
        "to": "pii",
        "label": "class escalation blocked",
        "kind": "error"
      },
      {
        "from": "api",
        "to": "slog",
        "label": "sampled",
        "kind": "async"
      }
    ],
    "note": "A feature cannot be derived from a restricted column into a group of lower classification. That rule is enforced at registration, not at read.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "20-identity-and-access",
    "title": "Identity and Access — Offline Read and Online Read",
    "layout": "sequence",
    "canvas": {
      "width": 1720
    },
    "lifelines": [
      {
        "id": "ds",
        "label": "Data scientist",
        "kind": "actor"
      },
      {
        "id": "idp",
        "label": "Corporate IdP",
        "kind": "external"
      },
      {
        "id": "reg",
        "label": "Registry API",
        "kind": "app"
      },
      {
        "id": "lf",
        "label": "Lake Formation",
        "kind": "security"
      },
      {
        "id": "off",
        "label": "Offline store",
        "kind": "store"
      },
      {
        "id": "pod",
        "label": "Model pod",
        "kind": "app"
      },
      {
        "id": "api",
        "label": "Serving API",
        "kind": "app"
      }
    ],
    "messages": [
      {
        "from": "ds",
        "to": "idp",
        "label": "OIDC authenticate",
        "kind": "call"
      },
      {
        "from": "idp",
        "to": "ds",
        "label": "id token + group claims",
        "kind": "return"
      },
      {
        "from": "ds",
        "to": "reg",
        "label": "offline read: 3 feature groups",
        "kind": "call"
      },
      {
        "from": "reg",
        "to": "reg",
        "label": "group ACL + declared purpose",
        "kind": "self"
      },
      {
        "from": "reg",
        "to": "lf",
        "label": "request scoped credential",
        "kind": "call"
      },
      {
        "from": "lf",
        "to": "off",
        "label": "column and row grants",
        "kind": "call"
      },
      {
        "from": "off",
        "to": "ds",
        "label": "as-of rows, permitted columns",
        "kind": "return"
      },
      {
        "from": "reg",
        "to": "ds",
        "label": "group 3: purpose not granted",
        "kind": "error"
      },
      {
        "from": "pod",
        "to": "api",
        "label": "gRPC + IRSA workload identity",
        "kind": "call"
      },
      {
        "from": "api",
        "to": "api",
        "label": "role → authorised group set",
        "kind": "self"
      },
      {
        "from": "api",
        "to": "pod",
        "label": "vector, authorised groups only",
        "kind": "return"
      },
      {
        "from": "api",
        "to": "pod",
        "label": "PERMISSION_DENIED on group 5",
        "kind": "error"
      }
    ],
    "note": "A human proves purpose; a workload proves identity. Neither gets a shared key, and both are refused at group granularity.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  },
  {
    "id": "21-failure-classes",
    "title": "Failure Classes — Detection, Behaviour, Recovery",
    "layout": "grid",
    "canvas": {
      "width": 1780
    },
    "laneHeaderWidth": 190,
    "stages": [
      "Detection",
      "Immediate behaviour",
      "Recovery",
      "If it goes wrong"
    ],
    "lanes": [
      {
        "title": "Stale upstream",
        "cells": [
          [
            {
              "label": "Age > 2× SLO in 60 s",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Mark stale, flag age",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Late batch lands",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Silent old value",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Streaming lag",
        "cells": [
          [
            {
              "label": "Lag SLO breach",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Stale, not fresh",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Replay from checkpoint",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Double-counted window",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Schema drift at ingest",
        "cells": [
          [
            {
              "label": "Type, null, range check",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Quarantine the batch",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Owner fixes source",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Bad batch published",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Partial vector",
        "cells": [
          [
            {
              "label": "Per-group read status",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Reason code + default",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Group returns",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Whole request failed",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Online partition loss",
        "cells": [
          [
            {
              "label": "Read error rate",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Fail over in SLO",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Rebuild ≤ 90 min",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Untested rebuild path",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Hot key",
        "cells": [
          [
            {
              "label": "Per-key read count",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Coalesce + short TTL",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Projection for the model",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Tail latency blowout",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Definition mismatch",
        "cells": [
          [
            {
              "label": "Version stamp compare",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Stale, block promotion",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Re-materialise group",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Undetectable skew",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Region loss",
        "cells": [
          [
            {
              "label": "Zonal then regional health",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "AZ loss: no SLO impact",
              "kind": "app"
            }
          ],
          [
            {
              "label": "RTO 15 min, rebuilt",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "Cold second region",
              "kind": "risk"
            }
          ]
        ]
      }
    ],
    "note": "Every row's right-hand cell is the failure the platform is designed to make impossible, not the one it accepts.",
    "meta": {
      "v": "1.0",
      "owner": "Data Platform Architecture",
      "date": "2026-09"
    }
  }
]
