{
  "docVersion": 1,
  "id": "template-anatomy-of-a-safe-rpc",
  "name": "Anatomy of a safe RPC",
  "purpose": "A reference request path where every hop demonstrates one stability pattern — deadline propagation, retry budget, circuit breaker, bulkhead, hedging and fallback — so a flaky dependency can't take the system down.",
  "nodes": {
    "client": {
      "type": "mobile",
      "label": "Mobile app",
      "x": 20,
      "y": 250,
      "runtime": "1s total budget"
    },
    "gw": {
      "type": "gateway",
      "label": "Edge Gateway",
      "x": 270,
      "y": 250,
      "runtime": "stamps deadline: 800ms",
      "notes": "Owns the client's 1s budget: sets an 800ms downstream deadline so inner work never outlives the caller."
    },
    "api": {
      "type": "k8s",
      "label": "Orders API",
      "x": 520,
      "y": 250,
      "runtime": "retry budget: 10%/s",
      "color": "blue",
      "patterns": [
        "stateless",
        "autoscale"
      ],
      "notes": "Retries are budgeted, not unbounded: at most 10% extra load from retries, with jittered backoff."
    },
    "pool": {
      "type": "worker",
      "label": "Payments client pool",
      "x": 770,
      "y": 90,
      "runtime": "bulkhead · 20 threads max",
      "notes": "The dangerous dependency gets its own pool — when the PSP hangs, it exhausts these 20 threads and nothing else."
    },
    "psp": {
      "type": "payment",
      "label": "PSP / Gateway",
      "x": 1020,
      "y": 90,
      "runtime": "flaky third party",
      "color": "amber"
    },
    "repa": {
      "type": "database",
      "label": "Catalog replica A",
      "x": 770,
      "y": 320,
      "runtime": "primary read path"
    },
    "repb": {
      "type": "database",
      "label": "Catalog replica B",
      "x": 770,
      "y": 470,
      "runtime": "hedge target"
    },
    "cache": {
      "type": "cache",
      "label": "Fallback cache",
      "x": 1020,
      "y": 320,
      "runtime": "last-good responses",
      "color": "green",
      "notes": "Serves slightly-stale catalog data when both replicas misbehave — the user sees a page, not an error."
    }
  },
  "edges": {
    "e1": {
      "from": "client",
      "to": "gw",
      "fromSide": "right",
      "toSide": "left",
      "label": "POST /order · 1s budget",
      "animated": true,
      "patterns": [
        "timeout",
        "authenticated"
      ]
    },
    "e2": {
      "from": "gw",
      "to": "api",
      "fromSide": "right",
      "toSide": "left",
      "label": "deadline: 800ms left",
      "animated": true,
      "patterns": [
        "timeout"
      ]
    },
    "e3": {
      "from": "api",
      "to": "pool",
      "fromSide": "right",
      "toSide": "left",
      "label": "isolated pool",
      "patterns": [
        "bulkhead"
      ]
    },
    "e4": {
      "from": "pool",
      "to": "psp",
      "fromSide": "right",
      "toSide": "left",
      "label": "charge · 500ms cap",
      "animated": true,
      "patterns": [
        "circuit-breaker",
        "retry",
        "timeout"
      ]
    },
    "e5": {
      "from": "api",
      "to": "repa",
      "fromSide": "right",
      "toSide": "left",
      "label": "read catalog",
      "patterns": [
        "timeout"
      ]
    },
    "e6": {
      "from": "api",
      "to": "repb",
      "fromSide": "bottom",
      "toSide": "left",
      "label": "hedge at p95",
      "style": "dashed",
      "patterns": [
        "hedged"
      ]
    },
    "e7": {
      "from": "repa",
      "to": "cache",
      "fromSide": "right",
      "toSide": "left",
      "label": "on failure: serve stale",
      "style": "dashed",
      "patterns": [
        "fallback",
        "cache-aside"
      ]
    }
  },
  "boxes": {
    "b1": {
      "x": 730,
      "y": 20,
      "w": 480,
      "h": 240,
      "label": "the dangerous dependency — pooled and fused",
      "color": "amber",
      "opacity": 0.04
    }
  },
  "texts": {
    "t1": {
      "x": 20,
      "y": 430,
      "text": "the deadline ladder:\nclient 1000ms → gateway 800ms → PSP call 500ms.\nEvery inner timeout is SHORTER than its caller's —\nreverse that and you build zombie work.",
      "color": "green",
      "size": 12
    },
    "t2": {
      "x": 20,
      "y": 570,
      "text": "read the badges: every edge declares its armor.\nAn unlabeled remote call is an unmanaged risk.",
      "color": "amber",
      "size": 12
    }
  },
  "meta": {
    "createdAt": "2026-07-13T09:00:00.000Z",
    "modifiedAt": "2026-07-13T09:00:00.000Z"
  }
}