writing-skills
writing-skills
Use when creating new skills, editing existing skills, or verifying skills work before deployment
opsDeploys, schema migrations, rollback and infrastructure. Use when "can I ship this on Friday", "this migration is scary", "what is the blast radius", "prevent accidental deletion of the database", or a change drops a column. Covers expand/contract, canary rollout, kill switches, prevent_destroy, tested backups. For an incident that already happened use retr…
Independent GitHub snapshot · Automated classification · Original documentation governs
Operations is where irreversible mistakes concentrate. Code mistakes are usually recoverable, git remembers, a revert ships in twenty minutes. A dropped table, a deleted bucket, a rotated credential, or a terminated stateful node is not recoverable by any amount of engineering after the fact.
So the governing question in this mode is different from the rest of the plugin. Not "can this be done wrong?" but: when this is done wrong, how much is affected, and can it be undone? Those two axes, blast radius and reversibility, determine every device below.
Before any framework or table, establish these. They are what an operator actually needs, and they are the things most often left out: an answer that skips them is not useful no matter how well organized the rest is. Say each one plainly, in a sentence, before going deeper.
Cover all four even when the answer is brief. If you only have room for a little, spend it here rather than on the taxonomy: the rungs below are how to think about the fix, but these four are what the person has to know before they ship.
Most ops poka-yoke is not about preventing the bad change. It is about ensuring the bad change reaches 1% of traffic instead of 100%. You cannot prevent every bad deploy; you can make bad deploys cheap.
| Rung | Device | What it buys |
|---|---|---|
| 1 Control | The dangerous operation is impossible in this environment, prevent_destroy on stateful resources, deletion protection on the database, no human write access to prod, immutable infrastructure | The mistake cannot be made at all |
| 1 Control | Progressive rollout with automatic rollback on error-rate: the bad version is withdrawn before most users see it | The mistake is capped and self-healing |
| 2 Warning | Required plan review, a deploy that prints what it will destroy and demands typed confirmation, alerts wired to the rollout | The mistake is visible at the moment of decision |
| 3 Detection | Post-deploy smoke tests, monitoring, an on-call human | The mistake is found after users find it |
| 0 | A runbook step that says "double-check the environment first" | Nothing |
Before adding any gate, ask whether the operation can be made reversible instead: a reversible operation needs far weaker devices, because the cost of the mistake collapses.
Co-deploying a destructive schema change with the code that depends on it is an outage, not a risk, during the rollout window old code necessarily runs against the new schema.
The pattern, one deploy per step:
Steps 1–4 are reversible: the old column stays readable throughout, so rolling the deploy
back is enough. Only step 5 is not, which is exactly why it gets its own deploy and its own
gate. The device that makes this stick is a CI check that refuses any DROP, TRUNCATE, or
ALTER ... DROP in a changed migration unless the PR carries an explicit approval label, see
guardrails for the gate itself.
Migration-specific hazards worth checking every time: a lock taken on a large table during
peak traffic; a backfill with no batch limit; an index created without CONCURRENTLY; a
NOT NULL added without a default on a populated table; a rename, which is a drop and an add
wearing a disguise.
A kill switch is a poka-yoke for a change you cannot fully test in advance. It converts "roll back a deploy" (minutes, and impossible if the migration already ran) into "flip a boolean" (seconds). Ship risky changes dark, behind a flag, then enable progressively.
Two things make flags devices rather than debt:
prevent_destroy on every stateful resource: databases, buckets, volumes, DNS zones.
One line, and it turns the worst cloud accident into a failed plan. It is Control against the
accident, not against intent: removing the block is another one-line change, so review has to
read a diff that deletes a prevent_destroy as itself a destructive change.The strongest device is not needing access: good observability, safe read-only debugging tools, and self-service runbooks remove most reasons a human ever holds a prod shell.
Where access is genuinely needed: time-boxed and audited, read-only by default, write access requiring a second approver, and a shell prompt that makes the environment impossible to mistake. Environment confusion, running the staging command against prod, is a top-tier ops mistake and it is fixed by making prod look and feel different, not by remembering.
Wrap dangerous scripts so the safe form is the easy one: dry-run by default with --apply to
commit, print the affected count before acting, refuse to run against prod without an explicit
flag, and refuse an empty or wildcard target.
Work through these, and report using the finding structure from audit:
--env flag defaulting to prod.Propose devices before applying them, and never apply infrastructure changes without explicit
approval: an apply is exactly the class of outward-facing, hard-to-reverse action that
belongs to the user, not to you. For anything you cannot run yourself (console settings,
branch protection, IAM), hand over the exact steps or CLI command.