~ / case-studies

Four engagements, measured

Client names are anonymised at their request; the numbers are not. Every figure below comes from the client's own Grafana or billing export, comparing thirty days before cutover with ninety days after. Where a metric got worse, we have said so.

Case 01 · Fintech — card payments

Single-region monolith to active/active in 14 weeks

Night-side view of Earth from orbit, city lights marking two continents on either side of an ocean. eu-west-1 us-east-1 · cell-based routing, 90-second promotion

The situation

A European payments processor handling roughly 40 million card authorisations a month, all of it served from a single region by a Rails monolith with a 900GB Postgres instance behind it. Checkout p99 sat at 340ms and the business had committed to a payment scheme SLA of 99.95% availability with a documented regional failover — which they could not demonstrate. Their tested failover was a 42-minute manual restore from snapshot.

The forcing function was regulatory: an operational resilience assessment gave them two quarters to prove a regional outage would not take the service down.

What we did

  1. Split the write path from the read path first. Authorisation is synchronous and must stay strongly consistent; settlement, reporting and webhook delivery do not. Moving those three into an event-driven pipeline took 61% of the load off the primary before any migration started.
  2. Cell-based routing. Rather than replicating everything everywhere, merchants were sharded into cells pinned to a home region, with the second region holding a warm promotable replica per cell. Failover moves cells, not the entire estate, so blast radius is bounded.
  3. Kubernetes with strict tenancy. Three-AZ EKS in each region, Karpenter for capacity, on-demand floor for the authorisation path and spot for settlement workers. Gateway API at the edge with per-merchant rate limiting.
  4. Latency work driven by profiles, not guesses. Continuous profiling identified two N+1 query patterns and a JSON serialisation hotspot responsible for 210ms of the p99 on its own. Connection pooling via PgBouncer in transaction mode removed another 60ms of queueing under peak.
  5. Failover as a drill, not a document. Region promotion is now a single ArgoCD-driven procedure, rehearsed quarterly against production with the regulator's assessor invited to watch the last one.
Engagement
Sector
Payments / regulated fintech
Scale
40M auths/month, 900GB primary
Duration
14 weeks build + 6 weeks migrate
Team
1 principal, 3 engineers
Model
Build & migrate, milestone-based
Stack
EKS · Aurora · Kafka · Envoy · ArgoCD
failover drill — 2026-Q2log
# regulator-witnessed promotion
t+00s  health check fails eu-west-1
t+11s  edge drains region, TTL 10s
t+26s  consensus lease acquired
t+48s  replica promoted, WAL replayed
t+71s  writes accepted us-east-1
t+90s  all SLIs green
# 4 auths failed, all retried by scheme

Before / after

MetricBeforeAfter (90d)DeltaHow measured
Checkout p99 latency340 ms45 ms−86.8%edge histogram, 1m buckets
Checkout p50 latency86 ms19 ms−77.9%edge histogram
Regional failover time42 min90 s−96.4%quarterly drill, wall clock
Availability (rolling 30d)99.87%99.982%−86% error ratesuccessful auth ratio at edge
Deploy frequency4 / month124 / month×31ArgoCD sync events
Primary DB write load100%39%−61%pg_stat, peak hour
Infrastructure cost$214k / mo$248k / mo+15.9%two regions — deliberate trade
↔ scroll table horizontally

"The number that mattered to our board was 90 seconds. The number that mattered to our engineers was that nobody had to be awake for it."

— VP Engineering, payments processor

Case 02 · B2B SaaS — product analytics

$2.1M off the annual cloud bill, SLOs untouched

Wireframe cubes suspended in a dark isometric lattice, standing in for a bin-packed compute fleet. 1,900 → 610 nodes · consolidation on, 68% commitment coverage

The situation

An analytics platform ingesting about 14 billion events a month, running 1,900 nodes across four clusters. Cloud spend had grown 3.4× in eighteen months against 1.9× revenue growth, and the CFO had asked engineering for a number they could not produce: what does one customer cost to serve.

Fleet-wide CPU utilisation was 19%. The team had already bought three-year reserved instances against that inflated baseline, which is the expensive version of this mistake.

What we did

  1. Made cost observable before changing anything. OpenCost attributing node-hours to namespaces, joined to the billing export and divided by ingested events. Four weeks later every team could see cost per million events on the same dashboard as their latency.
  2. Deleted waste. 31 orphaned volumes, 218 unattached IPs, a staging estate running 24/7 at 4% utilisation, and $19k a month of cross-AZ traffic caused by a service that had no topology-aware routing.
  3. Rightsized from observed p95, one PR per namespace. Requests had been copied between services for years. Vertical Pod Autoscaler in recommendation mode gave the numbers; we shipped them incrementally with SLO monitoring on each merge.
  4. Restructured the compute. Stateless tiers moved to Graviton (22% cheaper per vCPU for this workload), the entire batch ETL tier moved to diversified spot with checkpointing, and Karpenter consolidation replaced the static autoscaling groups.
  5. Re-modelled commitments last. Coverage was rebuilt against the new, smaller baseline with a deliberate 68% target rather than 100%, leaving headroom for the next architecture change.
Engagement
Sector
B2B SaaS, product analytics
Scale
14B events/mo, 4 clusters
Duration
4 weeks audit + 8 weeks execution
Team
1 principal, 2 engineers
Model
Share of verified year-one savings
Stack
EKS · Kafka · ClickHouse · S3
$500k $250k 0 $462k $287k WEEK 0 WEEK 12 monthly run rate, all-in

Before / after

MetricBeforeAfter (90d)DeltaHow measured
Monthly cloud spend$462,000$287,000−37.9%billing export, all accounts
Annualised saving$2.10Mverified12-month run-rate delta
Node count1,900610−67.9%peak-hour fleet size
Fleet CPU utilisation19%64%+237%requested vs used, p95
Cost per 1M events$33.00$20.50−37.9%OpenCost ÷ ingest counter
Cross-AZ data transfer$19,400/mo$2,100/mo−89.2%topology-aware routing
Ingest p99 latency240 ms238 msno changeSLO held throughout
Batch job duration p9531 min38 min+22.6%spot interruptions — within window
↔ scroll table horizontally
Case 03 · Marketplace — logistics

From 6 releases a month to 40 deploys a day

Source code on a dark monitor, photographed at a shallow angle so the lines recede into the frame. trunk → canary → prod · merge queue, 26-minute lead time

The situation

A logistics marketplace with 74 services, 180 engineers and a release train that left once a fortnight. The pipeline was a Jenkins install nobody wanted to touch: 4 hours 20 minutes end to end, a manual QA gate, and a separate build per environment — meaning the artifact tested in staging was never the artifact that reached production.

Change failure rate was 18%. Because releases were batched, every failure required bisecting a fortnight of merged work under incident pressure. Mean time to restore was three hours, most of which was identifying what had shipped.

What we did

  1. One artifact, promoted by digest. Build once in CI with an SBOM and a cosign signature; every environment deploys the same @sha256: reference. Environment config moved to Kustomize overlays.
  2. Change detection in the monorepo. A dependency graph so that touching the shipping package builds three services, not seventy-four. Combined with a remote build cache this took the median pipeline from 4h20 to 11 minutes.
  3. Replaced the QA gate with canary analysis. Argo Rollouts shifts 5% of traffic and queries Prometheus for error rate, p99 latency and saturation against the stable subset. It aborts on its own. Humans review the diff, not the deploy.
  4. Merge queue and trunk-based development. No long-lived branches, required checks defined in code, and a queue that rebases and re-tests before landing so main is always releasable.
  5. Deployment events as first-class telemetry. Every rollout emits an annotation into Grafana, so the first question in an incident — "what changed" — is answered by looking at the same graph as the symptom.
Engagement
Sector
Marketplace / logistics
Scale
74 services, 180 engineers
Duration
9 weeks
Team
1 principal, 2 engineers
Model
Build, milestone-based
Stack
GitHub Actions · ArgoCD · GKE
dora — trailing 90d
deploy freq     40.2/day  elite
lead time       26 min    elite
change fail     2.1%      elite
MTTR            7m 12s    elite
───────────────────────────
rollbacks       3 (auto: 3)
manual gates    0

Before / after

MetricBeforeAfter (90d)DeltaHow measured
Deploy frequency6 / month40.2 / day×201ArgoCD sync events
Lead time for change11 days26 min−99.8%first commit → prod traffic
Pipeline duration (median)4h 20m11 min−95.8%CI wall clock, monorepo
Change failure rate18%2.1%−88.3%rollbacks ÷ deploys
MTTR3h 04m7m 12s−96.1%sev-1 and sev-2 incidents
Manual approval gates30removedpolicy replaces sign-off
CI compute spend$28,600/mo$9,400/mo−67.1%cache hits + change detection
↔ scroll table horizontally
Case 04 · Healthtech — regulated

Three observability vendors down to one pipeline

Operators silhouetted against a wall of monitors in a darkened network operations centre. one OTLP pipeline · metrics, logs, traces and profiles on one clock

The situation

A clinical scheduling platform operating under HIPAA and NHS DSPT, with 210 services split across two clouds after an acquisition. Telemetry had accumulated rather than been designed: one vendor for APM, another for logs, Prometheus for infrastructure metrics, and no correlation between any of them.

Observability spend was $71,000 a month and rising faster than compute. During incidents engineers had four tabs open and were manually matching timestamps. Median time to identify a failing dependency was 41 minutes.

A complication: patient identifiers were appearing in application logs, which made the log estate a compliance liability as well as a cost problem.

What we did

  1. OTLP as the only wire format. Applications emit OpenTelemetry; collectors handle enrichment, redaction and routing. Backends became replaceable — which is how we could change them without touching 210 services.
  2. Redaction at the collector, not in the app. A processor strips identifiers matching known patient-identifier patterns before anything leaves the cluster, with a deny-by-default attribute allowlist for tier-0 clinical services. This removed the compliance finding in week three.
  3. Tail sampling instead of head sampling. Every error and every span slower than the SLO is kept; 2% of the healthy remainder is retained for baselines. Trace volume dropped 94% while the traces engineers actually open went up.
  4. Exemplars everywhere. Metrics carry trace IDs, so a latency spike on a dashboard is one click from the offending span, and that span carries the log correlation ID. Four tabs became one.
  5. eBPF for what could not be instrumented. Eleven vendor-supplied images and a legacy Java service nobody could rebuild got golden signals without a single code change.
Engagement
Sector
Healthtech, HIPAA + DSPT
Scale
210 services, 2 clouds
Duration
11 weeks
Team
1 principal, 2 engineers
Model
Build & enable
Stack
OTel · Mimir · Loki · Tempo · Cilium
redaction.processor.yamlyaml
processors:
  transform/phi:
    log_statements:
      - context: log
        statements:
          - replace_pattern(body,
              "\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b",
              "[REDACTED-SSN]")
          - replace_pattern(body,
              "\\bNHS[0-9]{10}\\b",
              "[REDACTED-NHS]")
  attributes/allowlist:
    actions:
      - { key: patient.*, action: delete }

Before / after

MetricBeforeAfter (90d)DeltaHow measured
Observability spend$71,000/mo$31,800/mo−55.2%3 vendor invoices → 1 self-hosted
Time to identify (TTI)41 min6 min−85.4%incident timeline, median
MTTR2h 51m11 min−93.6%sev-1 and sev-2
Trace volume stored4.1 TB/day240 GB/day−94.1%tail sampling
Error traces retained~8% (head)100%completestatus_code policy
Metric retention15 days400 days×26.7Mimir on object storage
PHI in log estatepresent0 findingsresolvedquarterly scan, 2 cycles clean
Services instrumented148 / 210210 / 210100%62 via eBPF, no code change
↔ scroll table horizontally
gw review --schedule

Your numbers are probably worse than you think

Most teams have never measured their change failure rate or their cost per request. The architecture review starts by establishing those, because you cannot improve a number you have not written down.