# Checking Production Readiness

> Audits a service for production readiness before its first deploy or a major rollout — verifies health endpoints, graceful shutdown, structured logging, 12-factor config, observability hooks, secrets handling, and container/runtime basics. Use when the user asks to "check production readiness", "pre-deploy audit", "is this ready to ship?", or mentions SLOs, health checks, graceful shutdown, or observability gaps. Covers a deterministic 40-item checklist, severity scoring, and a punch-list output. Do NOT use for security audits of secrets in source (use auditing-env-files), cloud cost review, pen testing, or load testing — those are separate skills.

- Skill: `criseulises/checking-production-readiness` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add criseulises/checking-production-readiness`
- Raw SKILL.md: https://api.skillmd.com/api/skills/criseulises/checking-production-readiness/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: criseulises (https://skillmd.com/u/criseulises)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/criseulises/checking-production-readiness

---


# Checking Production Readiness

## Overview

This skill walks through a 40-item checklist against a service's source tree and
generated artifacts (Dockerfile, k8s manifests, CI config). It does not run the
service or connect to cloud providers. It produces a punch-list graded by
severity so the team knows exactly what to fix before the deploy.

## Quick reference

| Area | Example checks |
|---|---|
| Health | `GET /healthz`, `GET /readyz`, distinct and correct |
| Shutdown | SIGTERM handler, drain timeout, in-flight request handling |
| Config | All config via env vars; schema-validated at boot; no commits with real values |
| Logging | Structured JSON, correlation id, no PII/secret leakage |
| Metrics | At least RED (Rate / Errors / Duration) exposed; `/metrics` for Prometheus |
| Tracing | OpenTelemetry SDK initialized; traceparent propagated through outbound calls |
| Errors | Error envelope consistent; stack traces never in response body |
| Dependencies | Pinned versions; lockfile present; `npm audit` / `pip-audit` clean |
| Container | Non-root user, minimal base, pinned digest, HEALTHCHECK or readiness probe |
| Rollout | Declared strategy (rolling, blue/green, canary); rollback documented |
| Docs | Runbook, SLOs, on-call rotation, dashboards linked from README |

## Workflow

```
Readiness check:
- [ ] Step 1: Confirm target project root
- [ ] Step 2: Detect stack (Node / Python / Go / Java) and framework
- [ ] Step 3: Run the 40-item checklist via scripts/check.py
- [ ] Step 4: Group findings by severity (Blocker / High / Medium / Info)
- [ ] Step 5: For each Blocker, propose a concrete fix
- [ ] Step 6: Emit punch-list to stdout; offer to write PRODUCTION-READINESS.md
- [ ] Step 7: Print the decision: Ship / Fix first / Needs deeper review
```

### Step 1 — Scope

Operate on the current directory. Refuse paths outside the project. Confirm the
directory contains at minimum one of: `package.json`, `pyproject.toml`,
`go.mod`, `pom.xml`, `build.gradle`, or `Cargo.toml`.

### Step 2 — Stack detection

Read the manifest file(s). Pick one primary stack. Emit a warning if multiple
services appear to live in the same root — suggest the user run the skill per
service.

### Step 3 — Checklist execution

```
python scripts/check.py
```

The script runs each item against the project tree. Each item returns one of:
`pass`, `fail`, `warn`, `skip` with a short reason string.

### Step 4 — Severity buckets

- **Blocker** — will cause an incident on day 1 (no `/healthz`, no shutdown
  handler, secret committed, no logging).
- **High** — will cause an incident within weeks (no error envelope, no rate
  limiting, no metrics, no tracing).
- **Medium** — will bite on-call within a quarter (no structured logs, no SLOs
  defined, docs missing).
- **Info** — nice-to-have.

### Step 5 — Per-blocker fix suggestions

For each blocker, include:
- Exact file and line (when applicable).
- The concrete fix (code snippet or config change).
- Rationale: what incident it prevents.

### Step 6 — Output format

Print the punch-list to stdout first. Then ask:

> "¿Querés que guarde esto como `./PRODUCTION-READINESS.md`? (y/N)"

Only write on explicit confirmation. Use this template:

```markdown
# Production readiness — <service> — <ISO date>

## Decision: <Ship | Fix first | Needs deeper review>

## Blockers (N)
- [ ] <file>:<line> — <check id> — <short reason>
      Fix: <concrete fix>

## High (N)
...

## Medium (N)
...

## Info (N)
...
```

### Step 7 — Decision rule

- 0 Blockers and ≤2 High → Ship.
- 0 Blockers and >2 High → Fix first (the Highs together usually add up to an
  incident).
- ≥1 Blocker → Fix first.
- Tricky ambiguous cases → Needs deeper review, list unresolved questions.

## The 40-item checklist (summary)

1–5: Health endpoints present, distinct, correct status codes, readiness pings deps, liveness is trivial.
6–10: Graceful shutdown — SIGTERM handler, drain timeout, in-flight requests, connection pools, queue workers.
11–15: Config — env-only, schema-validated, no defaults for secrets, fail-fast on missing, `.env.example` up to date.
16–20: Logging — structured, level-configurable, correlation id, no PII/secret leakage, sensible redaction list.
21–25: Metrics — RED exposed, `/metrics` endpoint, cardinality safe, business metrics identified, no per-user labels.
26–30: Tracing — OTel SDK, sampled, propagation, DB spans, outbound HTTP instrumented.
31–33: Errors — consistent envelope, no stack leakage, 4xx vs 5xx correctly mapped.
34–36: Dependencies — lockfile, pinned, audit tool run, no unapproved licenses.
37–40: Container — non-root, pinned base digest, HEALTHCHECK, rollout strategy + rollback runbook linked.

Full implementation in [scripts/check.py](scripts/check.py).

## Examples

**Example 1 — Greenfield Fastify service before first deploy**
Input: "is this Fastify service ready to ship to prod?"
Behavior: Detects Node + Fastify, runs 40 checks, reports 2 Blockers (no graceful
shutdown, no `/readyz` pinging DB), 3 High, 1 Medium. Outputs decision: Fix first.
Concrete fixes referenced by file:line.

**Example 2 — Python worker that looks fine but has no tracing**
Input: "pre-deploy audit of my celery worker"
Behavior: 0 Blockers, 1 High (no OTel SDK wired), 4 Medium. Decision: Ship, but
list the High to address next sprint.

**Example 3 — Repo with two services**
Input: "check prod readiness"
Behavior: Detects two manifests, warns the user, asks which service to audit
and recommends running once per service.

## Non-goals

- No secret scanning (use `auditing-env-files`).
- No cloud-cost review.
- No penetration testing.
- No load testing (use `k6-load-testing-builder`).
- No CI pipeline audit beyond the rollout artifact (use `ci-pipeline-optimizer`).
- No DB migration safety review (use `database-migration-writer`).

## Security

- **Scope**: operates only within the current directory. Refuses absolute paths,
  `..` escapes, and home-dir reads.
- **Read-only by default**. Writes exactly one file (`./PRODUCTION-READINESS.md`)
  and only after explicit user confirmation. Never modifies tracked files.
- **No network calls**. Does not ping cloud providers, does not pull from
  package registries, does not fetch manifests. All checks are offline.
- **No secret output**. If a check happens to find a literal-looking secret,
  report the file:line and defer to `auditing-env-files` for masked analysis.
- **Least-privilege `allowed-tools`**: `Read`, `Grep`, `Glob`, `Bash(python scripts/*)`,
  `Bash(git *)`. No `Write` without confirmation. No `WebFetch`, no `WebSearch`.
- **Dependencies**: Python 3.10+ standard library only. No pip installs.
- **No destructive actions**. Never runs deploys, never touches CI config files,
  never pushes, never rebases.

