Inside the Trenches of CI/CD
Inside the Trenches of CI/CD
Stories, insights, and opinions from the team behind Mergify

∙
9 min
read
How We Turned Claude Into a Cross-System Support Investigator
Support triage at Mergify meant juggling Datadog, Sentry, PostgreSQL, Linear, and source code. We built a repo with MCP servers and Claude Code that investigates tickets in parallel — cutting triage from 15 minutes to under 5, with 75% first-pass accuracy.

Julian Maurin

∙
9 min
read
How We Turned Claude Into a Cross-System Support Investigator
Support triage at Mergify meant juggling Datadog, Sentry, PostgreSQL, Linear, and source code. We built a repo with MCP servers and Claude Code that investigates tickets in parallel — cutting triage from 15 minutes to under 5, with 75% first-pass accuracy.

Julian Maurin

∙
9 min
read
How We Turned Claude Into a Cross-System Support Investigator
Support triage at Mergify meant juggling Datadog, Sentry, PostgreSQL, Linear, and source code. We built a repo with MCP servers and Claude Code that investigates tickets in parallel — cutting triage from 15 minutes to under 5, with 75% first-pass accuracy.

Julian Maurin

∙
9 min
read
How We Turned Claude Into a Cross-System Support Investigator
Support triage at Mergify meant juggling Datadog, Sentry, PostgreSQL, Linear, and source code. We built a repo with MCP servers and Claude Code that investigates tickets in parallel — cutting triage from 15 minutes to under 5, with 75% first-pass accuracy.

Julian Maurin

∙
7 min
read
Spinners Are the UX Equivalent of “TODO: Fix Later”
We replaced a spinner with a chart-shaped skeleton and realized loading states are part of the layout contract. Bad skeletons cause layout shift. Good ones match the final UI exactly. Here's what we learned fixing ours — and why CLS is a UX problem, not just an SEO metric.

Alexandre Gaubert

∙
7 min
read
Spinners Are the UX Equivalent of “TODO: Fix Later”
We replaced a spinner with a chart-shaped skeleton and realized loading states are part of the layout contract. Bad skeletons cause layout shift. Good ones match the final UI exactly. Here's what we learned fixing ours — and why CLS is a UX problem, not just an SEO metric.

Alexandre Gaubert

∙
7 min
read
Spinners Are the UX Equivalent of “TODO: Fix Later”
We replaced a spinner with a chart-shaped skeleton and realized loading states are part of the layout contract. Bad skeletons cause layout shift. Good ones match the final UI exactly. Here's what we learned fixing ours — and why CLS is a UX problem, not just an SEO metric.

Alexandre Gaubert

∙
7 min
read
Spinners Are the UX Equivalent of “TODO: Fix Later”
We replaced a spinner with a chart-shaped skeleton and realized loading states are part of the layout contract. Bad skeletons cause layout shift. Good ones match the final UI exactly. Here's what we learned fixing ours — and why CLS is a UX problem, not just an SEO metric.

Alexandre Gaubert

∙
4 min
read
On LATERAL Joins
Our new API endpoint worked in dev but timed out in production. A naive SQL subquery was scanning 660K rows to return 50. Switching to LATERAL JOIN cut response time by 1000x. Here's how join order can make or break your PostgreSQL queries.

Rémy Duthu

∙
4 min
read
On LATERAL Joins
Our new API endpoint worked in dev but timed out in production. A naive SQL subquery was scanning 660K rows to return 50. Switching to LATERAL JOIN cut response time by 1000x. Here's how join order can make or break your PostgreSQL queries.

Rémy Duthu

∙
4 min
read
On LATERAL Joins
Our new API endpoint worked in dev but timed out in production. A naive SQL subquery was scanning 660K rows to return 50. Switching to LATERAL JOIN cut response time by 1000x. Here's how join order can make or break your PostgreSQL queries.

Rémy Duthu

∙
4 min
read
On LATERAL Joins
Our new API endpoint worked in dev but timed out in production. A naive SQL subquery was scanning 660K rows to return 50. Switching to LATERAL JOIN cut response time by 1000x. Here's how join order can make or break your PostgreSQL queries.

Rémy Duthu

∙
5 min
read
Detecting Blocking Tasks in Asyncio by Measuring Event Loop Latency
Asyncio only works if every coroutine cooperates. One blocking call can freeze your entire app. This post shows a simple watchdog coroutine that measures event loop latency, detects blocking tasks early, and turns invisible stalls into actionable metrics.

Mehdi Abaakouk

∙
5 min
read
Detecting Blocking Tasks in Asyncio by Measuring Event Loop Latency
Asyncio only works if every coroutine cooperates. One blocking call can freeze your entire app. This post shows a simple watchdog coroutine that measures event loop latency, detects blocking tasks early, and turns invisible stalls into actionable metrics.

Mehdi Abaakouk

∙
5 min
read
Detecting Blocking Tasks in Asyncio by Measuring Event Loop Latency
Asyncio only works if every coroutine cooperates. One blocking call can freeze your entire app. This post shows a simple watchdog coroutine that measures event loop latency, detects blocking tasks early, and turns invisible stalls into actionable metrics.

Mehdi Abaakouk

∙
5 min
read
Detecting Blocking Tasks in Asyncio by Measuring Event Loop Latency
Asyncio only works if every coroutine cooperates. One blocking call can freeze your entire app. This post shows a simple watchdog coroutine that measures event loop latency, detects blocking tasks early, and turns invisible stalls into actionable metrics.

Mehdi Abaakouk

∙
5 min
read
GitHub Merge Queue Was Step One. Real CI Orchestration Comes Next.
GitHub’s merge queue solved safety, not scale. As CI grows slower, costlier, and shared across teams, merging becomes a scheduling problem. Learn why large monorepos and Bazel users outgrow native queues and what real CI orchestration looks like.

Julien Danjou

∙
5 min
read
GitHub Merge Queue Was Step One. Real CI Orchestration Comes Next.
GitHub’s merge queue solved safety, not scale. As CI grows slower, costlier, and shared across teams, merging becomes a scheduling problem. Learn why large monorepos and Bazel users outgrow native queues and what real CI orchestration looks like.

Julien Danjou

∙
5 min
read
GitHub Merge Queue Was Step One. Real CI Orchestration Comes Next.
GitHub’s merge queue solved safety, not scale. As CI grows slower, costlier, and shared across teams, merging becomes a scheduling problem. Learn why large monorepos and Bazel users outgrow native queues and what real CI orchestration looks like.

Julien Danjou

∙
5 min
read
GitHub Merge Queue Was Step One. Real CI Orchestration Comes Next.
GitHub’s merge queue solved safety, not scale. As CI grows slower, costlier, and shared across teams, merging becomes a scheduling problem. Learn why large monorepos and Bazel users outgrow native queues and what real CI orchestration looks like.

Julien Danjou

∙
5 min
read
Stop Lying to Your Dependency Resolver: The Real Rules for Python Dependency Management
Your Python app didn’t change: your dependencies did. This post explains why apps must pin dependencies, libraries must declare ranges, dev tools must be locked, and how to use lockfiles correctly with Poetry, PDM, and uv to avoid CI and production surprises.

Mehdi Abaakouk

∙
5 min
read
Stop Lying to Your Dependency Resolver: The Real Rules for Python Dependency Management
Your Python app didn’t change: your dependencies did. This post explains why apps must pin dependencies, libraries must declare ranges, dev tools must be locked, and how to use lockfiles correctly with Poetry, PDM, and uv to avoid CI and production surprises.

Mehdi Abaakouk

∙
5 min
read
Stop Lying to Your Dependency Resolver: The Real Rules for Python Dependency Management
Your Python app didn’t change: your dependencies did. This post explains why apps must pin dependencies, libraries must declare ranges, dev tools must be locked, and how to use lockfiles correctly with Poetry, PDM, and uv to avoid CI and production surprises.

Mehdi Abaakouk

∙
5 min
read
Stop Lying to Your Dependency Resolver: The Real Rules for Python Dependency Management
Your Python app didn’t change: your dependencies did. This post explains why apps must pin dependencies, libraries must declare ranges, dev tools must be locked, and how to use lockfiles correctly with Poetry, PDM, and uv to avoid CI and production surprises.

Mehdi Abaakouk

∙
9 min
read
Lessons From a Noisy Monitor
Your database monitors keep firing even though nothing is wrong? We hit the same problem: noisy IOPS alerts caused by predictable jobs. This post explains how we replaced brittle thresholds with an SLO-based approach that restored signal, eliminated noise, and stopped the monitor from "crying wolf."

Julian Maurin

∙
9 min
read
Lessons From a Noisy Monitor
Your database monitors keep firing even though nothing is wrong? We hit the same problem: noisy IOPS alerts caused by predictable jobs. This post explains how we replaced brittle thresholds with an SLO-based approach that restored signal, eliminated noise, and stopped the monitor from "crying wolf."

Julian Maurin

∙
9 min
read
Lessons From a Noisy Monitor
Your database monitors keep firing even though nothing is wrong? We hit the same problem: noisy IOPS alerts caused by predictable jobs. This post explains how we replaced brittle thresholds with an SLO-based approach that restored signal, eliminated noise, and stopped the monitor from "crying wolf."

Julian Maurin

∙
9 min
read
Lessons From a Noisy Monitor
Your database monitors keep firing even though nothing is wrong? We hit the same problem: noisy IOPS alerts caused by predictable jobs. This post explains how we replaced brittle thresholds with an SLO-based approach that restored signal, eliminated noise, and stopped the monitor from "crying wolf."

Julian Maurin

∙
7 min
read
await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks
Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

∙
7 min
read
await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks
Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

∙
7 min
read
await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks
Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

∙
7 min
read
await Is Not a Context Switch: Understanding Python's Coroutines vs Tasks
Python’s async model is misunderstood, especially by engineers coming from JS or C#. In Python, awaiting a coroutine doesn’t yield to the event loop. Only tasks create concurrency. This post explains why that distinction matters and how it affects locking, design, and correctness.

Mehdi Abaakouk

∙
4 min
read
Updating Materialized Views (Without Worrying Too Much)
Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

∙
4 min
read
Updating Materialized Views (Without Worrying Too Much)
Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

∙
4 min
read
Updating Materialized Views (Without Worrying Too Much)
Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu

∙
4 min
read
Updating Materialized Views (Without Worrying Too Much)
Materialized views are powerful but painful to change. Here’s how we safely version, refresh, and migrate them without locking production or timing out deployments, plus the approach we use to avoid dangerous DROP/CREATE migrations.

Rémy Duthu
Join our community on Slack
Join our community on Slack
Get tips, news, and resources from Mergify and its users.
Curious where your CI is slowing you down?
Try CI Insights — observability for CI teams.
Curious where your CI is slowing you down?
Try CI Insights — observability for CI teams.
Curious where your CI is slowing you down?
Try CI Insights — observability for CI teams.
Curious where your CI is slowing you down?
Try CI Insights — observability for CI teams.