{
 "title": "Feedback Loop Field Guide",
 "author": "Konrad Bloor",
 "authorUrl": "https://konradbloor.com",
 "url": "https://konradbloor.com/loops",
 "license": "https://creativecommons.org/licenses/by/4.0/",
 "citeAs": "Konrad Bloor, \"Feedback Loop Field Guide\" v0.23.1, https://konradbloor.com/loops",
 "meta": {
  "title": "Feedback Loop Field Guide",
  "description": "A catalog of feedback loops across Build, Value, Reach, Team and Risk tracks, ordered by latency. Latencies are in seconds: min = fastest plausible signal, typical = normal case, max = slow end of range. Loops carry stage, delivery (push/pull), cadence, latency kind (event/trend) and fast-proxy links.",
  "version": "0.23.1",
  "units": "seconds",
  "tracks": [
   {
    "id": "build",
    "name": "Build",
    "question": "Can we make the thing?"
   },
   {
    "id": "value",
    "name": "Value",
    "question": "Is it worth making?"
   },
   {
    "id": "reach",
    "name": "Reach",
    "question": "Can we get it to people?"
   },
   {
    "id": "team",
    "name": "Team",
    "question": "Can we sustain the people doing the thing?"
   },
   {
    "id": "risk",
    "name": "Risk & Moat",
    "question": "Do the economics allow success to continue?"
   }
  ],
  "changelog": [
   {
    "version": "0.23.1",
    "date": "2026-08-01",
    "entries": [
     {
      "type": "changed",
      "note": "Balancing pairs now trace in both directions (throughput, retention, NPS/CSAT, ROAS, pipeline, win/loss gained the reverse link)."
     }
    ]
   },
   {
    "version": "0.23.0",
    "date": "2026-07-21",
    "entries": [
     {
      "type": "added",
      "loop": "dead-code"
     }
    ]
   },
   {
    "version": "0.22.0",
    "date": "2026-07-19",
    "entries": [
     {
      "type": "changed",
      "loop": "email-reputation",
      "note": "Split out the instant reject/spam signal; this loop is now the slow sender-reputation trend."
     },
     {
      "type": "added",
      "loop": "email-reject-rate"
     }
    ]
   },
   {
    "version": "0.21.0",
    "date": "2026-07-14",
    "entries": [
     {
      "type": "added",
      "loop": "rework-rate"
     }
    ]
   },
   {
    "version": "0.20.0",
    "date": "2026-07-12",
    "entries": [
     {
      "type": "added",
      "loop": "liquidation"
     },
     {
      "type": "added",
      "loop": "cpc"
     }
    ]
   },
   {
    "version": "0.18.2",
    "date": "2026-07-10",
    "entries": [
     {
      "type": "changed",
      "note": "Tightened loop notes."
     }
    ]
   },
   {
    "version": "0.18.1",
    "date": "2026-07-10",
    "entries": [
     {
      "type": "added",
      "note": "Build (+32): Coverage / mutation testing, Accessibility checks, Pair / mob programming, AI code review, Visual regression testing, Canary / progressive rollout, Synthetic monitoring / uptime checks, Chaos engineering / game days, Load / stress testing, Threat modeling, SCA / dependency vulnerabilities, Cloud misconfiguration / CSPM, Runtime security detection, DAST / automated web scanning, Open vulnerability age / patch SLA, Bug bounty / VDP, Code complexity & coupling metrics, Hotspot analysis (churn × complexity), Dependency freshness (libyear), App store review gate, Daily standup, Sprint predictability (say:do ratio), Design / RFC review, Data quality tests, Pipeline freshness / data SLAs, Data anomaly detection, Eval suite / golden-set regression, LLM-as-judge scoring, AI red-teaming / adversarial evals, Token / cost per request, Model latency / time-to-first-token, Model & output drift."
     },
     {
      "type": "added",
      "note": "Value (+12): Beta / early-access program, Sprint review / stakeholder demo, Funnel / drop-off analysis, Thumbs up/down on AI output, AI synthesis of qualitative streams, Public reviews (G2 / app stores / Reddit), Sean Ellis PMF survey, Willingness-to-pay research, Feature request board / upvotes, Trial / freemium conversion, Stickiness (DAU/MAU), Churn interviews / exit surveys."
     },
     {
      "type": "added",
      "note": "Reach (+11): Influencer / sponsorship performance, Click-through rate, Unsubscribe / list churn, Pipeline stage conversion, Sales cycle length, AI search visibility (AEO / GEO), App store ratings & ASO, Comments / audience conversation, Comments & DMs, Events / webinar performance, Community activity & sentiment."
     },
     {
      "type": "added",
      "note": "Team (+10): Sourcing response rate, Compensation benchmarking, Onboarding ramp / time-to-first-commit, Developer experience survey, Pulse surveys, Meeting load / focus time, On-call load / pages per person, Bus factor / knowledge concentration, Performance reviews / 360 feedback, OKR check-ins / goal scoring."
     },
     {
      "type": "added",
      "note": "Risk & Moat (+11): AI / inference spend, Investor / fundraising feedback, Pricing realization / discount rate, Cash collection / DSO, Budget vs actuals (monthly close), Revenue forecast accuracy, 13-week cash flow forecast, Revenue concentration, Vendor / provider concentration, Compliance audits (SOC2 / ISO), Fraud / abuse / chargeback rate."
     }
    ]
   },
   {
    "version": "0.9.0",
    "date": "2026-07-02",
    "entries": [
     {
      "type": "added",
      "note": "Initial catalog, 123 loops: Build 39, Value 24, Reach 36, Team 9, Risk & Moat 15."
     }
    ]
   }
  ]
 },
 "loops": [
  {
   "id": "ide-feedback",
   "name": "IDE inline feedback",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 0.05,
    "typical": 0.3,
    "max": 2
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is this code correct?",
   "tools": [
    "VS Code",
    "IntelliJ",
    "Copilot"
   ],
   "notes": "The innermost loop, feedback before you finish typing.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "errors as you type"
   ]
  },
  {
   "id": "syntax",
   "name": "Syntax / parser",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 0.05,
    "typical": 0.5,
    "max": 3
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is this code correct?",
   "tools": [
    "compiler",
    "interpreter"
   ],
   "notes": "Binary, instant, free.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "pass / fail"
   ]
  },
  {
   "id": "types",
   "name": "Type system",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 0.2,
    "typical": 2,
    "max": 30
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is this code correct?",
   "tools": [
    "TypeScript",
    "mypy",
    "Rust"
   ],
   "notes": "Shape errors inside your own walls.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "type errors"
   ]
  },
  {
   "id": "hot-reload",
   "name": "Hot reload / REPL",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 0.5,
    "typical": 3,
    "max": 15
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Does this behave as I expect?",
   "tools": [
    "Vite HMR",
    "Fast Refresh",
    "REPL",
    "Storybook"
   ],
   "notes": "Visual/behavioral confirmation without a full rebuild.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "looks right / doesn't"
   ]
  },
  {
   "id": "schema-validation",
   "name": "Runtime schema validation",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 1,
    "typical": 60,
    "max": 3600
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Does outside data violate our assumptions?",
   "tools": [
    "Zod",
    "Pydantic",
    "io-ts",
    "protobuf"
   ],
   "notes": "The guard at the gate, catches what types can't: the outside world.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "validation failures"
   ]
  },
  {
   "id": "lint",
   "name": "Lint / static analysis",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 2,
    "typical": 30,
    "max": 300
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Does this follow our conventions?",
   "tools": [
    "ESLint",
    "Ruff",
    "clippy"
   ],
   "notes": "Style and convention enforcement at build time.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "violations"
   ]
  },
  {
   "id": "test-coverage",
   "name": "Coverage / mutation testing",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 120,
    "typical": 600,
    "max": 3600
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Would our tests even notice this bug?",
   "tools": [
    "coverage gates",
    "Stryker",
    "mutmut"
   ],
   "notes": "A loop about your loops: coverage says what the tests touch, mutation testing says whether they'd actually fail. Both are gameable; mutation less so.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% covered",
    "% mutants killed"
   ],
   "balancedBy": [
    "build-time"
   ]
  },
  {
   "id": "a11y-checks",
   "name": "Accessibility checks",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 60,
    "typical": 600,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Can everyone actually use this?",
   "tools": [
    "axe-core",
    "eslint-plugin-jsx-a11y",
    "manual audits"
   ],
   "notes": "Automated checks catch roughly a third of WCAG issues in seconds; the rest need a human with a screen reader. Cheap where it's automated, neglected where it isn't.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "violations"
   ]
  },
  {
   "id": "unit-tests",
   "name": "Unit tests",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 5,
    "typical": 120,
    "max": 900
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is the logic correct?",
   "tools": [
    "Jest",
    "pytest",
    "Vitest"
   ],
   "notes": "Fitness function for individual units of logic.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "sentry"
   ],
   "units": [
    "pass / fail"
   ]
  },
  {
   "id": "integration-tests",
   "name": "Integration tests",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 60,
    "typical": 600,
    "max": 3600
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Do the contracts between parts hold?",
   "tools": [
    "Testcontainers",
    "Playwright API"
   ],
   "notes": "Catches drift between components.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "pass / fail"
   ]
  },
  {
   "id": "code-review",
   "name": "Code review",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 1800,
    "typical": 43200,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Would another human build it this way?",
   "tools": [
    "GitHub PRs",
    "Graphite"
   ],
   "notes": "Human loop between lint and CI, catches design, not just defects.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "comments",
    "approval"
   ]
  },
  {
   "id": "pairing",
   "name": "Pair / mob programming",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 5,
    "typical": 60,
    "max": 3600
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "ic",
   "decision": "Would another human build it this way, while I'm still typing?",
   "tools": [
    "pair programming",
    "mob programming"
   ],
   "notes": "Code review at conversation speed. The objection arrives while your hands are still on the keyboard. The pair shares one context and one set of blind spots, so it complements async review rather than replacing it. Nearly impossible to measure, which is exactly why orgs undervalue it.",
   "framework": "XP",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "code-review"
   ],
   "units": [
    "in-flight corrections"
   ]
  },
  {
   "id": "ai-code-review",
   "name": "AI code review",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 60,
    "typical": 300,
    "max": 1800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Does a tireless machine reviewer spot what I missed?",
   "tools": [
    "Claude Code review",
    "Copilot code review",
    "Greptile"
   ],
   "notes": "A new rung between lint and human review, catches real bugs in minutes and never gets tired. What it misses tells you what humans are still for.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "code-review"
   ],
   "units": [
    "findings"
   ]
  },
  {
   "id": "e2e-tests",
   "name": "E2E tests",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 300,
    "typical": 1800,
    "max": 7200
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Do whole flows work?",
   "tools": [
    "Playwright",
    "Cypress"
   ],
   "notes": "High coverage, flaky signal. Trades fidelity for breadth.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "sentry"
   ],
   "aiAssisted": true,
   "units": [
    "pass / fail",
    "flake %"
   ]
  },
  {
   "id": "visual-regression",
   "name": "Visual regression testing",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 60,
    "typical": 600,
    "max": 3600
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did this change break how it looks?",
   "tools": [
    "Percy",
    "Chromatic",
    "Playwright screenshots"
   ],
   "notes": "Screenshot diffs catch the CSS regression the unit tests can't see. The fidelity lever is diff-threshold tuning. Too tight and every antialiasing shift pages a human.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "bug-reports"
   ],
   "units": [
    "visual diffs flagged"
   ],
   "aiAssisted": true
  },
  {
   "id": "sentry",
   "name": "Error monitoring",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is it correct in reality?",
   "tools": [
    "Sentry",
    "Rollbar",
    "PostHog error tracking",
    "Crashlytics"
   ],
   "notes": "Reality's opinion of your test suite. On mobile, crash-free sessions % is this loop's headline number.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "bug-reports"
   ],
   "units": [
    "errors/hr",
    "users affected"
   ],
   "actions": [
    "rollback or hotfix",
    "add a regression test",
    "mute and ticket if benign"
   ]
  },
  {
   "id": "bug-reports",
   "name": "Bug reports",
   "track": "build",
   "layer": "Correctness",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "What did every earlier loop miss?",
   "tools": [
    "Jira",
    "Linear",
    "support inbox"
   ],
   "notes": "The most expensive way to find a defect.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "reports/wk"
   ],
   "balancedBy": [
    "throughput"
   ],
   "actions": [
    "fix, then ask which earlier loop should have caught it"
   ]
  },
  {
   "id": "pager",
   "name": "Alerts / on-call pages",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 60,
    "typical": 900,
    "max": 3600
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is production healthy right now?",
   "tools": [
    "PagerDuty",
    "Opsgenie"
   ],
   "notes": "Production telling you something, loudly.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "pages"
   ],
   "actions": [
    "follow the runbook",
    "rollback the recent deploy",
    "declare an incident"
   ]
  },
  {
   "id": "apm",
   "name": "APM / distributed tracing",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Where is it slow and why?",
   "tools": [
    "OpenTelemetry",
    "Datadog",
    "Honeycomb",
    "Grafana"
   ],
   "notes": "Spans and telemetry: latency, error rates, p99s. OpenTelemetry is the usual instrumentation.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "ms p50–p99",
    "error %"
   ]
  },
  {
   "id": "slos",
   "name": "SLO / error budget burn",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Are we reliable enough to keep shipping?",
   "tools": [
    "SLO dashboards"
   ],
   "notes": "Feedback formalized as a contract.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% error budget burned"
   ],
   "actions": [
    "freeze features, spend the budget on reliability",
    "renegotiate the SLO"
   ]
  },
  {
   "id": "postmortems",
   "name": "Incident post-mortems",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 259200,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "What structural weakness did this expose?",
   "tools": [
    "Blameless reviews"
   ],
   "notes": "Delayed but very high fidelity.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "action items"
   ],
   "actions": [
    "fix the systemic cause",
    "add the guardrail"
   ]
  },
  {
   "id": "canary-rollouts",
   "name": "Canary / progressive rollout",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 300,
    "typical": 1800,
    "max": 14400
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does this deploy hurt real traffic at 1% before it can hurt 100%?",
   "tools": [
    "feature flags (LaunchDarkly, Statsig)",
    "canary analysis",
    "blue-green deploys"
   ],
   "notes": "The missing rung between CI and the pager, production feedback with the blast radius dialed down. Kill switches make rollback a config change, not a deploy.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "dora-cfr"
   ],
   "units": [
    "error delta vs baseline"
   ],
   "actions": [
    "halt and rollback",
    "proceed to 100%"
   ]
  },
  {
   "id": "synthetic-monitoring",
   "name": "Synthetic monitoring / uptime checks",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 60,
    "typical": 300,
    "max": 3600
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the front door open right now?",
   "tools": [
    "Checkly",
    "Pingdom",
    "health probes"
   ],
   "notes": "Scripted users hitting critical paths every minute, catches the outage before a human does, but only on the paths you thought to script.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "uptime %",
    "failed checks"
   ]
  },
  {
   "id": "chaos-engineering",
   "name": "Chaos engineering / game days",
   "track": "build",
   "layer": "Reliability",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Does our resilience survive contact with induced failure?",
   "tools": [
    "fault injection",
    "game days",
    "DR drills",
    "backup restore drills"
   ],
   "notes": "Synthetic incidents on your schedule instead of real ones on the pager's, the complementary leading loop to the post-mortem. The backup-restore drill is the variant nobody runs until the disaster: an untested backup is a hope, not a plan.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "postmortems"
   ],
   "units": [
    "weaknesses found"
   ]
  },
  {
   "id": "benchmarks",
   "name": "Benchmark tests",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 300,
    "typical": 1800,
    "max": 14400
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did this change make it slower?",
   "tools": [
    "k6",
    "criterion",
    "CI perf gates"
   ],
   "notes": "Performance regression caught before deploy.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "apm"
   ],
   "units": [
    "ms",
    "ops/s"
   ]
  },
  {
   "id": "load-testing",
   "name": "Load / stress testing",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "At what load does it actually break?",
   "tools": [
    "k6",
    "Gatling",
    "Locust"
   ],
   "notes": "The performance sibling loop of chaos engineering: synthetic 10x on your schedule instead of real 10x on launch day. Staging never quite matches production. Treat the number as a bound, not a forecast.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "capacity"
   ],
   "units": [
    "breaking point (RPS)",
    "p99 under load"
   ]
  },
  {
   "id": "capacity",
   "name": "Capacity / scaling signals",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Will this architecture survive growth?",
   "tools": [
    "autoscaler metrics",
    "load forecasts"
   ],
   "notes": "Demand signal disguised as infrastructure pain.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% utilization"
   ]
  },
  {
   "id": "bundle-size",
   "name": "Bundle size / asset weight",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 30,
    "typical": 180,
    "max": 1800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did this change bloat the download?",
   "tools": [
    "size-limit",
    "bundlewatch",
    "webpack-bundle-analyzer"
   ],
   "notes": "Fastest front-end loop: caught on the PR, before a page ever renders.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "lighthouse"
   ],
   "units": [
    "kB"
   ]
  },
  {
   "id": "lighthouse",
   "name": "Lighthouse / synthetic performance",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 60,
    "typical": 600,
    "max": 3600
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is the page fast in the lab?",
   "tools": [
    "Lighthouse CI",
    "WebPageTest"
   ],
   "notes": "Lab data, deterministic and leading, but a synthetic proxy for what real users feel.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "core-web-vitals"
   ],
   "units": [
    "score 0–100"
   ]
  },
  {
   "id": "memory-utilization",
   "name": "Memory / resource utilization",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Are we leaking memory or heading for an OOM?",
   "tools": [
    "heap profiler",
    "cgroup / RSS metrics",
    "OOM-kill alerts"
   ],
   "notes": "Slow creep in staging, sudden OOM in prod. Same loop, two speeds.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "MB",
    "OOM kills"
   ]
  },
  {
   "id": "core-web-vitals",
   "name": "Core Web Vitals (field / RUM)",
   "track": "build",
   "layer": "Performance",
   "latency": {
    "min": 86400,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is the page fast for real users?",
   "tools": [
    "CrUX",
    "web-vitals RUM",
    "Search Console"
   ],
   "notes": "LCP, INP, CLS at p75 over a 28-day rolling window. The field truth Lighthouse only estimates, and a ranking signal.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "ms at p75",
    "CLS"
   ]
  },
  {
   "id": "secrets-scan",
   "name": "Secrets detection",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 2,
    "typical": 60,
    "max": 600
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did we just leak a credential?",
   "tools": [
    "gitleaks",
    "GitHub secret scanning"
   ],
   "notes": "One of the few security loops that's instant.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "leaks found"
   ]
  },
  {
   "id": "threat-modeling",
   "name": "Threat modeling",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Where would an attacker go, before we build it?",
   "tools": [
    "STRIDE",
    "attack trees",
    "design review"
   ],
   "notes": "The flaw caught at the whiteboard costs a conversation; the same flaw caught by the pen test costs a rebuild.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "pentest"
   ],
   "units": [
    "threats identified"
   ],
   "aiAssisted": true,
   "actions": [
    "redesign the risky surface",
    "backlog the mitigations"
   ]
  },
  {
   "id": "sast",
   "name": "SAST / code security scan",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 120,
    "typical": 1800,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Did we just write a vulnerability?",
   "tools": [
    "Semgrep",
    "CodeQL"
   ],
   "notes": "Scans the code you wrote, at commit time. Noisy, fidelity depends on triage discipline.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "pentest"
   ],
   "aiAssisted": true,
   "units": [
    "vulns by severity"
   ]
  },
  {
   "id": "sca",
   "name": "SCA / dependency vulnerabilities",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Did we inherit a vulnerability, and can it reach us?",
   "tools": [
    "Dependabot",
    "Snyk",
    "OSV / CVE feeds"
   ],
   "notes": "Fires on someone else's event, a CVE lands against code you haven't touched in a year. Noisy: most hits sit in code paths you never call, so reachability triage is the fidelity lever.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "pentest"
   ],
   "units": [
    "open CVEs by severity"
   ],
   "aiAssisted": true,
   "actions": [
    "patch or pin",
    "triage reachability",
    "accept the risk with an expiry date"
   ]
  },
  {
   "id": "cspm",
   "name": "Cloud misconfiguration / CSPM",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is our infrastructure drifting into exposure?",
   "tools": [
    "AWS Config / Security Hub",
    "Wiz / Prisma",
    "tfsec / IaC scans"
   ],
   "notes": "The public-S3-bucket loop. Code scanners read the repo; this reads the live cloud, where drift happens without a commit.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "pentest"
   ],
   "units": [
    "open misconfigurations"
   ]
  },
  {
   "id": "runtime-security",
   "name": "Runtime security detection",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is someone attacking us right now?",
   "tools": [
    "WAF",
    "SIEM / audit logs",
    "anomaly alerts"
   ],
   "notes": "The lagging half of security that scans can't cover, detection instead of prevention. Noisy enough that triage discipline is the real fidelity.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "alerts"
   ]
  },
  {
   "id": "dast",
   "name": "DAST / automated web scanning",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 3600,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does the running app expose known attack patterns?",
   "tools": [
    "OWASP ZAP",
    "Burp scans in CI"
   ],
   "notes": "The automated sibling loop of the pen test, probes the deployed app on a schedule instead of an engagement. Finds the known patterns; the human finds the novel ones.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "periodic",
   "latencyKind": "event",
   "proxyFor": [
    "pentest"
   ],
   "units": [
    "findings per scan"
   ]
  },
  {
   "id": "vuln-age",
   "name": "Open vulnerability age / patch SLA",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Are we closing holes faster than we open them?",
   "tools": [
    "vuln management dashboards",
    "SLA by severity"
   ],
   "notes": "Every scanner feeds a backlog, and this is the loop that watches whether the backlog is shrinking. It's also the number auditors actually check.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "median days open by severity"
   ],
   "aiAssisted": true,
   "actions": [
    "set SLAs by severity",
    "burn down the backlog"
   ]
  },
  {
   "id": "bug-bounty",
   "name": "Bug bounty / VDP",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 86400,
    "typical": 1210000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "What can an unbounded adversary pool find that we can't?",
   "tools": [
    "HackerOne",
    "Bugcrowd",
    "security.txt / VDP"
   ],
   "notes": "Continuous where the pen test is commissioned: reports arrive unbidden from an unbounded researcher pool, and you pay per find instead of per engagement. Triage load is the hidden cost.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "valid reports"
   ],
   "aiAssisted": true
  },
  {
   "id": "pentest",
   "name": "Pen test / red team",
   "track": "build",
   "layer": "Security",
   "latency": {
    "min": 604800,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Can an adversary actually get in?",
   "tools": [
    "external pen test",
    "red team exercise"
   ],
   "notes": "High fidelity, very slow cycle. The tabletop drill is the same loop run against your response process instead of your perimeter.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "findings by severity"
   ],
   "actions": [
    "remediate criticals first",
    "re-test to confirm"
   ]
  },
  {
   "id": "build-time",
   "name": "Build & CI duration",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 300,
    "typical": 86400,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is our own loop degrading?",
   "tools": [
    "CI dashboards"
   ],
   "notes": "A feedback loop about your feedback loops.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "minutes"
   ],
   "balancedBy": [
    "test-coverage"
   ]
  },
  {
   "id": "code-complexity",
   "name": "Code complexity & coupling metrics",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 120,
    "typical": 600,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is this change making the code structurally worse?",
   "tools": [
    "SonarQube",
    "radon",
    "ESLint complexity rules"
   ],
   "notes": "Cyclomatic/cognitive complexity, duplication, module coupling, on the PR like lint, and easy to game: thresholds invite threshold-dodging. The OO metrics (LCOM, CBO, Law of Demeter) don't transfer to FP, where the analogues are module coupling and purity boundaries.",
   "units": [
    "complexity per function",
    "duplication %",
    "module coupling"
   ],
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "code-hotspots"
   ],
   "actions": [
    "refactor only if the file is hot",
    "tune thresholds to advisory"
   ]
  },
  {
   "id": "dead-code",
   "name": "Unused code / dead exports",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 30,
    "typical": 300,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Are we accumulating unused code?",
   "tools": [
    "knip",
    "ts-prune",
    "depcheck"
   ],
   "notes": "Whole-project analysis for files, exports, and dependencies nothing imports. TypeScript and lint catch unused locals inside a file, but only project-wide analysis catches an export no other file uses. Medium fidelity: dynamic imports, framework entry points, and genuine public API read as false positives, so treat hits as candidates to review, not delete-on-sight. Best run as a per-PR ratchet on net-new code rather than a gate on the whole backlog.",
   "units": [
    "unused files / exports / deps",
    "dead-code %"
   ],
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "tech-debt"
   ],
   "actions": [
    "rule out dynamic and entry-point use before deleting",
    "ratchet net-new, don't gate the backlog"
   ]
  },
  {
   "id": "code-hotspots",
   "name": "Hotspot analysis (churn × complexity)",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Where is complexity actually costing us?",
   "tools": [
    "CodeScene",
    "code-maat",
    "git log frequency analysis"
   ],
   "notes": "Churn × complexity is what makes the static numbers mean something: complexity in a file nobody touches is trivia; in a file with 40 commits this quarter it's a fire. Lab snapshot vs field truth, the same split as Lighthouse and Core Web Vitals, for code structure.",
   "units": [
    "churn × complexity rank",
    "files flagged"
   ],
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "tech-debt"
   ],
   "actions": [
    "schedule a refactoring sprint",
    "add tests before touching"
   ]
  },
  {
   "id": "rework-rate",
   "name": "Rework rate / code churn",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How much recent code are we already rewriting?",
   "tools": [
    "CodeScene",
    "GitClear",
    "git-of-theseus"
   ],
   "notes": "The share of new code rewritten again within weeks. High rework signals unclear requirements or a thrashing design, not productivity. A repo-wide leading proxy for where hotspots will form.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "code-hotspots"
   ],
   "units": [
    "% of code churned within N weeks"
   ]
  },
  {
   "id": "dependency-freshness",
   "name": "Dependency freshness (libyear)",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How far behind the ecosystem are we drifting?",
   "tools": [
    "libyear",
    "Renovate",
    "Dependabot version updates"
   ],
   "notes": "Dependency drift is the precondition for CVEs hurting you. Current means the patch is a version bump; three majors behind means the patch is a migration project. Supply-chain tech debt, and it sets your future time-to-patch.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "vuln-age"
   ],
   "units": [
    "libyears behind"
   ],
   "actions": [
    "turn on auto-update PRs",
    "schedule an upgrade spike"
   ]
  },
  {
   "id": "pr-cycle-time",
   "name": "PR cycle time",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is friction accumulating?",
   "tools": [
    "LinearB",
    "Swarmia"
   ],
   "notes": "Leading indicator of tech debt and process drag.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "dora-lead-time"
   ],
   "units": [
    "hours open"
   ]
  },
  {
   "id": "dora-deploy-freq",
   "name": "Deployment frequency",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How often do we ship to production?",
   "tools": [
    "CI/CD analytics",
    "Sleuth",
    "DX"
   ],
   "notes": "How many OODA cycles you complete per unit time, the cadence of every other Build loop.",
   "framework": "DORA",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "deploys/wk"
   ],
   "balancedBy": [
    "dora-cfr",
    "dora-mttr"
   ]
  },
  {
   "id": "app-review-gate",
   "name": "App store review gate",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 3600,
    "typical": 172800,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "Will the gatekeeper let this release through?",
   "tools": [
    "App Store review",
    "Play Console staged rollout"
   ],
   "notes": "The only loop in Build whose latency belongs to someone else. It caps your deploy frequency, breaks your hotfix MTTR, and its rejections arrive with the clarity of a fortune cookie.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "review turnaround",
    "rejection rate"
   ],
   "actions": [
    "keep an expedite playbook",
    "server-drive features to skip the gate",
    "stage rollouts behind flags"
   ]
  },
  {
   "id": "dora-lead-time",
   "name": "Lead time for changes",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How long from commit to production?",
   "tools": [
    "CI/CD analytics",
    "LinearB"
   ],
   "notes": "The physical length of your ship loop. Everything downstream inherits this latency.",
   "framework": "DORA",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "hours commit → prod"
   ],
   "balancedBy": [
    "dora-cfr"
   ]
  },
  {
   "id": "dora-cfr",
   "name": "Change failure rate",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "What fraction of deploys break something?",
   "tools": [
    "incident tagging",
    "deploy annotations"
   ],
   "notes": "Speed without this is just shipping bugs faster.",
   "framework": "DORA",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% of deploys"
   ],
   "balancedBy": [
    "dora-deploy-freq",
    "dora-lead-time"
   ],
   "actions": [
    "shrink batch size",
    "invest in pre-deploy gates"
   ]
  },
  {
   "id": "dora-mttr",
   "name": "Mean time to restore",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "How fast do we recover when it breaks?",
   "tools": [
    "PagerDuty analytics",
    "incident tooling"
   ],
   "notes": "Measured monthly as a trend, even though each incident resolves in hours.",
   "framework": "DORA",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "hours to restore"
   ],
   "balancedBy": [
    "dora-deploy-freq"
   ],
   "actions": [
    "invest in rollback tooling",
    "run recovery drills"
   ]
  },
  {
   "id": "task-cycle-time",
   "name": "Task cycle time",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How long does work-in-progress stay in progress?",
   "tools": [
    "Jira/Linear analytics",
    "cumulative flow"
   ],
   "notes": "Idea-to-done for a unit of work. Pre-PMF it's your iteration speed. Slow cycle time throttles learning. Later it also catches queueing and handoff waste that PR cycle time misses.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "days"
   ]
  },
  {
   "id": "wip",
   "name": "WIP",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How much work is in flight right now?",
   "tools": [
    "board WIP limits",
    "cumulative flow diagram"
   ],
   "notes": "The control knob for the whole flow system. Little's Law says cycle time = WIP / throughput, so too much in flight slows everything. Doubles as an early warning of overcommitment and burnout.",
   "framework": "Kanban",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "task-cycle-time"
   ],
   "units": [
    "items in flight"
   ],
   "balancedBy": [
    "throughput"
   ],
   "actions": [
    "stop starting, start finishing"
   ]
  },
  {
   "id": "work-item-age",
   "name": "Work item age",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 86400,
    "typical": 259200,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Which in-progress items are going stale unnoticed?",
   "tools": [
    "aging WIP charts"
   ],
   "notes": "The complementary leading loop to cycle time. Cycle time tells you after an item finishes, age warns you while it can still be saved.",
   "framework": "Kanban",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "task-cycle-time"
   ],
   "units": [
    "days in progress"
   ],
   "actions": [
    "swarm the stale item",
    "split it or kill it"
   ]
  },
  {
   "id": "standup",
   "name": "Daily standup",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 14400,
    "typical": 86400,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is anyone blocked, and is today's plan still right?",
   "tools": [
    "daily standup",
    "async check-in bots"
   ],
   "notes": "The human sensor for aging work. A good standup notices a stuck ticket days before the metric does. Failure mode: status theatre, reporting to the manager instead of unblocking each other.",
   "framework": "Scrum",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "periodic",
   "latencyKind": "event",
   "proxyFor": [
    "work-item-age"
   ],
   "units": [
    "blockers surfaced"
   ],
   "actions": [
    "unblock now",
    "replan the day"
   ]
  },
  {
   "id": "throughput",
   "name": "Throughput",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "How many items actually finish per week?",
   "tools": [
    "items completed per period",
    "Monte Carlo forecasting"
   ],
   "notes": "The blunt counterpart to velocity, counts finished things, not estimated points.",
   "framework": "Kanban",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "items/wk"
   ],
   "balancedBy": [
    "wip",
    "bug-reports",
    "say-do-ratio"
   ]
  },
  {
   "id": "say-do-ratio",
   "name": "Sprint predictability (say:do ratio)",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 1210000,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Can we trust our own plans?",
   "tools": [
    "velocity vs commitment",
    "Jira sprint reports"
   ],
   "notes": "Sandbagging and story-point inflation both flatter this number while draining ambition, the Goodhart poster child of agile metrics. Throughput balances it by counting what actually finished.",
   "framework": "Scrum",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "dora-lead-time"
   ],
   "units": [
    "% of committed work delivered"
   ],
   "balancedBy": [
    "throughput"
   ],
   "actions": [
    "shrink the batch",
    "stop estimating, start counting"
   ]
  },
  {
   "id": "flow-efficiency",
   "name": "Flow efficiency",
   "track": "build",
   "layer": "Delivery flow",
   "latency": {
    "min": 1210000,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "How much of cycle time is work vs waiting?",
   "tools": [
    "touch time / total time",
    "blocked-time tracking"
   ],
   "notes": "Typically 15% or less. Most cycle time is queueing, which is why adding people rarely helps.",
   "framework": "Kanban",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% touch time"
   ]
  },
  {
   "id": "tech-debt",
   "name": "Tech debt accumulation",
   "track": "build",
   "layer": "Maintainability",
   "latency": {
    "min": 7900000,
    "typical": 31500000,
    "max": 94500000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is the codebase still an asset?",
   "tools": [
    "dev surveys",
    "velocity trends"
   ],
   "notes": "Noisy, contested, and usually noticed too late.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "aiAssisted": true,
   "units": [
    "survey score",
    "velocity trend"
   ],
   "actions": [
    "dedicate a capacity %",
    "decide: rewrite or strangle"
   ]
  },
  {
   "id": "feasibility-spike",
   "name": "Feasibility spike / throwaway prototype",
   "track": "build",
   "layer": "Feasibility",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "ic",
   "decision": "Can we even build this, for real?",
   "tools": [
    "spike branch",
    "proof-of-concept"
   ],
   "notes": "This is Cagan's feasibility risk, and the prototype is built to be thrown away.",
   "framework": "Cagan product risks",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "go / no-go"
   ]
  },
  {
   "id": "tech-evaluation",
   "name": "Technology / model evaluation",
   "track": "build",
   "layer": "Feasibility",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is this tech good enough to bet on?",
   "tools": [
    "eval harness",
    "vendor POC"
   ],
   "notes": "Feasibility for the AI era, does the model clear the bar before you commit?",
   "framework": "Cagan product risks",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "eval score vs bar"
   ]
  },
  {
   "id": "design-review",
   "name": "Design / RFC review",
   "track": "build",
   "layer": "Feasibility",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Will this design survive contact with other engineers?",
   "tools": [
    "RFCs / design docs",
    "ADRs",
    "architecture review"
   ],
   "notes": "The cheapest place to kill a bad architecture. The same flaw found by the capacity loop two years later costs a rewrite. Failure mode: rubber-stamp reviews that optimise for approval speed.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "capacity"
   ],
   "units": [
    "blocking comments resolved"
   ],
   "aiAssisted": true
  },
  {
   "id": "dbt-tests",
   "name": "Data quality tests",
   "track": "build",
   "layer": "Data",
   "latency": {
    "min": 60,
    "typical": 900,
    "max": 21600
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is the data still shaped the way downstream consumers assume?",
   "tools": [
    "dbt tests",
    "Great Expectations",
    "Elementary"
   ],
   "notes": "Unit tests for the warehouse, assertions that fail the pipeline before a bad number reaches a dashboard or a model.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "assertion failures"
   ]
  },
  {
   "id": "pipeline-freshness",
   "name": "Pipeline freshness / data SLAs",
   "track": "build",
   "layer": "Data",
   "latency": {
    "min": 300,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Did the data arrive on time, or are the dashboards stale and nobody's caught it?",
   "tools": [
    "Airflow / Dagster alerts",
    "dbt source freshness",
    "Monte Carlo"
   ],
   "notes": "Stale data fails silently. Decisions keep flowing off last week's numbers unless something watches arrival times.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "hours stale"
   ]
  },
  {
   "id": "data-anomaly",
   "name": "Data anomaly detection",
   "track": "build",
   "layer": "Data",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Did the data break in a way nobody thought to assert?",
   "tools": [
    "Monte Carlo",
    "Elementary",
    "row-count / distribution anomalies"
   ],
   "notes": "dbt tests catch what you asserted; this catches what you didn't, volume drops, distribution drift, silent nulls. The error monitoring of the data stack.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "anomalies flagged"
   ]
  },
  {
   "id": "ai-evals",
   "name": "Eval suite / golden-set regression",
   "track": "build",
   "layer": "AI & model",
   "latency": {
    "min": 120,
    "typical": 1800,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did this prompt or model change make the product dumber?",
   "tools": [
    "promptfoo",
    "Braintrust",
    "LangSmith"
   ],
   "notes": "The unit tests of AI behavior, run on every prompt tweak and model swap. Fidelity is capped by how well the golden set represents the wild.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "llm-judge"
   ],
   "units": [
    "% of golden set passed"
   ],
   "balancedBy": [
    "token-cost",
    "model-latency"
   ],
   "actions": [
    "block the change",
    "expand the golden set"
   ]
  },
  {
   "id": "llm-judge",
   "name": "LLM-as-judge scoring",
   "track": "build",
   "layer": "AI & model",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is production output quality drifting, at a scale no human can read?",
   "tools": [
    "LLM-as-judge pipelines",
    "Langfuse",
    "Braintrust"
   ],
   "notes": "A model grading a model, cheap enough to score everything, biased in ways you must periodically audit against human labels.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "ai-user-feedback"
   ],
   "units": [
    "judge score 1–5"
   ]
  },
  {
   "id": "ai-redteam",
   "name": "AI red-teaming / adversarial evals",
   "track": "build",
   "layer": "AI & model",
   "latency": {
    "min": 86400,
    "typical": 1210000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Can the model be made to do what it shouldn't?",
   "tools": [
    "prompt injection suites",
    "jailbreak evals",
    "manual red-teaming"
   ],
   "notes": "The pen test of the AI stack: evals measure whether the model is good, this measures whether it holds up. Injection via retrieved content is the finding that surprises everyone.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "successful attacks per suite"
   ],
   "aiAssisted": true
  },
  {
   "id": "token-cost",
   "name": "Token / cost per request",
   "track": "build",
   "layer": "AI & model",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did this change blow up the cost or context per task?",
   "tools": [
    "Helicone / Langfuse",
    "provider usage dashboards",
    "cost per trace"
   ],
   "notes": "The new unit economics. One prompt tweak can 10x COGS overnight. Watch cost per task, not the monthly bill.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "ai-spend"
   ],
   "units": [
    "$ per task",
    "tokens"
   ],
   "balancedBy": [
    "ai-evals"
   ],
   "actions": [
    "cache and truncate context",
    "route to a cheaper model"
   ]
  },
  {
   "id": "model-latency",
   "name": "Model latency / time-to-first-token",
   "track": "build",
   "layer": "AI & model",
   "latency": {
    "min": 60,
    "typical": 3600,
    "max": 86400
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "ic",
   "decision": "How long until the user sees the first token?",
   "tools": [
    "TTFT dashboards",
    "APM spans",
    "provider status"
   ],
   "notes": "Streaming hides total latency but not time-to-first-token. Part of it sits with the provider, not you.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "ms to first token"
   ],
   "balancedBy": [
    "ai-evals"
   ]
  },
  {
   "id": "model-drift",
   "name": "Model & output drift",
   "track": "build",
   "layer": "AI & model",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Has the upstream model or the user mix shifted under us?",
   "tools": [
    "canary prompts",
    "output distribution monitors",
    "Langfuse dashboards"
   ],
   "notes": "Providers swap weights behind stable API names; users drift too. Scheduled canary prompts catch what evals only catch on deploy.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "score drift"
   ],
   "actions": [
    "pin the model version",
    "refresh prompts and evals"
   ]
  },
  {
   "id": "dogfooding",
   "name": "Dogfooding",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Can we stand to use it ourselves?",
   "tools": [
    "internal releases"
   ],
   "notes": "Fast but biased. You are not your user.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "usability-tests"
   ],
   "units": [
    "internal complaints"
   ]
  },
  {
   "id": "beta-program",
   "name": "Beta / early-access program",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 259200,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "How does it fare with friendly outsiders before the real crowd?",
   "tools": [
    "early-access cohorts",
    "TestFlight",
    "design partners"
   ],
   "notes": "The rung between dogfooding and GA, users who forgive rough edges but aren't blinded by having built it.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "feature-adoption"
   ],
   "units": [
    "issues",
    "beta adoption %"
   ]
  },
  {
   "id": "sprint-review",
   "name": "Sprint review / stakeholder demo",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the increment what stakeholders actually wanted?",
   "tools": [
    "sprint reviews",
    "stakeholder demos"
   ],
   "notes": "The retro inspects the process; the review inspects the product. Stakeholders nod politely in demos. Acceptance here is not adoption.",
   "framework": "Scrum",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "periodic",
   "latencyKind": "event",
   "proxyFor": [
    "feature-adoption"
   ],
   "units": [
    "stakeholder acceptance"
   ]
  },
  {
   "id": "usability-tests",
   "name": "Usability tests",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Can people actually use it?",
   "tools": [
    "moderated sessions",
    "Maze"
   ],
   "notes": "Five users find most of the problems.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "issues per 5 users"
   ]
  },
  {
   "id": "task-success",
   "name": "Task success rate",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Can they finish the task at all?",
   "tools": [
    "moderated sessions",
    "Maze",
    "Lyssna"
   ],
   "notes": "Effectiveness, the headline usability number. Binary per user, brutal in aggregate.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "% completed"
   ],
   "balancedBy": [
    "time-on-task"
   ]
  },
  {
   "id": "first-click",
   "name": "First-click / findability",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Do they even know where to start?",
   "tools": [
    "tree testing (Treejack)",
    "first-click tests",
    "Maze / Lyssna"
   ],
   "notes": "A correct first click predicts ~87% task success vs. ~46% for a wrong one, the 'identify the task' signal.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "task-success"
   ],
   "units": [
    "% correct first click"
   ]
  },
  {
   "id": "interaction-cost",
   "name": "Clicks / interaction cost",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "How far do they wander off the ideal path?",
   "tools": [
    "path metrics (Maze / Lyssna)",
    "session replay",
    "analytics funnels"
   ],
   "notes": "Lostness: clicks taken vs. clicks needed. The raw 'number of clicks' made comparable across users.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "clicks vs ideal path"
   ]
  },
  {
   "id": "time-on-task",
   "name": "Time on task",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "How long does the task take?",
   "tools": [
    "moderated sessions",
    "session timers",
    "Maze / Lyssna"
   ],
   "notes": "Efficiency, noisy with small n; pair it with success rate or it misleads.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "minutes per task"
   ],
   "balancedBy": [
    "task-success"
   ]
  },
  {
   "id": "task-ease",
   "name": "Task ease (SEQ / SUS)",
   "track": "value",
   "layer": "Usability testing",
   "latency": {
    "min": 60,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "How hard did that feel?",
   "tools": [
    "Single Ease Question (SEQ)",
    "System Usability Scale (SUS)",
    "post-task survey"
   ],
   "notes": "Satisfaction. SEQ is one question the moment the task ends; SUS scores the whole system 0–100.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "SEQ 1–7",
    "SUS 0–100"
   ]
  },
  {
   "id": "session-recordings",
   "name": "Session recordings / rage clicks",
   "track": "value",
   "layer": "Usability signals",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Where do real users struggle?",
   "tools": [
    "FullStory",
    "Hotjar",
    "PostHog replays"
   ],
   "notes": "Qualitative signal at quantitative scale.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "rage clicks",
    "replays"
   ]
  },
  {
   "id": "funnel-analysis",
   "name": "Funnel / drop-off analysis",
   "track": "value",
   "layer": "Usability signals",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Where exactly do users abandon the flow?",
   "tools": [
    "Amplitude funnels",
    "GA4",
    "PostHog funnels"
   ],
   "notes": "A session recording shows one user struggling; the funnel shows the cliff a thousand walked off. The complementary aggregate loop to the recording.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "feature-adoption"
   ],
   "units": [
    "stage conversion %"
   ],
   "actions": [
    "redesign the cliff step",
    "remove a step entirely"
   ]
  },
  {
   "id": "ai-user-feedback",
   "name": "Thumbs up/down on AI output",
   "track": "value",
   "layer": "Usability signals",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Do users think the AI's answers are any good?",
   "tools": [
    "thumbs up/down",
    "regenerate rate",
    "edits to accepted output"
   ],
   "notes": "Sparse and polarized, but the only label stream that comes from the people you actually serve. Regenerates and abandoned sessions are the behavioural check on the thumbs.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "retention"
   ],
   "units": [
    "% thumbs-up",
    "regenerate %"
   ]
  },
  {
   "id": "ai-qual-synthesis",
   "name": "AI synthesis of qualitative streams",
   "track": "value",
   "layer": "Usability signals",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "What are thousands of tickets, calls and reviews saying this week?",
   "tools": [
    "LLM tagging / clustering",
    "Gong AI",
    "support copilots"
   ],
   "notes": "Compresses the slowest qualitative loops from months to days, the same tickets and calls, read by something that never gets bored.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "themes/wk"
   ]
  },
  {
   "id": "public-reviews",
   "name": "Public reviews (G2 / app stores / Reddit)",
   "track": "value",
   "layer": "Usability signals",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "What do people say about us where we can't moderate?",
   "tools": [
    "G2",
    "app store reviews",
    "Reddit / HN mentions"
   ],
   "notes": "Unsolicited, public, and permanent. Feedback that doubles as marketing or anti-marketing. Watch the complaints that repeat, not the star average.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "stars",
    "mentions"
   ]
  },
  {
   "id": "support-tickets",
   "name": "Support tickets",
   "track": "value",
   "layer": "Usability signals",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "What is confusing or broken in practice?",
   "tools": [
    "Zendesk",
    "Intercom"
   ],
   "notes": "Reveals doc gaps and silent feature failures too.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "tickets/wk"
   ]
  },
  {
   "id": "first-response-time",
   "name": "Time to first response",
   "track": "value",
   "layer": "Support ops",
   "latency": {
    "min": 3600,
    "typical": 14400,
    "max": 86400
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How quickly do customers hear a human?",
   "tools": [
    "Zendesk SLAs",
    "Intercom"
   ],
   "notes": "The fastest service loop, and the one customers judge you on before anything is even fixed.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "aiAssisted": true,
   "units": [
    "hours"
   ],
   "balancedBy": [
    "fcr"
   ]
  },
  {
   "id": "resolution-time",
   "name": "Resolution time",
   "track": "value",
   "layer": "Support ops",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "How long until the problem is actually solved?",
   "tools": [
    "ticket analytics"
   ],
   "notes": "MTTR for customer pain rather than infrastructure.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "aiAssisted": true,
   "units": [
    "hours",
    "days"
   ],
   "balancedBy": [
    "ticket-csat"
   ]
  },
  {
   "id": "fcr",
   "name": "First contact resolution",
   "track": "value",
   "layer": "Support ops",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Do we fix it in one touch or bounce people around?",
   "tools": [
    "ticket reopens",
    "transfer tracking"
   ],
   "notes": "Low FCR is a process smell: knowledge gaps, bad tooling, or unclear ownership.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% resolved first touch"
   ],
   "balancedBy": [
    "first-response-time"
   ]
  },
  {
   "id": "ticket-csat",
   "name": "Ticket CSAT",
   "track": "value",
   "layer": "Support ops",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Was that interaction any good?",
   "tools": [
    "post-ticket surveys"
   ],
   "notes": "Response bias runs hot. Mostly the delighted and the furious answer.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% satisfied"
   ],
   "balancedBy": [
    "resolution-time"
   ]
  },
  {
   "id": "contact-rate",
   "name": "Contact rate / tickets per customer",
   "track": "value",
   "layer": "Support ops",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the product generating support burden?",
   "tools": [
    "ticket volume normalized by MAU"
   ],
   "notes": "Rising contact rate leads churn. The product is asking for help on customers' behalf.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "grr"
   ],
   "units": [
    "tickets per 100 customers"
   ],
   "actions": [
    "fix the top ticket driver",
    "add self-serve deflection"
   ]
  },
  {
   "id": "fake-door",
   "name": "Fake door / prototype tests",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does anyone want this before we build it?",
   "tools": [
    "landing page tests",
    "clickable prototypes"
   ],
   "notes": "Cheapest possible value signal, pre-build.",
   "stages": [
    "pre-pmf",
    "growth"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "feature-adoption"
   ],
   "units": [
    "% clicked",
    "signed up"
   ]
  },
  {
   "id": "pmf-survey",
   "name": "Sean Ellis PMF survey",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 259200,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "leadership",
   "decision": "How disappointed would users be if this disappeared?",
   "tools": [
    "40% very-disappointed threshold",
    "Superhuman PMF engine"
   ],
   "notes": "The canonical fast proxy for product-market fit, retention's answer, months earlier. The segment that says 'very disappointed' tells you who to build for.",
   "framework": "Sean Ellis",
   "stages": [
    "pre-pmf",
    "growth"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "retention"
   ],
   "units": [
    "% very disappointed"
   ],
   "actions": [
    "double down on the very-disappointed segment"
   ]
  },
  {
   "id": "wtp-research",
   "name": "Willingness-to-pay research",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "What would they actually pay, before we bet the pricing page on it?",
   "tools": [
    "Van Westendorp",
    "conjoint analysis",
    "pricing interviews"
   ],
   "notes": "The research loop underneath Pricing power. Stated willingness runs high, but the shape of the curve is real. Months faster than finding out at renewal.",
   "framework": "Van Westendorp",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "pricing-power"
   ],
   "units": [
    "acceptable price range"
   ]
  },
  {
   "id": "feature-requests",
   "name": "Feature request board / upvotes",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "What do engaged users think they want?",
   "tools": [
    "Canny",
    "Productboard",
    "GitHub issues"
   ],
   "notes": "A demand signal from the vocal minority. Treat votes as evidence of pain, not as a spec. The comments are worth more than the counts.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "aiAssisted": true,
   "units": [
    "votes"
   ]
  },
  {
   "id": "discovery-interviews",
   "name": "Weekly discovery interviews",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 259200,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "What problem are people actually hiring us for?",
   "tools": [
    "Teresa Torres' continuous discovery",
    "opportunity solution trees"
   ],
   "notes": "Torres' core move is compressing the value loop from quarterly research to weekly touchpoints.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "interviews/wk",
    "insights"
   ]
  },
  {
   "id": "kano-survey",
   "name": "Kano survey",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is this feature a must-have, a delighter, or indifferent?",
   "tools": [
    "functional/dysfunctional question pairs"
   ],
   "notes": "A survey instrument, not just a 2x2. Classifies features by how their presence and absence feel.",
   "framework": "Kano",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "category per feature"
   ]
  },
  {
   "id": "opportunity-scoring",
   "name": "Opportunity scoring (importance vs satisfaction)",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Which customer outcomes are important but badly served?",
   "tools": [
    "ODI surveys",
    "opportunity landscape"
   ],
   "notes": "In Ulwick's outcome-driven framing, underserved outcomes are where value hides.",
   "framework": "ODI",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "importance − satisfaction"
   ]
  },
  {
   "id": "feature-adoption",
   "name": "Feature adoption / activation",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Do people reach the value moment?",
   "tools": [
    "Amplitude",
    "PostHog",
    "GA"
   ],
   "notes": "Leading proxy for retention.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "retention"
   ],
   "units": [
    "% reaching value moment"
   ],
   "actions": [
    "improve discoverability",
    "move it into onboarding",
    "kill the feature"
   ]
  },
  {
   "id": "ab-tests",
   "name": "A/B experiments",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 5260000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Did this change move the outcome metric?",
   "tools": [
    "Statsig",
    "GrowthBook",
    "Optimizely"
   ],
   "notes": "High fidelity if powered properly; loop length set by traffic.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% lift (significant)"
   ],
   "balancedBy": [
    "retention"
   ],
   "actions": [
    "ship the winner",
    "kill the change",
    "iterate the hypothesis"
   ]
  },
  {
   "id": "nps-csat",
   "name": "NPS / CSAT",
   "track": "value",
   "layer": "Desirability",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How do people feel about us?",
   "tools": [
    "Delighted",
    "in-app surveys"
   ],
   "notes": "Popular, cheap, and noisy.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "retention"
   ],
   "units": [
    "NPS −100…100",
    "CSAT %"
   ],
   "balancedBy": [
    "gross-margin",
    "stickiness"
   ]
  },
  {
   "id": "retention",
   "name": "Retention curves",
   "track": "value",
   "layer": "Solves the problem",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Does it keep solving the problem?",
   "tools": [
    "cohort analysis"
   ],
   "notes": "You cannot read it faster than time passes. Use activation as the fast proxy.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "ltv"
   ],
   "units": [
    "% retained by cohort"
   ],
   "balancedBy": [
    "ab-tests",
    "trial-conversion"
   ],
   "actions": [
    "fix the leakiest cohort",
    "revisit the ICP"
   ]
  },
  {
   "id": "trial-conversion",
   "name": "Trial / freemium conversion",
   "track": "value",
   "layer": "Solves the problem",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Do free users become paying customers?",
   "tools": [
    "trial→paid dashboards",
    "PLG funnels"
   ],
   "notes": "The commercial moment of truth for product-led growth, value delivered but not yet paid for. Gaming it with pressure tactics shows up two quarters later in retention.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "arr-growth"
   ],
   "balancedBy": [
    "retention"
   ],
   "units": [
    "trial→paid %"
   ],
   "actions": [
    "tune paywall timing",
    "shorten path to the value moment",
    "requalify who gets a trial"
   ]
  },
  {
   "id": "stickiness",
   "name": "Stickiness (DAU/MAU)",
   "track": "value",
   "layer": "Solves the problem",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the product becoming a habit?",
   "tools": [
    "Amplitude",
    "Mixpanel",
    "DAU/MAU dashboards"
   ],
   "notes": "The fast proxy for retention, but only meaningful against the product's natural cadence. A payroll product at 20% DAU/MAU is a triumph; a social product at 20% is dying.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "retention"
   ],
   "units": [
    "DAU/MAU %"
   ],
   "balancedBy": [
    "nps-csat"
   ],
   "actions": [
    "build the habit hook",
    "re-check the product's natural cadence"
   ]
  },
  {
   "id": "churn-interviews",
   "name": "Churn interviews / exit surveys",
   "track": "value",
   "layer": "Solves the problem",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "Why did they actually leave?",
   "tools": [
    "cancellation-flow surveys",
    "churned-customer calls"
   ],
   "notes": "Win/loss analysis for the customers you already had. The cancel-flow survey lies less than you'd think; the call afterwards lies least.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "reasons coded"
   ],
   "actions": [
    "fix the top churn driver",
    "tighten targeting upstream"
   ]
  },
  {
   "id": "expansion",
   "name": "Expansion / referral revenue",
   "track": "value",
   "layer": "Solves the problem",
   "latency": {
    "min": 7900000,
    "typical": 15800000,
    "max": 31500000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is it valuable enough to buy more of?",
   "tools": [
    "NRR",
    "referral tracking"
   ],
   "notes": "The strongest value signal there is, and the slowest.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "NRR %"
   ],
   "balancedBy": [
    "grr"
   ]
  },
  {
   "id": "win-loss",
   "name": "Win/loss analysis",
   "track": "value",
   "layer": "Better than alternatives",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Why do we win and lose deals?",
   "tools": [
    "sales call reviews",
    "Gong"
   ],
   "notes": "Competitive truth from people who just made a real choice.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "win rate %",
    "reasons"
   ],
   "actions": [
    "arm sales against the top objection",
    "fix the losable reasons"
   ],
   "balancedBy": [
    "pricing-realization"
   ]
  },
  {
   "id": "ad-ctr",
   "name": "Paid ads CTR / CPA",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does this message pull this audience?",
   "tools": [
    "Google Ads",
    "Meta Ads"
   ],
   "notes": "The fastest reach loop, Weinberg's rational early choice for exactly this reason.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "roas"
   ],
   "units": [
    "CTR %",
    "$ CPA"
   ],
   "balancedBy": [
    "cvr"
   ]
  },
  {
   "id": "roas",
   "name": "ROAS / channel CAC",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is this channel economically viable?",
   "tools": [
    "attribution tooling"
   ],
   "notes": "Fidelity degrades as attribution gets murkier.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "ltv-cac"
   ],
   "units": [
    "return multiple"
   ],
   "actions": [
    "shift budget between channels",
    "kill the channel"
   ],
   "balancedBy": [
    "liquidation"
   ]
  },
  {
   "id": "liquidation",
   "name": "Ad-spend liquidation",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "leadership",
   "decision": "How fast does ad spend come back as cash?",
   "tools": [
    "blended spend vs revenue",
    "Shopify"
   ],
   "notes": "Cash-recovery speed, not profitability. 100%+ day-0 liquidation lets you recycle spend almost without limit; a slow liquidator funds the gap from its own pocket. Blended, it needs no attribution.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "ltv-cac"
   ],
   "units": [
    "% of spend recovered",
    "days to recoup"
   ],
   "balancedBy": [
    "roas"
   ]
  },
  {
   "id": "cpm-auction",
   "name": "CPM / auction pressure",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "What is the market charging us for attention?",
   "tools": [
    "Meta CPM",
    "TikTok CPM",
    "auction insights"
   ],
   "notes": "Market feedback, not just cost. Rising CPM means competition or a creative the auction dislikes.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "$ per 1k impressions"
   ]
  },
  {
   "id": "cpc",
   "name": "Cost per click (CPC)",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "What is the auction charging us per click?",
   "tools": [
    "Google Ads",
    "Meta Ads"
   ],
   "notes": "CPM divided by CTR. A rising CPC means attention got pricier or the creative stopped earning clicks. Cheap clicks are only cheap if they convert, so read it against CVR.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "roas"
   ],
   "units": [
    "$ per click"
   ],
   "balancedBy": [
    "cvr"
   ]
  },
  {
   "id": "cvr",
   "name": "Landing conversion rate (CVR)",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 86400,
    "typical": 259200,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does the click become a customer action?",
   "tools": [
    "pixel events",
    "GA4 funnels"
   ],
   "notes": "Separates ad problems from page problems; CTR without CVR is expensive applause.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "roas"
   ],
   "units": [
    "% of clicks converting"
   ],
   "balancedBy": [
    "ad-ctr",
    "cpc"
   ]
  },
  {
   "id": "quality-score",
   "name": "Quality / relevance score",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does the platform think this ad deserves cheap reach?",
   "tools": [
    "Google Ads quality score",
    "Meta relevance diagnostics"
   ],
   "notes": "The platform's own model grading you, a proxy loop for user response, machine-mediated.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "score 1–10"
   ]
  },
  {
   "id": "ad-fatigue",
   "name": "Frequency / creative fatigue",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 259200,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Has this creative worn out its audience?",
   "tools": [
    "frequency caps",
    "CTR decay by cohort"
   ],
   "notes": "Leading indicator of CPA rot; when it climbs, feed the machine new creative.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "frequency",
    "CTR decay"
   ],
   "actions": [
    "rotate creative",
    "expand the audience"
   ]
  },
  {
   "id": "lift-tests",
   "name": "Incrementality / lift tests",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 1209600,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Did the spend cause the revenue, or just claim it?",
   "tools": [
    "geo holdouts",
    "conversion lift studies"
   ],
   "notes": "The audit of every faster paid loop. Attribution flatters, holdouts tell the truth.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "incremental lift %"
   ]
  },
  {
   "id": "influencer-sponsorship",
   "name": "Influencer / sponsorship performance",
   "track": "reach",
   "layer": "Paid",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Did borrowed audiences convert to ours?",
   "tools": [
    "promo codes",
    "dedicated landing pages",
    "sponsor-read attribution"
   ],
   "notes": "Paid reach with a human face. Attribution is murkier than ads, trust transfer is stronger. Codes and dedicated URLs are the only meter you can trust.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "code redemptions",
    "CPA"
   ]
  },
  {
   "id": "last-click",
   "name": "Last-click attribution",
   "track": "reach",
   "layer": "Attribution",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Which channel touched them last?",
   "tools": [
    "GA4 default reports",
    "platform dashboards"
   ],
   "notes": "Fast, free, and systematically wrong. Over-credits bottom-funnel, erases everything that built the intent.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "lift-tests"
   ],
   "units": [
    "% credit by channel"
   ]
  },
  {
   "id": "mta",
   "name": "Multi-touch / data-driven attribution",
   "track": "reach",
   "layer": "Attribution",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "How should credit split across the journey?",
   "tools": [
    "GA4 DDA",
    "MTA platforms"
   ],
   "notes": "Better than last-click, but privacy changes (iOS, cookie loss) have blinded much of what it once saw.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "lift-tests"
   ],
   "units": [
    "% credit by touch"
   ]
  },
  {
   "id": "self-reported",
   "name": "Self-reported attribution",
   "track": "reach",
   "layer": "Attribution",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "lagging",
   "owner": "team",
   "decision": "Where do customers say they found us?",
   "tools": [
    "'How did you hear about us?' field"
   ],
   "notes": "Catches dark social and word of mouth that pixels can't see; biased by memory, candid about influence.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% by source"
   ]
  },
  {
   "id": "mmm",
   "name": "Marketing mix modeling",
   "track": "reach",
   "layer": "Attribution",
   "latency": {
    "min": 7900000,
    "typical": 15800000,
    "max": 31500000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How should budget split across all channels?",
   "tools": [
    "MMM (Robyn, Meridian)"
   ],
   "notes": "The slowest reach loop, statistical, assumption-heavy, but the only one that sees the whole board.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "units": [
    "$ effect per channel"
   ]
  },
  {
   "id": "email-delivered",
   "name": "Delivered / inbox placement",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 60,
    "typical": 900,
    "max": 14400
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did it even reach the inbox?",
   "tools": [
    "ESP delivery logs",
    "seed / inbox-placement tests"
   ],
   "notes": "Delivered isn't the same as inboxed. The spam folder counts as delivered.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% inboxed"
   ]
  },
  {
   "id": "email-bounce",
   "name": "Bounce rate",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 30,
    "typical": 600,
    "max": 172800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Are we mailing dead addresses?",
   "tools": [
    "ESP bounce logs",
    "list verification"
   ],
   "notes": "Hard bounces return in seconds; soft bounces retry over days.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% bounced"
   ]
  },
  {
   "id": "email-reputation",
   "name": "Sender reputation",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is our sender reputation healthy?",
   "tools": [
    "Postmaster Tools",
    "SNDS",
    "complaint feedback loops"
   ],
   "notes": "Reputation erodes or heals over days to weeks. Complaints are the real killer.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "reputation",
    "complaint %"
   ]
  },
  {
   "id": "email-reject-rate",
   "name": "Spam / reject rate",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 30,
    "typical": 300,
    "max": 3600
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Are mailboxes blocking this send?",
   "tools": [
    "Postmaster Tools",
    "SNDS",
    "complaint feedback loops"
   ],
   "notes": "Rejects and spam-folder placement show up within minutes, a hard signal a send is being filtered.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% rejected"
   ],
   "proxyFor": [
    "email-reputation"
   ]
  },
  {
   "id": "email-open",
   "name": "Open rate",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 300,
    "typical": 14400,
    "max": 259200
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did the subject line earn a look?",
   "tools": [
    "ESP open tracking"
   ],
   "notes": "Increasingly unreliable. Apple Mail Privacy Protection auto-fires opens and inflates the number.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% opened"
   ],
   "balancedBy": [
    "unsubscribe-rate"
   ]
  },
  {
   "id": "email-ctr",
   "name": "Click-through rate",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 300,
    "typical": 14400,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Did the content earn a click, not just a look?",
   "tools": [
    "ESP click tracking",
    "UTM links"
   ],
   "notes": "The email signal Apple didn't break. A click is intent in a way an auto-fired open never was.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% clicked"
   ]
  },
  {
   "id": "unsubscribe-rate",
   "name": "Unsubscribe / list churn",
   "track": "reach",
   "layer": "Email deliverability",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Are we burning the list to hit this month's number?",
   "tools": [
    "ESP unsubscribe reports",
    "net list growth"
   ],
   "notes": "Every send spends trust; unsubscribes are the receipt. Rising unsubs lead spam complaints, which lead reputation damage.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "email-reputation"
   ],
   "units": [
    "% per send"
   ],
   "balancedBy": [
    "email-open"
   ],
   "actions": [
    "cut send frequency",
    "resegment the list"
   ]
  },
  {
   "id": "outbound-replies",
   "name": "Cold outreach reply rates",
   "track": "reach",
   "layer": "Outbound",
   "latency": {
    "min": 86400,
    "typical": 259200,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Does the pitch resonate with this segment?",
   "tools": [
    "sequences",
    "reply tracking"
   ],
   "notes": "Cheap message-market fit signal.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "pipeline"
   ],
   "units": [
    "% replied"
   ],
   "actions": [
    "rewrite the pitch",
    "change the segment"
   ]
  },
  {
   "id": "pipeline",
   "name": "Meetings booked / pipeline",
   "track": "reach",
   "layer": "Outbound",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Is outbound converting to real demand?",
   "tools": [
    "CRM"
   ],
   "notes": "Leading indicator for revenue, lagging for messaging.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "arr-growth"
   ],
   "units": [
    "meetings",
    "$ pipeline"
   ],
   "balancedBy": [
    "stage-conversion"
   ]
  },
  {
   "id": "stage-conversion",
   "name": "Pipeline stage conversion",
   "track": "reach",
   "layer": "Outbound",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Where does the sales machine actually jam?",
   "tools": [
    "CRM stage reports",
    "demo→proposal→close rates"
   ],
   "notes": "Pipeline says how much is in the machine; win/loss says why deals die; this says where. The jam is usually one stage, and it's usually not the one sales says it is.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "% conversion by stage"
   ],
   "balancedBy": [
    "pipeline"
   ],
   "actions": [
    "fix the jam stage",
    "qualify harder upstream"
   ]
  },
  {
   "id": "sales-cycle",
   "name": "Sales cycle length",
   "track": "reach",
   "layer": "Outbound",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How long from first meeting to signature?",
   "tools": [
    "CRM stage timestamps"
   ],
   "notes": "The lead time of the revenue machine. Lengthening cycles are an early sign of weakening urgency, wrong ICP, or a new blocker in procurement.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "days to close"
   ]
  },
  {
   "id": "content-engagement",
   "name": "Content engagement",
   "track": "reach",
   "layer": "Content",
   "latency": {
    "min": 3600,
    "typical": 259200,
    "max": 1210000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does this topic and angle resonate?",
   "tools": [
    "shares",
    "comments",
    "time on page"
   ],
   "notes": "Fast but weakly correlated with buying intent.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "shares",
    "time on page"
   ]
  },
  {
   "id": "keyword-research",
   "name": "Keyword research (difficulty vs. potential)",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is this keyword worth targeting?",
   "tools": [
    "Ahrefs / Semrush Keywords Explorer",
    "Google Keyword Planner",
    "Search Console",
    "AlsoAsked"
   ],
   "notes": "A cheap forecast up front, but Google takes months to confirm the bet. Content's version of a feasibility spike.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "seo-rankings"
   ],
   "aiAssisted": true,
   "units": [
    "volume vs difficulty"
   ]
  },
  {
   "id": "technical-seo",
   "name": "Technical SEO / indexation",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Can Google even crawl and index us?",
   "tools": [
    "Search Console coverage",
    "Screaming Frog",
    "Sitebulb",
    "Ahrefs / Semrush site audit"
   ],
   "notes": "The precondition for everything else. An unindexed page can't rank at all.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "pages indexed"
   ]
  },
  {
   "id": "seo-rankings",
   "name": "Keyword rankings / SERP position",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Where do we actually rank for our targets?",
   "tools": [
    "rank tracker",
    "Search Console",
    "Ahrefs / Semrush / SE Ranking"
   ],
   "notes": "Daily numbers, monthly truth. The loop length belongs to Google, not you.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "organic-traffic"
   ],
   "units": [
    "SERP position"
   ],
   "actions": [
    "refresh the content",
    "build links",
    "target easier keywords"
   ]
  },
  {
   "id": "organic-traffic",
   "name": "Organic traffic & CTR",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 259200,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is search actually sending clicks?",
   "tools": [
    "Search Console",
    "GA4",
    "Plausible"
   ],
   "notes": "You can rank #3 and still get no clicks. The title and meta have to earn them.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "clicks",
    "CTR %"
   ]
  },
  {
   "id": "domain-authority",
   "name": "Domain authority / backlink profile",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 604800,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is our link authority growing?",
   "tools": [
    "Ahrefs DR / Moz DA",
    "Majestic",
    "referring-domain monitors"
   ],
   "notes": "It feeds rankings rather than reflecting them. Compounds slowly, decays if you stop earning links.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "seo-rankings"
   ],
   "units": [
    "DR/DA 0–100"
   ]
  },
  {
   "id": "content-decay",
   "name": "Content decay / refresh signal",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 2630000,
    "typical": 15800000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Which pages are slipping in traffic?",
   "tools": [
    "Search Console",
    "GA4",
    "Ahrefs / Semrush traffic trends"
   ],
   "notes": "Rankings rot silently. The fix is usually refreshing old winners, not writing new.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% traffic lost"
   ],
   "actions": [
    "refresh or consolidate",
    "redirect and prune"
   ]
  },
  {
   "id": "ai-search-visibility",
   "name": "AI search visibility (AEO / GEO)",
   "track": "reach",
   "layer": "SEO",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Do the answer engines mention us when buyers ask?",
   "tools": [
    "Profound",
    "share-of-model tracking",
    "LLM brand monitoring"
   ],
   "notes": "Search traffic is migrating into answers. Measurement is young and noisy, but being absent from the answer is a silent zero.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% of answers citing you"
   ]
  },
  {
   "id": "app-store-ratings",
   "name": "App store ratings & ASO",
   "track": "reach",
   "layer": "App stores",
   "latency": {
    "min": 86400,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Does the store surface us, and do the stars invite the tap?",
   "tools": [
    "App Store Connect",
    "Play Console",
    "ASO keyword tools"
   ],
   "notes": "SEO's mobile sibling loop, with ranking driven by ratings, retention and keyword relevance. The rating is a lagging echo of product quality that then leads installs.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "avg rating",
    "keyword rank"
   ],
   "actions": [
    "prompt ratings after value moments",
    "answer reviews",
    "fix the top-complained bug"
   ]
  },
  {
   "id": "social-views",
   "name": "Views / impressions",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 900,
    "typical": 21600,
    "max": 172800
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Did the algorithm pick this up?",
   "tools": [
    "TikTok analytics",
    "YouTube Studio",
    "IG insights"
   ],
   "notes": "The fastest reach signal that exists, and the noisiest. It shows distribution luck more than durable demand.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "views"
   ],
   "balancedBy": [
    "follows-per-view"
   ]
  },
  {
   "id": "social-hook",
   "name": "Hook rate / swipe-aways",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Do the first three seconds earn the next thirty?",
   "tools": [
    "3-sec retention",
    "swipe-away rate",
    "thumbstop"
   ],
   "notes": "The most actionable creative signal. It isolates the open from the content.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% past 3 seconds"
   ]
  },
  {
   "id": "social-retention",
   "name": "Audience retention / watch time",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Where exactly do people leave?",
   "tools": [
    "avg view duration",
    "retention curves",
    "watch time"
   ],
   "notes": "Second-by-second feedback on content quality; the closest thing organic has to a session recording.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% watched",
    "drop-off point"
   ]
  },
  {
   "id": "completion-rate",
   "name": "Completion / loop rate",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 3600,
    "typical": 43200,
    "max": 259200
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Do they watch to the end, or rewatch?",
   "tools": [
    "platform analytics",
    "average view duration",
    "loops / rewatches"
   ],
   "notes": "Completions and rewatches are the signal short-form algorithms reward hardest.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% completed",
    "rewatches"
   ]
  },
  {
   "id": "shares-saves",
   "name": "Shares & saves",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 259200
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "ic",
   "decision": "Is it worth passing on or keeping?",
   "tools": [
    "platform analytics",
    "shares",
    "saves / bookmarks"
   ],
   "notes": "The real currency of short-form distribution. Saves and shares outrank likes by a mile.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "shares",
    "saves"
   ]
  },
  {
   "id": "video-comments",
   "name": "Comments / audience conversation",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 900,
    "typical": 21600,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "What is the audience actually saying back?",
   "tools": [
    "comment sections",
    "pinned-comment replies",
    "comment sentiment"
   ],
   "notes": "The qualitative half of engagement. Comments tell you why the retention curve did what it did, and hand you the next video's hook. Replying early also feeds the algorithm.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "comments per video"
   ]
  },
  {
   "id": "follows-per-view",
   "name": "Follows-per-view",
   "track": "reach",
   "layer": "Short-form video",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Does a view convert into a follower?",
   "tools": [
    "platform analytics",
    "follows attributed to post"
   ],
   "notes": "Reach that doesn't convert to follows is rented attention, not a compounding audience.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "follows per 1k views"
   ],
   "balancedBy": [
    "social-views"
   ]
  },
  {
   "id": "social-engagement",
   "name": "Engagement rate",
   "track": "reach",
   "layer": "Organic social",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Does this provoke a response?",
   "tools": [
    "likes",
    "comments",
    "shares",
    "saves"
   ],
   "notes": "Comments and saves outweigh likes. Platforms rank by effortful signals.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "% engaged"
   ]
  },
  {
   "id": "social-comments",
   "name": "Comments & DMs",
   "track": "reach",
   "layer": "Organic social",
   "latency": {
    "min": 900,
    "typical": 21600,
    "max": 259200
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "What is the audience saying back, in words?",
   "tools": [
    "comment threads",
    "DM inbox",
    "social listening"
   ],
   "notes": "Engagement rate counts the conversation; reading it is a different loop. DMs are where the buying questions arrive.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "comments",
    "DMs"
   ]
  },
  {
   "id": "social-followers",
   "name": "Follower / subscriber growth",
   "track": "reach",
   "layer": "Organic social",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Are we compounding an audience or renting attention?",
   "tools": [
    "subs per video",
    "follower conversion"
   ],
   "notes": "The compounding metric. Views are the loop, followers are what the loop accumulates.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "net follows/mo"
   ]
  },
  {
   "id": "referral-k",
   "name": "Referral / K-factor",
   "track": "reach",
   "layer": "Viral / referral",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Does usage generate more usage?",
   "tools": [
    "invite tracking"
   ],
   "notes": "Compounding loops need cycles before the signal is real.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "K-factor"
   ]
  },
  {
   "id": "pr-press",
   "name": "PR / press coverage",
   "track": "reach",
   "layer": "Brand",
   "latency": {
    "min": 86400,
    "typical": 1210000,
    "max": 7900000
   },
   "fidelity": "low",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Does the story land with media?",
   "tools": [
    "coverage tracking"
   ],
   "notes": "Unpredictable timing, spiky signal.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "placements",
    "reach"
   ]
  },
  {
   "id": "partnerships",
   "name": "Partnership pipeline",
   "track": "reach",
   "layer": "Partnerships",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Can others distribute us?",
   "tools": [
    "co-sell tracking",
    "revenue attribution"
   ],
   "notes": "Slow to start, slow to stop.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "partner-sourced $"
   ]
  },
  {
   "id": "events-webinars",
   "name": "Events / webinar performance",
   "track": "reach",
   "layer": "Events",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Did showing up in person (or live) create pipeline?",
   "tools": [
    "registration / attendance",
    "pipeline sourced",
    "booth conversations"
   ],
   "notes": "Spiky, expensive, and hard to attribute, but the only channel where the market talks back in full sentences.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "attendance",
    "pipeline $"
   ]
  },
  {
   "id": "community-engagement",
   "name": "Community activity & sentiment",
   "track": "reach",
   "layer": "Community",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the community compounding or decaying?",
   "tools": [
    "Discord / Slack activity",
    "forum posts",
    "unprompted advocacy"
   ],
   "notes": "Slow to build, fast to read once it exists, the channel where users answer each other and tell you the truth in public.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "active members",
    "posts/wk"
   ]
  },
  {
   "id": "brand-recall",
   "name": "Brand awareness / recall",
   "track": "reach",
   "layer": "Brand",
   "latency": {
    "min": 7900000,
    "typical": 31500000,
    "max": 94500000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Do people think of us unprompted?",
   "tools": [
    "surveys",
    "share of voice"
   ],
   "notes": "Builds slowly, decays slowly. Parallelize brand bets to keep some signal flowing.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "% unaided recall"
   ]
  },
  {
   "id": "time-to-hire",
   "name": "Time-to-hire",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 1210000,
    "typical": 3600000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "How long from opening a role to a signed offer?",
   "tools": [
    "ATS funnel metrics",
    "stage conversion"
   ],
   "notes": "The recruitment loop's own cycle time. Slow hiring loops mean losing candidates to faster ones.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "days role → offer"
   ],
   "balancedBy": [
    "quality-of-hire"
   ]
  },
  {
   "id": "sourcing-response",
   "name": "Sourcing response rate",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 86400,
    "typical": 259200,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Does our pitch open doors with talent we want?",
   "tools": [
    "outreach reply rates",
    "ATS sourcing metrics"
   ],
   "notes": "Cold outreach reply rates for hiring, message-market fit where the market is candidates. Fast feedback on employer brand.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "offer-acceptance"
   ],
   "units": [
    "% replied"
   ]
  },
  {
   "id": "interview-signal",
   "name": "Interview signal",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 3600,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Will this person succeed here?",
   "tools": [
    "structured loops",
    "work samples"
   ],
   "notes": "Everyone's most confident low-fidelity loop.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "quality-of-hire"
   ],
   "units": [
    "hire / no-hire confidence"
   ]
  },
  {
   "id": "offer-acceptance",
   "name": "Offer acceptance rate",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is our pitch to talent working?",
   "tools": [
    "ATS metrics"
   ],
   "notes": "Market feedback on your employer brand and comp.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% accepted"
   ]
  },
  {
   "id": "comp-benchmarking",
   "name": "Compensation benchmarking",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 2630000,
    "typical": 15800000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Are we paying market before the market tells us?",
   "tools": [
    "Radford / Pave",
    "offer decline reasons"
   ],
   "notes": "Offer acceptance and attrition are the complementary lagging loops. By the time they move, you've been below market for a year.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "offer-acceptance",
    "attrition"
   ],
   "units": [
    "percentile vs market"
   ],
   "actions": [
    "adjust bands ahead of cycle",
    "target retention grants at flight risks"
   ]
  },
  {
   "id": "quality-of-hire",
   "name": "Quality of hire / ramp time",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 7900000,
    "typical": 15800000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Was the interview signal right?",
   "tools": [
    "ramp milestones",
    "manager review"
   ],
   "notes": "6–12 months to close the loop the interview opened.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "units": [
    "ramp months",
    "manager rating"
   ],
   "balancedBy": [
    "time-to-hire"
   ]
  },
  {
   "id": "onboarding-ramp",
   "name": "Onboarding ramp / time-to-first-commit",
   "track": "team",
   "layer": "Hiring",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the new hire reaching productive ground on schedule?",
   "tools": [
    "first PR merged",
    "30-60-90 milestones"
   ],
   "notes": "The fast proxy for quality-of-hire, and a test of your own onboarding, docs and dev environment as much as of the hire.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "quality-of-hire"
   ],
   "units": [
    "days to first PR"
   ]
  },
  {
   "id": "one-on-ones",
   "name": "1:1 sentiment",
   "track": "team",
   "layer": "Engagement",
   "latency": {
    "min": 259200,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "How is this person really doing?",
   "tools": [
    "weekly 1:1s"
   ],
   "notes": "The manager's fastest loop, and easy to over-read.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "proxyFor": [
    "attrition"
   ],
   "units": [
    "sentiment"
   ],
   "actions": [
    "adjust the load",
    "escalate support early"
   ]
  },
  {
   "id": "retros",
   "name": "Team retrospectives",
   "track": "team",
   "layer": "Engagement",
   "latency": {
    "min": 604800,
    "typical": 1210000,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Is our process helping or hurting?",
   "tools": [
    "sprint retros"
   ],
   "notes": "An integration test for the team, if run honestly.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "units": [
    "improvements shipped"
   ],
   "actions": [
    "pick one improvement and assign an owner"
   ]
  },
  {
   "id": "devex-survey",
   "name": "Developer experience survey",
   "track": "team",
   "layer": "Engagement",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "Where does the day-to-day work actually hurt?",
   "tools": [
    "DX",
    "SPACE framework",
    "internal DevEx surveys"
   ],
   "notes": "Tech debt measured from the inside. The people slowed down by it are the instrument. Quarterly signal for a problem you can fix weekly.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "tech-debt"
   ],
   "units": [
    "DevEx score"
   ]
  },
  {
   "id": "enps",
   "name": "eNPS / engagement surveys",
   "track": "team",
   "layer": "Engagement",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is morale trending?",
   "tools": [
    "CultureAmp",
    "Officevibe"
   ],
   "notes": "Quarterly cadence, survey-fatigue noise.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "attrition"
   ],
   "aiAssisted": true,
   "units": [
    "eNPS −100…100"
   ]
  },
  {
   "id": "pulse-surveys",
   "name": "Pulse surveys",
   "track": "team",
   "layer": "Engagement",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 1210000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "How is the team this week, not last quarter?",
   "tools": [
    "weekly pulse tools",
    "Officevibe",
    "Slack polls"
   ],
   "notes": "eNPS at a cadence that can still change the outcome. Two questions weekly beat forty questions quarterly. Survey fatigue is the failure mode.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "enps"
   ],
   "aiAssisted": true,
   "units": [
    "pulse score"
   ],
   "actions": [
    "act visibly on the top pain",
    "close the loop in public"
   ]
  },
  {
   "id": "attrition",
   "name": "Attrition / regretted departures",
   "track": "team",
   "layer": "Capacity",
   "latency": {
    "min": 7900000,
    "typical": 31500000,
    "max": 63000000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Did we lose people we needed?",
   "tools": [
    "exit interviews",
    "Glassdoor"
   ],
   "notes": "Unambiguous, and far too late.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "%",
    "regretted count"
   ],
   "actions": [
    "fix the systemic cause",
    "start succession planning"
   ]
  },
  {
   "id": "meeting-load",
   "name": "Meeting load / focus time",
   "track": "team",
   "layer": "Capacity",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Do makers still have time to make?",
   "tools": [
    "calendar analytics",
    "focus-time metrics"
   ],
   "notes": "Burnout's leading indicator hides in the calendar. Fully automated and almost never looked at.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "attrition"
   ],
   "units": [
    "focus hrs/wk"
   ]
  },
  {
   "id": "oncall-load",
   "name": "On-call load / pages per person",
   "track": "team",
   "layer": "Capacity",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "team",
   "decision": "Is the pager burning anyone out?",
   "tools": [
    "PagerDuty analytics",
    "pages per rotation",
    "night pages"
   ],
   "notes": "Reliability debt lands on people before it lands on dashboards. Night pages predict resignations.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "attrition"
   ],
   "units": [
    "pages per person/wk"
   ],
   "actions": [
    "fix the top alert sources",
    "grow the rotation"
   ]
  },
  {
   "id": "bus-factor",
   "name": "Bus factor / knowledge concentration",
   "track": "team",
   "layer": "Capacity",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "leadership",
   "decision": "What breaks if this one person leaves?",
   "tools": [
    "git ownership analysis",
    "CodeScene knowledge maps"
   ],
   "notes": "Git-derived like hotspots, but measuring fragility instead of cost: the files only one person has ever touched. Nobody runs this loop until the person resigns. The point is to run it before.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "% single-owner files"
   ],
   "actions": [
    "pair on single-owner areas",
    "write down the tribal knowledge"
   ]
  },
  {
   "id": "promo-readiness",
   "name": "Growth / promotion readiness",
   "track": "team",
   "layer": "Growth",
   "latency": {
    "min": 7900000,
    "typical": 15800000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Are people growing here?",
   "tools": [
    "career frameworks",
    "calibration"
   ],
   "notes": "Slow loop; skip-levels and skill-gap reviews are the faster proxies.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "promotions",
    "readiness"
   ]
  },
  {
   "id": "perf-reviews",
   "name": "Performance reviews / 360 feedback",
   "track": "team",
   "layer": "Growth",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is each person growing, stuck, or misplaced?",
   "tools": [
    "review cycles",
    "360 feedback",
    "calibration"
   ],
   "notes": "High ceremony, twice a year, and lossy. Nothing in a good review should be news if the 1:1 loop is working.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "units": [
    "ratings distribution"
   ]
  },
  {
   "id": "okr-checkins",
   "name": "OKR check-ins / goal scoring",
   "track": "team",
   "layer": "Alignment",
   "latency": {
    "min": 604800,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Are we progressing on what we said mattered, and were they the right goals?",
   "tools": [
    "quarterly OKRs",
    "weekly confidence check-ins"
   ],
   "notes": "Every other loop here is a sensor; this is where the org decides which sensors it steers by. Failure mode: set-and-forget, where grading day is the first time anyone looks.",
   "framework": "OKR",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "OKR score 0–1",
    "confidence"
   ],
   "actions": [
    "kill the stalled key result",
    "reallocate focus"
   ]
  },
  {
   "id": "burn-alerts",
   "name": "Cloud spend / burn alerts",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Are costs running away?",
   "tools": [
    "billing alerts",
    "FinOps dashboards"
   ],
   "notes": "One of the few fast loops in the risk track.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "event",
   "proxyFor": [
    "runway"
   ],
   "units": [
    "$/day vs budget"
   ],
   "actions": [
    "kill zombie infra",
    "rightsize instances"
   ]
  },
  {
   "id": "ai-spend",
   "name": "AI / inference spend",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is inference eating into gross margin off the radar?",
   "tools": [
    "provider billing alerts",
    "FinOps dashboards"
   ],
   "notes": "The line item that turns software margins into hardware margins. Its fast proxy is cost-per-request in Build.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "proxyFor": [
    "gross-margin"
   ],
   "units": [
    "$/mo",
    "% of COGS"
   ]
  },
  {
   "id": "runway",
   "name": "Runway / burn multiple",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How long can we keep playing?",
   "tools": [
    "finance reviews"
   ],
   "notes": "A readout of every other loop, and you still have to check it.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "months of cash"
   ],
   "balancedBy": [
    "arr-growth"
   ],
   "actions": [
    "cut burn",
    "raise",
    "grow into the gap"
   ]
  },
  {
   "id": "fundraising-feedback",
   "name": "Investor / fundraising feedback",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "low",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Does the capital market believe our story?",
   "tools": [
    "partner meetings",
    "term sheets",
    "pass notes"
   ],
   "notes": "Noisy and polite. Passes rarely say why. But a fundraise is the one time the market prices your whole strategy at once.",
   "stages": [
    "pre-pmf",
    "growth"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "term sheets",
    "passes"
   ]
  },
  {
   "id": "gross-margin",
   "name": "Gross margin",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Does each unit sold actually make money?",
   "tools": [
    "monthly close",
    "FinOps"
   ],
   "notes": "The ceiling on every other financial metric; software margins hide infra and support costs.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "%"
   ],
   "balancedBy": [
    "nps-csat"
   ]
  },
  {
   "id": "pricing-realization",
   "name": "Pricing realization / discount rate",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How much of list price do we actually collect?",
   "tools": [
    "CPQ reports",
    "discount approval logs"
   ],
   "notes": "The sales team's revealed opinion of your pricing power. Heavy discounting shows up here quarters before it shows up in gross margin.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "pricing-power"
   ],
   "units": [
    "% of list realized",
    "avg discount %"
   ],
   "balancedBy": [
    "win-loss"
   ],
   "actions": [
    "tighten discount approvals",
    "reprice the list"
   ]
  },
  {
   "id": "arr-growth",
   "name": "MRR / ARR growth",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is revenue compounding?",
   "tools": [
    "revenue dashboards"
   ],
   "notes": "The scoreboard everyone watches; explains nothing on its own.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "$ ARR",
    "% growth"
   ],
   "balancedBy": [
    "grr",
    "runway"
   ]
  },
  {
   "id": "grr",
   "name": "Revenue churn / GRR",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How much revenue leaks before expansion papers over it?",
   "tools": [
    "gross revenue retention"
   ],
   "notes": "GRR is the stricter number; NRR lets expansion hide a leaky bucket.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "% revenue retained"
   ],
   "balancedBy": [
    "arr-growth",
    "expansion",
    "pricing-power"
   ],
   "actions": [
    "fix the churn drivers",
    "invest in customer success"
   ]
  },
  {
   "id": "dso",
   "name": "Cash collection / DSO",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is billed revenue becoming actual cash?",
   "tools": [
    "days sales outstanding",
    "aging receivables"
   ],
   "notes": "Revenue is an opinion, cash is a fact. Rising DSO shortens runway while the ARR chart still smiles.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "runway"
   ],
   "units": [
    "days outstanding"
   ]
  },
  {
   "id": "budget-actuals",
   "name": "Budget vs actuals (monthly close)",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 7900000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Are we spending what we planned, where we planned?",
   "tools": [
    "monthly close",
    "headcount vs plan",
    "variance reports"
   ],
   "notes": "Runway says how long the money lasts; the close says where the plan is leaking. Headcount is the line item that matters. Most of the rest is rounding.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "proxyFor": [
    "runway"
   ],
   "units": [
    "% variance vs plan"
   ],
   "actions": [
    "reforecast",
    "freeze discretionary spend"
   ]
  },
  {
   "id": "forecast-accuracy",
   "name": "Revenue forecast accuracy",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "medium",
   "cost": "low",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Do our revenue forecasts mean anything?",
   "tools": [
    "forecast vs actual by quarter",
    "pipeline-weighted forecasts"
   ],
   "notes": "The say:do ratio of the revenue side. A forecast that is always wrong in the same direction is a negotiating position, not a forecast.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "forecast error %"
   ],
   "actions": [
    "recalibrate stage weights",
    "sandbag-proof the pipeline review"
   ]
  },
  {
   "id": "cash-forecast",
   "name": "13-week cash flow forecast",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 86400,
    "typical": 604800,
    "max": 2630000
   },
   "fidelity": "high",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Will the cash be there when the bills land?",
   "tools": [
    "rolling 13-week model"
   ],
   "notes": "DSO tells you receivables are slipping; this tells you whether payroll clears in week nine. Standard practice at scale, survival practice in a crunch.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "proxyFor": [
    "runway"
   ],
   "units": [
    "weeks of cover",
    "forecast vs actual"
   ]
  },
  {
   "id": "revenue-concentration",
   "name": "Revenue concentration",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "high",
   "cost": "low",
   "automation": "automated",
   "direction": "leading",
   "owner": "leadership",
   "decision": "How much of the company walks out if one logo does?",
   "tools": [
    "top-N customer share of ARR"
   ],
   "notes": "A single number that reprices every other metric. 40% in one account means their roadmap is your roadmap.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "% ARR in top 5"
   ]
  },
  {
   "id": "blended-cac",
   "name": "Blended CAC",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 15800000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "What does a customer actually cost, all-in?",
   "tools": [
    "S&M spend / new customers"
   ],
   "notes": "Channel CAC (in Reach) tells you where to spend; blended CAC tells you if the machine works.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "ltv-cac"
   ],
   "units": [
    "$ per customer"
   ]
  },
  {
   "id": "cac-payback",
   "name": "CAC payback period",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "How long until a customer repays their acquisition cost?",
   "tools": [
    "cohort payback curves"
   ],
   "notes": "A faster, less model-dependent proxy for LTV:CAC, often the better operating metric.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "proxyFor": [
    "ltv-cac"
   ],
   "units": [
    "months"
   ]
  },
  {
   "id": "ltv",
   "name": "LTV",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 7900000,
    "typical": 31500000,
    "max": 63000000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "What is a customer worth over their lifetime?",
   "tools": [
    "cohort LTV models"
   ],
   "notes": "A forecast dressed as a measurement, fidelity depends entirely on churn assumptions.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "$ lifetime value"
   ]
  },
  {
   "id": "ltv-cac",
   "name": "LTV:CAC ratio",
   "track": "risk",
   "layer": "Capital",
   "latency": {
    "min": 7900000,
    "typical": 31500000,
    "max": 63000000
   },
   "fidelity": "low",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Is the whole growth machine economically sound?",
   "tools": [
    "unit economics reviews"
   ],
   "notes": "The classic 3x rule of thumb; inherits the noise of both its inputs.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "trend",
   "units": [
    "ratio"
   ]
  },
  {
   "id": "platform-risk",
   "name": "Platform / API dependency changes",
   "track": "risk",
   "layer": "Platform",
   "latency": {
    "min": 86400,
    "typical": 2630000,
    "max": 31500000
   },
   "fidelity": "low",
   "cost": "medium",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Can a platform kill us by email?",
   "tools": [
    "changelog monitoring",
    "app store relations"
   ],
   "notes": "Most startups have no loop here until the late-night email arrives.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "units": [
    "breaking changes flagged"
   ]
  },
  {
   "id": "vendor-concentration",
   "name": "Vendor / provider concentration",
   "track": "risk",
   "layer": "Platform",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Which single supplier could take us down or reprice us?",
   "tools": [
    "dependency inventory",
    "provider reviews",
    "exit-cost estimates"
   ],
   "notes": "Platform risk's quieter sibling. You chose these dependencies. The AI era added a new one: a single model provider under everything.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "units": [
    "% spend per vendor"
   ]
  },
  {
   "id": "regulatory",
   "name": "Regulatory & legal signals",
   "track": "risk",
   "layer": "Compliance",
   "latency": {
    "min": 2630000,
    "typical": 15800000,
    "max": 63000000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Are we allowed to keep doing this?",
   "tools": [
    "counsel reviews",
    "policy tracking",
    "audits"
   ],
   "notes": "Ignored until crisis; loop length set by governments.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "open issues"
   ]
  },
  {
   "id": "compliance-audit",
   "name": "Compliance audits (SOC2 / ISO)",
   "track": "risk",
   "layer": "Compliance",
   "latency": {
    "min": 2630000,
    "typical": 7900000,
    "max": 31500000
   },
   "fidelity": "high",
   "cost": "high",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Can we prove we do what we claim?",
   "tools": [
    "SOC2 Type II",
    "ISO 27001",
    "continuous compliance monitors"
   ],
   "notes": "An annual exam with continuous homework. Compliance platforms turned a yearly panic into a standing loop, mostly.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "periodic",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "findings",
    "attestation"
   ]
  },
  {
   "id": "fraud-abuse",
   "name": "Fraud / abuse / chargeback rate",
   "track": "risk",
   "layer": "Trust & safety",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "medium",
   "cost": "medium",
   "automation": "automated",
   "direction": "lagging",
   "owner": "team",
   "decision": "Is someone exploiting the product faster than we notice?",
   "tools": [
    "chargeback monitoring",
    "abuse reports",
    "anomaly detection"
   ],
   "notes": "One of the few genuinely fast Risk loops, and one where slow response compounds: card networks, app stores and users all keep score.",
   "stages": [
    "growth",
    "scale"
   ],
   "delivery": "push",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "chargeback %",
    "abuse reports"
   ]
  },
  {
   "id": "competitor-launches",
   "name": "Competitor launches",
   "track": "risk",
   "layer": "Moat",
   "latency": {
    "min": 604800,
    "typical": 2630000,
    "max": 15800000
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "leadership",
   "decision": "Is our position eroding?",
   "tools": [
    "competitive intel",
    "teardowns"
   ],
   "notes": "Indirect feedback about your own strategy.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "event",
   "aiAssisted": true,
   "units": [
    "launches tracked"
   ]
  },
  {
   "id": "switching-costs",
   "name": "Churn by tenure / lock-in strength",
   "track": "risk",
   "layer": "Moat",
   "latency": {
    "min": 7900000,
    "typical": 31500000,
    "max": 94500000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "automated",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Do we keep winning once we've won?",
   "tools": [
    "cohort churn",
    "integration depth"
   ],
   "notes": "So slow it's closer to strategic radar than an operational loop.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "continuous",
   "latencyKind": "trend",
   "units": [
    "% churn by tenure"
   ]
  },
  {
   "id": "pricing-power",
   "name": "Pricing power",
   "track": "risk",
   "layer": "Moat",
   "latency": {
    "min": 15800000,
    "typical": 31500000,
    "max": 94500000
   },
   "fidelity": "medium",
   "cost": "high",
   "automation": "human",
   "direction": "lagging",
   "owner": "leadership",
   "decision": "Can we raise prices without losing customers?",
   "tools": [
    "price tests",
    "renewal negotiations"
   ],
   "notes": "The ultimate lagging indicator of brand and moat combined.",
   "stages": [
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "units": [
    "% increase held"
   ],
   "balancedBy": [
    "grr"
   ],
   "actions": [
    "raise prices",
    "add value before raising"
   ]
  },
  {
   "id": "premortems",
   "name": "Pre-mortems",
   "track": "risk",
   "layer": "Anticipatory",
   "latency": {
    "min": 3600,
    "typical": 86400,
    "max": 604800
   },
   "fidelity": "low",
   "cost": "low",
   "automation": "human",
   "direction": "leading",
   "owner": "team",
   "decision": "How might this fail before it does?",
   "tools": [
    "structured pre-mortem sessions"
   ],
   "notes": "Synthetic feedback from a hypothetical future, the weird one, and cheap.",
   "stages": [
    "pre-pmf",
    "growth",
    "scale"
   ],
   "delivery": "pull",
   "cadence": "on-demand",
   "latencyKind": "event",
   "proxyFor": [
    "postmortems"
   ],
   "aiAssisted": true,
   "units": [
    "risks surfaced"
   ]
  }
 ]
}