agentleFS
sriptcollectorsriptcollector/toolbay-skills/skills/dependency-outage-audit/SKILL.md

dependency-outage-audit

Skill0 starsChanged 4 months agoMITView on GitHub

Find which pages die when a dependency dies — database, cache, or upstream API — and which ones lie about it by returning HTTP 200 with an empty body. Use before a launch, after an incident, when adding a page that fetches data, or when the user asks how their app behaves if the database goes down.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If you serve stale or partial data, SAY SO on the page.

    line 154
  2. Distinctive:

    Keep this line and others can find it too.

    line 161

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Dependency Outage Audit

Install

Save this file as ~/.claude/skills/dependency-outage-audit/SKILL.md, or .claude/skills/dependency-outage-audit/SKILL.md to scope it to one repo. Claude Code auto-discovers it. Invoke with /dependency-outage-audit or by asking "what breaks if my database goes down?".

Why this exists

Most apps have never been tested with their database unavailable. The first real outage is the experiment, it runs in front of customers, and the result is usually worse than anyone expected: not one broken feature, but every page at once, because a single unguarded call in a shared layout or helper takes down surfaces that did not need that data at all.

Two failure modes cost the most, and both are invisible from a status dashboard:

  1. A read-only page dying for a write-path dependency. Browsing a catalog does not need a live database on every request, and yet it usually does.
  2. Failing at HTTP 200. A page that renders an error boundary still returns 200. Uptime monitors see success. Crawlers store the empty page as your content. You find out weeks later, from a human.

Step 1 — Inventory what each public page actually needs

rg --files -g '**/page.tsx' -g '**/page.jsx' -g '**/+page.svelte' -g 'pages/**/*.tsx'

For each page, list its data calls, following helpers rather than trusting names. A page calling getProduct() may pull five queries three levels down.

rg -n "await (prisma|db|sql|supabase|fetch|redis)\." <file>

Classify each call:

  • ESSENTIAL — the page is meaningless without it (an order, a user's library).
  • DECORATIVE — improves the page but is not the point (view counts, related items, ratings, seller stats).
  • INHERITED — pulled in by a shared layout, middleware, or session helper, so it hits pages that never asked for it. These cause the widest outages and are the least visible. Audit shared code first.

Step 2 — Find the pages that die for decorative or inherited reasons

These are the wins. A catalog page that dies because it also fetches a review count is trading its entire availability for a number nobody reads.

For each, decide the honest degraded output:

  • Real cached or snapshot data, if you have it.
  • The section omitted entirely.
  • An empty state that is TRUE ("no reviews shown" rather than "0 reviews").

Never invent a value to fill a gap. A fabricated count that persists after recovery is a worse outcome than the outage.

Step 3 — Check what status code a broken page returns

curl -s -o /dev/null -w "%{http_code}\n" https://<host>/<path>
curl -s https://<host>/<path> | head -c 2000

Compare status against CONTENT. Flag any 200 whose body is an error boundary, a spinner, or empty. For streamed server rendering, look for an abort marker with no completion (in React, a $RX( with no matching $RC(): the shell streamed, the data failed, and the error was painted on by client JavaScript after the 200 was already sent.

Rules of thumb:

  • Page temporarily unable to render real content: 503 with Retry-After.
  • A sitemap or feed that cannot enumerate: 5xx, never a valid-but-empty 200. An empty sitemap is a positive assertion that your pages are gone.
  • Genuinely missing: 404.

Step 4 — Simulate the outage, do not imagine it

Reasoning about this is unreliable. Break it on purpose, locally:

DATABASE_URL="postgresql://nope:nope@127.0.0.1:1/none" npm run start

Point the app at an unreachable host, not a deleted one, so you get connection failures rather than schema errors. Then walk every public route and record what each does. Do the same for cache and upstream APIs.

Do not sample. Sampling is how the interesting failures survive an audit: the broken page is rarely the one you would have picked.

Step 5 — Sweep every URL you advertise

The set that matters most is the set you have publicly promised is there:

curl -s https://<host>/sitemap.xml | grep -oE '<loc>[^<]+' | sed 's|<loc>||' > urls.txt
while read -r u; do
  code=$(curl -s -o /dev/null -w '%{http_code}' "$u")
  body=$(curl -s "$u")
  if [ "$code" != "200" ]; then echo "STATUS $code  $u"
  elif echo "$body" | grep -q '\$RX('; then echo "BROKEN RENDER  $u"; fi
done < urls.txt

Fetch every URL, including nested sitemaps. Pointing a crawler at a page you know is broken is the same error as an empty sitemap, aimed the other way. If a route genuinely cannot be served while degraded, unlist it until it can be.

Step 6 — Verify the guard actually fires

A degradation path that has never run is a guess. After adding one, re-run the broken-dependency simulation and confirm the page renders. Be especially suspicious of flags and helpers that decide whether to degrade: if that check silently evaluates false, it reports success while protecting nothing, and you will believe it. Assert the degraded state directly, in the environment where it runs.

Step 7 — Report

Pages audited: <n>       Advertised URLs swept: <n>

DIES, AND DOES NOT NEED TO
  <path>  needs <call> which is <decorative|inherited>  -> serve <what>

LIES ABOUT IT
  <path>  returns 200 with an error body  -> should be 503

DIES, LEGITIMATELY
  <path>  needs <call>  -> unlist while degraded, keep the honest error

NO ALERT PATH
  <yes/no: would anyone find out, through a channel that survives the outage>

That last line is frequently the real finding. An in-app dashboard, a log nobody reads, and a job that needs the same database are not alerts.

Rules

  • Simulate; never reason about it from the code alone.
  • Sweep every advertised URL, never a sample.
  • Degrading is not licence to invent data. Show less, never show fiction.
  • If you serve stale or partial data, SAY SO on the page. A store that looks healthy while checkout is dead burns more trust than one that admits it.
  • Route the alarm through something that does not share the dependency it watches.

From Toolbay. Free to use, modify, and share. Keep this line and others can find it too.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.