<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>IT Checklists</title><link>https://checklists.metacog.co.kr/</link><description>Recent content on IT Checklists</description><generator>Hugo</generator><language>en-US</language><atom:link href="https://checklists.metacog.co.kr/index.xml" rel="self" type="application/rss+xml"/><item><title>Web Application Security Review</title><link>https://checklists.metacog.co.kr/docs/security/web-application-security/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/security/web-application-security/</guid><description>&lt;p&gt;Most web applications are not broken into through exotic zero-days. They are broken into through a missing authorisation check on an object ID, a session that never expires, or a file upload that lands in a directory the web server will happily execute. This review walks the request path from the browser to the database and back, in the order an attacker would probe it.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; an application security engineer together with a developer who knows the codebase. &lt;strong&gt;When:&lt;/strong&gt; before the first public release, after any change to authentication or authorisation, and at least annually for anything internet-facing.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="authentication"&gt;1. Authentication &lt;a href="#authentication" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Passwords are stored with a memory-hard hash&lt;/strong&gt; — bcrypt, scrypt, or Argon2id with tuned parameters; SHA-256 with a salt is not adequate against modern GPU cracking.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Credential stuffing is throttled per account and per source&lt;/strong&gt; — rate limit on the username as well as the IP, because attackers spread a single password across many accounts from many addresses.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Multi-factor authentication is available and enforced for privileged accounts&lt;/strong&gt; — TOTP or WebAuthn; SMS is a fallback, not a control you rely on for admins.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Account enumeration is not possible through login, registration, or password reset&lt;/strong&gt; — identical responses and identical timing whether or not the account exists.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Password reset tokens are single-use, random, and short-lived&lt;/strong&gt; — bound to the account, invalidated on use, and expiring within an hour.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The reset flow does not trust the Host header&lt;/strong&gt; — a reset link built from an attacker-controlled &lt;code&gt;Host&lt;/code&gt; sends the token to the attacker.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Default and seeded credentials are removed from every environment&lt;/strong&gt; — including the demo admin account someone added for a sales pitch.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="session-management"&gt;2. Session management &lt;a href="#session-management" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Session cookies carry HttpOnly, Secure, and SameSite=Lax or Strict&lt;/strong&gt; — HttpOnly blocks theft via XSS, Secure blocks it over plaintext, SameSite blunts CSRF.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The session identifier is rotated on login and on privilege change&lt;/strong&gt; — otherwise an attacker who fixes a victim&amp;rsquo;s session ID before login inherits the authenticated session.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Sessions expire on both idle timeout and absolute lifetime&lt;/strong&gt; — an idle timeout alone lets a stolen token live forever if it is used periodically.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Logout invalidates the session server-side&lt;/strong&gt; — deleting the cookie in the browser does nothing to a token an attacker already copied.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;JWTs, if used, pin the algorithm server-side and validate issuer, audience, and expiry&lt;/strong&gt; — accepting the &lt;code&gt;alg&lt;/code&gt; header from the token is how &lt;code&gt;none&lt;/code&gt; and key-confusion attacks work.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;There is a way to revoke a session or token before it expires&lt;/strong&gt; — needed the moment a laptop is lost or an account is compromised.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="authorisation-and-access-control"&gt;3. Authorisation and access control &lt;a href="#authorisation-and-access-control" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every request is authorised server-side against the authenticated principal&lt;/strong&gt; — hiding a button in the UI is not access control.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Object-level authorisation is checked on every object reference&lt;/strong&gt; — the classic IDOR is &lt;code&gt;GET /invoices/1042&lt;/code&gt; returning someone else&amp;rsquo;s invoice because only authentication was checked.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Authorisation is enforced in a central, hard-to-bypass layer&lt;/strong&gt; — a per-controller &lt;code&gt;if&lt;/code&gt; statement will eventually be forgotten on a new endpoint.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The default for a new endpoint is deny&lt;/strong&gt; — allow-listing what is public beats blocklisting what is protected.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Horizontal and vertical privilege escalation have been tested explicitly&lt;/strong&gt; — log in as a low-privilege user and replay an admin request with their session.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Multi-tenant queries are scoped by tenant at the data layer&lt;/strong&gt; — a missing &lt;code&gt;WHERE tenant_id = ?&lt;/code&gt; is a cross-customer data breach, not a bug.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Mass assignment is prevented&lt;/strong&gt; — bind request bodies to an explicit allow-list of fields, or a user updates their own &lt;code&gt;role&lt;/code&gt; field.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; broken object-level authorisation is the single most commonly exploited web flaw and is invisible to most automated scanners. Test it by hand, with two accounts, before release.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="input-handling-and-injection"&gt;4. Input handling and injection &lt;a href="#input-handling-and-injection" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All database access uses parameterised queries or a well-used ORM&lt;/strong&gt; — string concatenation into SQL is still the fastest route to full data loss.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dynamic query fragments such as sort columns are mapped through an allow-list&lt;/strong&gt; — parameter binding cannot protect an identifier or an &lt;code&gt;ORDER BY&lt;/code&gt; clause.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;OS command execution avoids the shell and passes arguments as an array&lt;/strong&gt; — and no user input reaches a command line at all where it can be avoided.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Templating engines are used in their auto-escaping mode with no raw interpolation of user data&lt;/strong&gt; — server-side template injection escalates straight to code execution.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deserialisation of untrusted data is avoided, or restricted to a safe format with a type allow-list&lt;/strong&gt; — native object deserialisation is remote code execution waiting for input.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Input validation is positive&lt;/strong&gt; — validate against expected type, length, format, and range rather than trying to filter known-bad strings.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;XML parsers have external entity resolution disabled&lt;/strong&gt; — XXE turns a document upload into a file-read and internal-network probe.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="output-encoding-and-browser-side-defences"&gt;5. Output encoding and browser-side defences &lt;a href="#output-encoding-and-browser-side-defences" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Output is contextually encoded at the point of rendering&lt;/strong&gt; — HTML body, attribute, JavaScript, URL, and CSS contexts each need different escaping.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any use of a raw-HTML sink is reviewed and sanitised with a maintained library&lt;/strong&gt; — &lt;code&gt;innerHTML&lt;/code&gt;, &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;, and their equivalents are where DOM XSS lives.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A Content Security Policy is deployed without unsafe-inline or unsafe-eval&lt;/strong&gt; — nonce or hash based, so an injected script has nowhere to execute.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;State-changing requests require an anti-CSRF token or are restricted to same-site requests&lt;/strong&gt; — SameSite cookies help but do not cover every browser or every flow.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;CORS does not reflect arbitrary origins and does not combine a wildcard with credentials&lt;/strong&gt; — reflecting &lt;code&gt;Origin&lt;/code&gt; with &lt;code&gt;Allow-Credentials: true&lt;/code&gt; is equivalent to no same-origin policy at all.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Security headers are set&lt;/strong&gt; — HSTS with a long max-age, &lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt;, and a restrictive &lt;code&gt;Referrer-Policy&lt;/code&gt; and &lt;code&gt;Permissions-Policy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Clickjacking is prevented&lt;/strong&gt; — &lt;code&gt;frame-ancestors&lt;/code&gt; in the CSP, with &lt;code&gt;X-Frame-Options&lt;/code&gt; for legacy clients.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="business-logic-and-abuse-resistance"&gt;6. Business logic and abuse resistance &lt;a href="#business-logic-and-abuse-resistance" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Server-side price, quantity, and discount values are authoritative&lt;/strong&gt; — never trust an amount that came back from the client.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Workflow steps cannot be skipped or replayed&lt;/strong&gt; — verify that jumping straight to the confirmation endpoint fails.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Race conditions on limited resources are handled with locking or atomic operations&lt;/strong&gt; — parallel requests are how a single-use coupon gets redeemed fifty times.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Expensive endpoints are rate limited and quota bounded&lt;/strong&gt; — search, export, and report generation are cheap to request and expensive to serve.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Server-side requests to user-supplied URLs are blocked or proxied through an allow-list&lt;/strong&gt; — SSRF into cloud metadata endpoints is a standard path to credential theft.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="data-protection-and-privacy"&gt;7. Data protection and privacy &lt;a href="#data-protection-and-privacy" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All traffic is HTTPS with modern TLS and HTTP redirected permanently&lt;/strong&gt; — including internal service-to-service calls.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Sensitive data is not placed in URLs&lt;/strong&gt; — query strings end up in access logs, referrer headers, and browser history.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Personal and sensitive fields are encrypted at rest where the threat model demands it&lt;/strong&gt; — with keys held outside the database.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Error responses are generic and stack traces are never returned to the client&lt;/strong&gt; — detailed errors map your framework, versions, and file layout for an attacker.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Caching headers prevent sensitive responses being stored by browsers or intermediaries.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Uploaded files are validated by content, stored outside the web root, and served with a fixed content type&lt;/strong&gt; — and never with a user-controlled filename or extension.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dependencies-and-configuration"&gt;8. Dependencies and configuration &lt;a href="#dependencies-and-configuration" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A software bill of materials is generated and dependencies are scanned on every build&lt;/strong&gt; — with a policy for how quickly a critical finding must be fixed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Framework and server configurations are hardened for production&lt;/strong&gt; — debug mode off, directory listing off, admin consoles unreachable from the internet.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Client-side third-party scripts are inventoried and justified&lt;/strong&gt; — every tag manager script runs with full access to your DOM and cookies.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets are loaded from a secret manager, not from the repository or the container image&lt;/strong&gt; — verify with a history scan, not just a look at the current tree.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Security-relevant events are logged with enough context to investigate&lt;/strong&gt; — authentication outcomes, authorisation failures, and privileged actions, with no credentials in the log.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Authentication&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Session management&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Authorisation and access control&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Input handling and injection&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Output encoding and browser defences&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Business logic and abuse resistance&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Data protection and privacy&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Dependencies and configuration&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Every finding that is not a clean pass needs a severity, an owner, and a fix date agreed before release.&lt;/p&gt;</description></item><item><title>Cloud Security Posture</title><link>https://checklists.metacog.co.kr/docs/security/cloud-security/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/security/cloud-security/</guid><description>&lt;p&gt;Cloud breaches rarely involve breaking the provider. They involve an over-permissive role, a storage bucket that was made public for a demo, or a long-lived access key committed to a repository. This checklist reviews the posture of a cloud account or subscription across identity, network, data, logging, and workload configuration. It is written to apply to AWS, Azure, and Google Cloud; substitute the local name for each concept as you go.&lt;/p&gt;</description></item><item><title>Security Code Review</title><link>https://checklists.metacog.co.kr/docs/security/security-code-review/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/security/security-code-review/</guid><description>&lt;p&gt;A security code review is a normal code review with one extra question asked of every line: what happens if the input is hostile? It is cheaper than a penetration test and catches a different class of problem — the missing check, the unsafe default, the trust boundary crossed without anyone noticing. Use this list when reviewing a change that touches authentication, authorisation, data handling, cryptography, or anything that parses untrusted input.&lt;/p&gt;</description></item><item><title>Secrets Management</title><link>https://checklists.metacog.co.kr/docs/security/secrets-management/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/security/secrets-management/</guid><description>&lt;p&gt;Secrets leak the same way every time: someone needed a credential in a hurry, put it somewhere convenient, and nobody ever moved it. This checklist covers the whole lifecycle of a secret — how it is created, where it lives, how it reaches the workload that needs it, how it is rotated, and how it is destroyed. Work through it per system rather than per organisation, because one exemplary service and one hardcoded database password in the next repository still adds up to a breach.&lt;/p&gt;</description></item><item><title>Security Incident Response</title><link>https://checklists.metacog.co.kr/docs/security/incident-response/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/security/incident-response/</guid><description>&lt;p&gt;A security incident is an operational incident with lawyers, regulators, and an adversary who reacts to what you do. The decisions that matter most — whether to isolate a host, when to rotate credentials, who tells the regulator — are terrible decisions to make for the first time at 2am. This checklist covers both readiness and the live response, in the order events actually unfold: prepare, detect, contain, eradicate, recover, and learn.&lt;/p&gt;</description></item><item><title>Penetration Test Readiness</title><link>https://checklists.metacog.co.kr/docs/security/penetration-test-readiness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/security/penetration-test-readiness/</guid><description>&lt;p&gt;A penetration test is expensive per day and the days are easily wasted. Testers regularly spend the first two of five days waiting for credentials, discovering the environment does not match production, or re-finding issues an internal scanner already reported. This checklist gets the engagement ready so the testers spend their time on the things only a human can find: chained logic flaws, authorisation gaps, and abuse of the features you are proud of.&lt;/p&gt;</description></item><item><title>Production Readiness Review</title><link>https://checklists.metacog.co.kr/docs/devops/production-readiness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/devops/production-readiness/</guid><description>&lt;p&gt;A production readiness review (PRR) is the gate between &amp;ldquo;it works on staging&amp;rdquo; and &amp;ldquo;it carries customer traffic at 3am while nobody is watching&amp;rdquo;. Work through this before the first real request hits the service, and again whenever ownership changes hands.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the owning team, with one reviewer from outside the team. &lt;strong&gt;When:&lt;/strong&gt; at least one week before launch, so findings can actually be fixed.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="ownership-and-documentation"&gt;1. Ownership and documentation &lt;a href="#ownership-and-documentation" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A named team owns the service&lt;/strong&gt; — not an individual, and the owner is recorded somewhere machine-readable (service catalogue, &lt;code&gt;CODEOWNERS&lt;/code&gt;, or repo metadata).&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The escalation path is written down&lt;/strong&gt; — who gets paged first, who gets paged if they do not acknowledge, and who is the business decision-maker for an outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A runbook exists and has been read by someone who did not write it&lt;/strong&gt; — start-up, shut-down, common failure modes, and how to check whether the service is actually healthy.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The architecture diagram matches reality&lt;/strong&gt; — every dependency the service calls, and every caller it serves, is on the diagram.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All upstream and downstream dependencies are listed with their criticality&lt;/strong&gt; — mark each as hard (service fails without it) or soft (degrades gracefully).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="reliability-and-failure-behaviour"&gt;2. Reliability and failure behaviour &lt;a href="#reliability-and-failure-behaviour" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every outbound call has a timeout&lt;/strong&gt; — a default-infinite HTTP client is the single most common cause of cascading failure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retries use exponential backoff with jitter and a retry budget&lt;/strong&gt; — naive retries turn a slow dependency into a self-inflicted denial of service.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Hard dependency failures degrade rather than crash&lt;/strong&gt; — decide per dependency whether to fail open, fail closed, or serve stale data, and make it explicit in code.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The service starts cleanly from cold&lt;/strong&gt; — no dependency on warm caches, in-memory state from a previous instance, or manual post-start steps.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Health checks distinguish liveness from readiness&lt;/strong&gt; — liveness must not fail because a downstream dependency is down, or the orchestrator will restart-loop a healthy process.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Graceful shutdown is implemented&lt;/strong&gt; — the process stops accepting new work, drains in-flight requests, and exits within the orchestrator&amp;rsquo;s termination grace period.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Single points of failure are identified and accepted in writing&lt;/strong&gt; — a shared database, a single availability zone, or one licence server all count.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; a service without timeouts on outbound calls should not be launched. Everything else on this list can carry a dated follow-up ticket; this one cannot.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="observability"&gt;3. Observability &lt;a href="#observability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The four golden signals are on a dashboard&lt;/strong&gt; — traffic, error rate, latency (p50/p95/p99), and saturation of the constraining resource.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Logs are structured and include a correlation ID&lt;/strong&gt; — free-text logs are unsearchable at the exact moment you need them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No secrets, tokens, or personal data are written to logs&lt;/strong&gt; — grep the codebase for logging of request bodies and auth headers specifically.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Distributed tracing is wired through the request path&lt;/strong&gt; — trace context is propagated to every downstream call, not just the first hop.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Log retention is set deliberately&lt;/strong&gt; — long enough to investigate a slow-burning bug, short enough to satisfy the data retention policy.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A synthetic probe exercises the critical user journey&lt;/strong&gt; — dashboards go green when nobody is using a broken feature.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="alerting"&gt;4. Alerting &lt;a href="#alerting" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alerts fire on user-visible symptoms, not on causes&lt;/strong&gt; — &amp;ldquo;checkout error rate above 2% for 5 minutes&amp;rdquo; beats &amp;ldquo;CPU above 80%&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every alert links to the runbook section that resolves it&lt;/strong&gt; — an alert with no documented response is a notification, not an alert.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alert thresholds have been tested by deliberately breaking something&lt;/strong&gt; — in staging, with the on-call rotation watching.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Paging alerts are distinguishable from ticket-generating alerts&lt;/strong&gt; — if everything pages, nothing pages.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alert volume is estimated and is under a page or two per shift&lt;/strong&gt; — model it against the last month of staging data if you have nothing else.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="capacity-and-performance"&gt;5. Capacity and performance &lt;a href="#capacity-and-performance" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A load test has been run against production-like infrastructure&lt;/strong&gt; — same instance sizes, same database tier, same network topology.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The breaking point is known&lt;/strong&gt; — the request rate at which latency degrades past the SLO, and what fails first when you get there.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Expected launch traffic is documented with a peak-to-average ratio&lt;/strong&gt; — including any marketing spike, batch job, or scheduled import.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Autoscaling limits are set and the maximum is affordable&lt;/strong&gt; — check the maximum against the monthly budget, not just the technical limit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Resource requests and limits are set from measured usage&lt;/strong&gt; — not copied from another service&amp;rsquo;s manifest.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rate limiting or load shedding protects the service from a bad client&lt;/strong&gt; — including your own retrying clients.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="data-and-state"&gt;6. Data and state &lt;a href="#data-and-state" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backups are configured and a restore has actually been performed&lt;/strong&gt; — an untested backup is a hypothesis.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The recovery time and recovery point objectives are written down and achievable&lt;/strong&gt; — measure the restore, do not estimate it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Schema migrations are backward compatible&lt;/strong&gt; — the previous version of the application must run against the new schema for the duration of the rollout.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data at rest and in transit is encrypted&lt;/strong&gt; — including backups, snapshots, and any object storage bucket.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Personal data is classified and its retention period is enforced by a job, not by intention.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security"&gt;7. Security &lt;a href="#security" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The service authenticates its callers and authorises every request&lt;/strong&gt; — network position is not authorisation.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets come from a secret manager at runtime&lt;/strong&gt; — not from environment variables baked into an image, and never from the repository.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependencies have been scanned and known critical vulnerabilities are resolved or accepted in writing.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The container runs as a non-root user with a read-only root filesystem where possible.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Network access is least-privilege&lt;/strong&gt; — the service can reach only the dependencies it declared in section 1.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;An audit log records security-relevant events&lt;/strong&gt; — authentication, authorisation failures, and privileged actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="release-and-rollback"&gt;8. Release and rollback &lt;a href="#release-and-rollback" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deployment is fully automated and repeatable&lt;/strong&gt; — the same command, run by anyone on the team, from a clean checkout.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback has been rehearsed and is a single documented action&lt;/strong&gt; — and it works even when the deployment pipeline is broken.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The rollout is progressive&lt;/strong&gt; — canary, blue/green, or percentage-based, with automated abort on error-rate regression.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Feature flags gate risky behaviour and are removed on a schedule&lt;/strong&gt; — a permanent flag is a permanent untested code path.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback is safe with respect to data&lt;/strong&gt; — if the new version wrote data the old version cannot read, rollback is a lie.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cost"&gt;9. Cost &lt;a href="#cost" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The expected monthly cost is estimated and has an owner.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every resource is tagged for cost allocation&lt;/strong&gt; — service, team, and environment at minimum.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A budget alert is configured at a threshold that gives you time to react.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Reliability and failure behaviour&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Observability and alerting&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Capacity and performance&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Data, backup, and recovery&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Security&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Release and rollback&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with an owner before the launch is approved.&lt;/p&gt;</description></item><item><title>CI/CD Pipeline Review</title><link>https://checklists.metacog.co.kr/docs/devops/cicd-pipeline/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/devops/cicd-pipeline/</guid><description>&lt;p&gt;A pipeline is production infrastructure. It holds credentials to every environment you own, it decides what code becomes a running artefact, and when it is wrong it is wrong for every service at once. Review it the way you would review a service that has write access to production, because that is exactly what it is.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the team that owns the pipeline, with a reviewer from platform or security. &lt;strong&gt;When:&lt;/strong&gt; when a new pipeline is created, after any change to its credentials or permissions, and at least annually for pipelines that deploy to production.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="source-control-and-change-flow"&gt;1. Source control and change flow &lt;a href="#source-control-and-change-flow" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The default branch is protected against direct pushes&lt;/strong&gt; — including for administrators, or the protection is decorative.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Merging requires a passing pipeline and at least one approving review&lt;/strong&gt; — and approvals are dismissed when new commits are pushed, otherwise a reviewer approves one diff and a different one merges.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;CODEOWNERS&lt;/code&gt; covers the pipeline definition itself&lt;/strong&gt; — a change to the deploy workflow deserves more scrutiny than a change to a README.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Force-push and branch deletion are disabled on protected branches&lt;/strong&gt; — recovering the true history after a force-push to main is far harder than preventing it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Commits are traceable to a person&lt;/strong&gt; — signed commits or a verified identity, so a compromised token cannot quietly author a change attributed to someone else.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every deployable commit is reachable from a tag or release record&lt;/strong&gt; — you must be able to answer &amp;ldquo;what exactly is running?&amp;rdquo; without guessing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="build-reproducibility"&gt;2. Build reproducibility &lt;a href="#build-reproducibility" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A clean checkout on a fresh runner produces the same artefact&lt;/strong&gt; — any dependence on a warm cache, a pre-installed tool, or a developer&amp;rsquo;s machine is a latent build break.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All dependencies are pinned by version and, where the ecosystem supports it, by digest or hash&lt;/strong&gt; — a lockfile that resolves floating ranges at build time is not pinning.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The lockfile is committed and the build fails if it is out of date&lt;/strong&gt; — &lt;code&gt;npm ci&lt;/code&gt;, &lt;code&gt;pip install --require-hashes&lt;/code&gt;, &lt;code&gt;go mod verify&lt;/code&gt; and equivalents rather than a permissive install.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Base images and build tool versions are pinned rather than tracking &lt;code&gt;latest&lt;/code&gt;&lt;/strong&gt; — an upstream tag moving under you turns a green pipeline red for reasons unrelated to your change.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The build has no network access to unpinned sources at package time&lt;/strong&gt; — pulling a script from a URL during the build makes the artefact a function of the internet&amp;rsquo;s mood.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Build outputs are written to a fresh workspace each run&lt;/strong&gt; — leftover files from a previous build are a classic source of artefacts that cannot be recreated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pipeline-credentials-and-permissions"&gt;3. Pipeline credentials and permissions &lt;a href="#pipeline-credentials-and-permissions" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline authenticates to cloud providers with short-lived OIDC federation, not a long-lived access key stored as a repository secret&lt;/strong&gt; — a leaked static key is valid until someone notices; a federated token expires in minutes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each job requests the minimum token scope it needs&lt;/strong&gt; — a test job does not need write permission to packages or deployments.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets are scoped per environment&lt;/strong&gt; — the staging deploy job must not be able to read production credentials.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deployment credentials are held by a protected environment with required reviewers, not by the workflow file&lt;/strong&gt; — otherwise any contributor who can edit a workflow can reach production.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Workflows triggered by forked pull requests cannot read secrets&lt;/strong&gt; — the &lt;code&gt;pull_request_target&lt;/code&gt; trigger and equivalents are the single most exploited CI misconfiguration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets are masked in logs and the masking has been tested&lt;/strong&gt; — try echoing a secret through base64 in a scratch branch and confirm it is redacted.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Credential rotation is documented and has been performed at least once&lt;/strong&gt; — an unrotatable credential is a permanent liability.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; a pipeline that exposes production credentials to workflows runnable from a fork is remotely exploitable by any user of the platform. Fix this before anything else on the list.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="third-party-actions-and-runners"&gt;4. Third-party actions and runners &lt;a href="#third-party-actions-and-runners" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every third-party action or plugin is pinned to a full commit SHA, not a tag&lt;/strong&gt; — tags are mutable, so a pinned tag is an invitation to a supply-chain compromise.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The set of allowed actions is restricted by policy&lt;/strong&gt; — an allowlist of verified publishers and your own organisation, rather than the whole marketplace.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Self-hosted runners for public repositories are ephemeral and isolated&lt;/strong&gt; — a persistent runner shared with untrusted pull requests leaks the previous job&amp;rsquo;s state.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Runner images are patched and rebuilt on a schedule&lt;/strong&gt; — a runner is a long-lived machine with credentials, and it ages like any other host.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Caches are keyed so that untrusted branches cannot poison a cache used by trusted builds&lt;/strong&gt; — cache entries are executable inputs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline pulls container images by digest, not by mutable tag&lt;/strong&gt; — &lt;code&gt;:latest&lt;/code&gt; in a deployment step means you cannot say what you shipped.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="testing-and-quality-gates"&gt;5. Testing and quality gates &lt;a href="#testing-and-quality-gates" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Unit, integration, and contract tests run on every pull request and block merge on failure&lt;/strong&gt; — a test suite that only runs after merge is a report, not a gate.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Flaky tests are quarantined with an owner and a deadline, not retried silently&lt;/strong&gt; — automatic retries hide real race conditions until they reach production.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Database migrations are exercised against a realistic schema in CI&lt;/strong&gt; — a migration that has only ever run on an empty table has not been tested.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Test data contains no production personal data&lt;/strong&gt; — synthetic or masked fixtures only, since CI logs and artefacts are widely readable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Total pipeline duration for a pull request is measured and kept short enough that people do not batch changes&lt;/strong&gt; — slow pipelines cause large, risky merges.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A failing pipeline cannot be bypassed by a manual override without an audit record&lt;/strong&gt; — emergency overrides need to exist and need to leave a trace.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security-scanning-in-the-pipeline"&gt;6. Security scanning in the pipeline &lt;a href="#security-scanning-in-the-pipeline" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependency scanning runs on every build and fails on new critical vulnerabilities&lt;/strong&gt; — with an explicit, time-limited exception process rather than a permanently ignored report.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Static analysis runs on changed code and its findings block merge at an agreed severity&lt;/strong&gt; — a scanner whose output nobody reads is theatre.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secret scanning runs on the diff and on the full history&lt;/strong&gt; — push protection stops the next leak, history scanning finds the one from last year.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Container images are scanned after build and before promotion&lt;/strong&gt; — scanning only the Dockerfile misses everything the base image contributes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Infrastructure-as-code templates are scanned for misconfiguration&lt;/strong&gt; — public buckets and open security groups are cheaper to catch here than in a cloud audit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Scanner findings have an owner and an SLA by severity&lt;/strong&gt; — an unbounded backlog of findings is indistinguishable from no scanning.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="artefact-management-and-provenance"&gt;7. Artefact management and provenance &lt;a href="#artefact-management-and-provenance" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Artefacts are built once and promoted through environments unchanged&lt;/strong&gt; — rebuilding per environment means staging never tested what production runs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every artefact is immutable in the registry&lt;/strong&gt; — tag overwrites must be disabled, or a rollback can silently deliver different bytes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A software bill of materials is generated and stored with each artefact&lt;/strong&gt; — when the next widely used library has a critical CVE, you need to answer &amp;ldquo;are we affected?&amp;rdquo; in minutes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Build provenance is recorded and verifiable&lt;/strong&gt; — an attestation binding the artefact digest to the source commit and the builder, following SLSA levels.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The deployment step verifies the artefact signature or attestation before rolling out&lt;/strong&gt; — provenance you never check is metadata, not a control.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Registry retention and cleanup policies exist&lt;/strong&gt; — untagged layers accumulate cost, and stale images get deployed by accident.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="deployment-and-rollback"&gt;8. Deployment and rollback &lt;a href="#deployment-and-rollback" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deployment to production is a distinct, separately authorised step&lt;/strong&gt; — not a side effect of merging.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline can deploy a specific previous artefact version on demand&lt;/strong&gt; — rollback must not require rebuilding from an old commit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Concurrency control prevents two deployments to the same environment at once&lt;/strong&gt; — overlapping rollouts produce a state nobody designed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollouts are progressive with automated abort on error-rate or latency regression&lt;/strong&gt; — canary or percentage-based, with the abort criteria defined before the deploy.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A break-glass deployment path exists and is documented&lt;/strong&gt; — including how to deploy when the CI platform itself is down.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every deployment writes an audit record&lt;/strong&gt; — who, what artefact digest, which environment, and when.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pipeline-reliability-and-maintenance"&gt;9. Pipeline reliability and maintenance &lt;a href="#pipeline-reliability-and-maintenance" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Pipeline failures alert the owning team, not just the commit author&lt;/strong&gt; — a broken shared pipeline blocks everyone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Pipeline definitions are version controlled and reviewed like application code&lt;/strong&gt; — no click-configured jobs that exist only in the CI platform&amp;rsquo;s database.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Success rate and duration are tracked over time&lt;/strong&gt; — a slowly degrading pipeline is a slowly degrading release cadence.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline is restorable if the CI platform account is lost&lt;/strong&gt; — configuration in the repository, secrets in a secret manager with a documented restore.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Unused workflows, runners, and credentials are removed on a schedule&lt;/strong&gt; — dormant automation with live credentials is a favourite foothold.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Source control and change flow&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Build reproducibility&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pipeline credentials and permissions&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Third-party actions and runners&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Testing and quality gates&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Security scanning in the pipeline&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Artefact management and provenance&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Deployment and rollback&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pipeline reliability and maintenance&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner before the pipeline is approved for production deployments.&lt;/p&gt;</description></item><item><title>Container Image Hardening</title><link>https://checklists.metacog.co.kr/docs/devops/container-image/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/devops/container-image/</guid><description>&lt;p&gt;Most container images in production are far larger, far more privileged, and far older than anyone intended. Each extra package is attack surface you will be asked about after an incident, and each unpinned base tag is a change you did not review. Work through this before an image is promoted beyond a development environment, and again whenever the base image changes.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the team that owns the Dockerfile, with a reviewer from platform or security for images that run in production. &lt;strong&gt;When:&lt;/strong&gt; at image creation, at any base image change, and on a recurring schedule for long-lived images.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="base-image-selection"&gt;1. Base image selection &lt;a href="#base-image-selection" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The base image comes from a known, maintained publisher&lt;/strong&gt; — an official image, a vendor-supported distribution image, or your own internal base, rather than an arbitrary registry account.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The base image is pinned by digest, not by tag&lt;/strong&gt; — &lt;code&gt;FROM node:22-slim&lt;/code&gt; moves under you; &lt;code&gt;FROM node:22-slim@sha256:...&lt;/code&gt; is a decision you can review.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The smallest viable base is used&lt;/strong&gt; — distroless, Alpine, or a slim variant, since packages you never installed cannot be vulnerable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The base image&amp;rsquo;s support lifecycle outlasts the planned life of the service&lt;/strong&gt; — building on a distribution release that reaches end of life in three months guarantees unpatchable CVEs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A rebuild cadence is defined for picking up base image patches&lt;/strong&gt; — an image built once and never rebuilt accumulates vulnerabilities even if your own code never changes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The architecture set is explicit&lt;/strong&gt; — multi-architecture images are built deliberately, so an arm64 node does not silently pull an emulated amd64 image.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="build-hygiene"&gt;2. Build hygiene &lt;a href="#build-hygiene" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A multi-stage build separates compilation from runtime&lt;/strong&gt; — compilers, package managers, and build caches must not ship to production.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The final stage copies only the artefacts it needs&lt;/strong&gt; — copying the whole build workspace defeats the point of multi-stage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;.dockerignore&lt;/code&gt; excludes &lt;code&gt;.git&lt;/code&gt;, local environment files, credentials, and test fixtures&lt;/strong&gt; — build context leakage is a routine cause of secrets inside images.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Package installation and cache cleanup happen in the same layer&lt;/strong&gt; — a cleanup in a later layer removes files from the filesystem view but not from the image size or history.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Layer ordering puts rarely changing steps first&lt;/strong&gt; — dependency installation before source copy, so a code change does not invalidate the whole cache.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No package manager remains usable at runtime where it can be removed&lt;/strong&gt; — an image where an attacker can &lt;code&gt;apt-get install&lt;/code&gt; their tooling is a much friendlier environment for them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image builds without &lt;code&gt;--privileged&lt;/code&gt; or a mounted Docker socket&lt;/strong&gt; — build steps requiring the host daemon are a privilege escalation path from CI into the host.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="secrets-and-build-time-data"&gt;3. Secrets and build-time data &lt;a href="#secrets-and-build-time-data" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No secret is passed as a build argument&lt;/strong&gt; — &lt;code&gt;ARG&lt;/code&gt; values are recorded in image history and readable by anyone who can pull the image.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Private registry or repository credentials use build secret mounts&lt;/strong&gt; — BuildKit secret mounts are not persisted into any layer.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image history has been inspected for accidental secret inclusion&lt;/strong&gt; — a file deleted in a later layer is still present in the earlier one and still extractable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.npmrc&lt;/code&gt;, &lt;code&gt;.netrc&lt;/code&gt;, or cloud credential file is present in the final image&lt;/strong&gt; — verify by listing the filesystem, not by reading the Dockerfile.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Runtime configuration comes from the environment or a mounted secret, not baked into the image&lt;/strong&gt; — an image containing production endpoints and keys cannot be reused or safely shared.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Private base images are pulled with credentials scoped to the pipeline&lt;/strong&gt; — not a shared personal registry token.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="runtime-user-and-filesystem"&gt;4. Runtime user and filesystem &lt;a href="#runtime-user-and-filesystem" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image declares a non-root &lt;code&gt;USER&lt;/code&gt; with a fixed numeric UID&lt;/strong&gt; — a username alone does not satisfy orchestrator policies that check &lt;code&gt;runAsNonRoot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The UID is outside the host&amp;rsquo;s reserved range and does not collide with a privileged host user&lt;/strong&gt; — a common convention is a UID above 10000.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The application does not need to write to the root filesystem&lt;/strong&gt; — everything writable is an explicit volume or &lt;code&gt;tmpfs&lt;/code&gt;, so the container can run with a read-only root.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No file in the image is setuid or setgid unless justified&lt;/strong&gt; — strip these bits during the build and record any exception.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;File ownership and permissions are set at build time, not by a start-up script running as root&lt;/strong&gt; — an entrypoint that starts privileged and drops later is weaker than never being privileged.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image contains no shell where the workload does not require one&lt;/strong&gt; — a distroless runtime removes the most convenient post-exploitation tooling.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="image-content-and-dependencies"&gt;5. Image content and dependencies &lt;a href="#image-content-and-dependencies" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The package list has been reviewed and unnecessary packages removed&lt;/strong&gt; — debugging tools, editors, and network utilities are for a debug image, not the production one.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Application dependencies are installed from a lockfile with integrity hashes&lt;/strong&gt; — so the image content is a function of the commit, not of the registry at build time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A software bill of materials is generated at build and stored alongside the image&lt;/strong&gt; — this is how you answer &amp;ldquo;are we affected?&amp;rdquo; during the next ecosystem-wide CVE.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image is scanned for operating system and language-level vulnerabilities before promotion&lt;/strong&gt; — many scanners default to OS packages only and miss the application layer entirely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Critical and high findings are fixed or have a recorded, dated exception&lt;/strong&gt; — with the compensating control written down, not implied.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Licence obligations of bundled dependencies have been checked&lt;/strong&gt; — copyleft components in a distributed image create obligations that are expensive to discover late.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Common mistake:&lt;/strong&gt; scanning the image once at build time and never again. A CVE published tomorrow applies to the image running today, so scan images in the registry on a schedule and alert on newly discovered findings in what is deployed, not only in what is being built.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="image-metadata-and-identity"&gt;6. Image metadata and identity &lt;a href="#image-metadata-and-identity" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image carries OCI standard labels&lt;/strong&gt; — source repository, revision, build timestamp, and version, so a running container can be traced to a commit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Tags are immutable in the registry&lt;/strong&gt; — overwriting a tag makes rollback and forensics unreliable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deployments reference images by digest&lt;/strong&gt; — a tag tells you the intent, a digest tells you the bytes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A meaningful versioning scheme is used, and &lt;code&gt;latest&lt;/code&gt; is not deployed anywhere&lt;/strong&gt; — &lt;code&gt;latest&lt;/code&gt; is the fastest way to lose track of what is running.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The image is signed and the signature is verifiable&lt;/strong&gt; — with the verification wired into admission control rather than performed by hand.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Build provenance attestations are attached to the image&lt;/strong&gt; — recording which builder, which source commit, and which parameters produced it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="runtime-configuration-in-the-image"&gt;7. Runtime configuration in the image &lt;a href="#runtime-configuration-in-the-image" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;ENTRYPOINT&lt;/code&gt; uses exec form so the application is PID 1 and receives signals&lt;/strong&gt; — a shell form entrypoint swallows &lt;code&gt;SIGTERM&lt;/code&gt; and turns every deploy into a hard kill after the grace period.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Zombie process reaping is handled&lt;/strong&gt; — either the application reaps children correctly or a minimal init process is used.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;EXPOSE&lt;/code&gt; documents the ports actually served, and nothing listens on an undocumented port&lt;/strong&gt; — surprises here become surprises in network policy.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Application logs go to stdout and stderr&lt;/strong&gt; — writing to files inside the container hides logs from the platform&amp;rsquo;s collector.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A health check endpoint exists in the application and is documented&lt;/strong&gt; — the orchestrator&amp;rsquo;s probe configuration depends on it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The default working directory and configuration paths are documented&lt;/strong&gt; — operators should not have to read the Dockerfile to mount a config file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="registry-and-distribution"&gt;8. Registry and distribution &lt;a href="#registry-and-distribution" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Push access to production repositories is limited to the pipeline identity&lt;/strong&gt; — no individual should be able to push an image that admission control will accept.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The registry requires authentication for pulls of private images and does not permit anonymous listing&lt;/strong&gt; — public registry repositories routinely leak internal service names and configuration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retention policies remove untagged and superseded images&lt;/strong&gt; — while retaining every digest that is still referenced by a running workload or a rollback plan.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Image promotion between environments copies the same digest&lt;/strong&gt; — never a rebuild, or staging validated something production never ran.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Registry availability is considered in the failure model&lt;/strong&gt; — a node that cannot pull cannot recover, so pull policies and caching are chosen deliberately.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Access to the registry is audited&lt;/strong&gt; — pushes, deletes, and permission changes are logged and reviewed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Base image selection&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Build hygiene&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Secrets and build-time data&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Runtime user and filesystem&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Image content and dependencies&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Image metadata and identity&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Runtime configuration in the image&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Registry and distribution&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner before the image is promoted to production.&lt;/p&gt;</description></item><item><title>Kubernetes Deployment</title><link>https://checklists.metacog.co.kr/docs/devops/kubernetes-deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/devops/kubernetes-deployment/</guid><description>&lt;p&gt;Kubernetes will happily run a badly configured workload for months and then fail it all at once, during a node upgrade or a noisy-neighbour spike. Almost every &amp;ldquo;Kubernetes outage&amp;rdquo; is really a missing probe, an absent resource request, or a disruption budget nobody set. Work through this before a workload goes to a production cluster, and again after any significant change to its manifests.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the owning team, with a platform engineer reviewing cluster-level settings. &lt;strong&gt;When:&lt;/strong&gt; before the first production apply, and whenever resources, probes, or scaling behaviour change.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="workload-definition"&gt;1. Workload definition &lt;a href="#workload-definition" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The correct workload kind is used&lt;/strong&gt; — &lt;code&gt;Deployment&lt;/code&gt; for stateless replicas, &lt;code&gt;StatefulSet&lt;/code&gt; where stable identity and storage matter, &lt;code&gt;DaemonSet&lt;/code&gt; for per-node agents, &lt;code&gt;Job&lt;/code&gt;/&lt;code&gt;CronJob&lt;/code&gt; for finite work.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Images are referenced by digest and &lt;code&gt;imagePullPolicy&lt;/code&gt; is deliberate&lt;/strong&gt; — a mutable tag with &lt;code&gt;IfNotPresent&lt;/code&gt; means different nodes can run different code indefinitely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Replica count is at least two for anything that serves traffic&lt;/strong&gt; — a single replica means every node drain is an outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Labels follow a consistent scheme including app, component, version, and owner&lt;/strong&gt; — selectors, dashboards, network policies, and cost allocation all depend on them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pod template has no mutable configuration embedded in it&lt;/strong&gt; — configuration comes from &lt;code&gt;ConfigMap&lt;/code&gt; or &lt;code&gt;Secret&lt;/code&gt; references, so a config change is reviewable on its own.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A change to a &lt;code&gt;ConfigMap&lt;/code&gt; triggers a rollout&lt;/strong&gt; — either via a checksum annotation on the pod template or immutable, versioned config objects, otherwise pods keep the old values until something unrelated restarts them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The manifest is version controlled and applied by automation&lt;/strong&gt; — nothing reaches production through &lt;code&gt;kubectl edit&lt;/code&gt; on someone&amp;rsquo;s laptop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="resource-requests-and-limits"&gt;2. Resource requests and limits &lt;a href="#resource-requests-and-limits" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every container sets CPU and memory requests based on measured usage&lt;/strong&gt; — requests drive scheduling, and an unset request means the scheduler is guessing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Memory limits are set and equal to or close to the request for latency-sensitive workloads&lt;/strong&gt; — memory is incompressible, so exceeding a limit means an immediate &lt;code&gt;OOMKilled&lt;/code&gt;, not throttling.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;CPU limits are applied only where you intend throttling&lt;/strong&gt; — an aggressive CPU limit causes latency spikes through CFS throttling even while the node has idle capacity.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The resulting quality-of-service class is understood&lt;/strong&gt; — &lt;code&gt;BestEffort&lt;/code&gt; pods are evicted first under node pressure, which is rarely what you want for a production service.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Resource values have been revisited against real production usage&lt;/strong&gt; — copied-from-another-service values are the most common source of both waste and eviction.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Namespace &lt;code&gt;ResourceQuota&lt;/code&gt; and &lt;code&gt;LimitRange&lt;/code&gt; allow the workload&amp;rsquo;s peak, including during a rollout&lt;/strong&gt; — a rollout temporarily needs headroom for surge pods.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Requests are reconciled against the cluster&amp;rsquo;s node sizes&lt;/strong&gt; — a pod requesting more than any node can offer stays &lt;code&gt;Pending&lt;/code&gt; forever with an unhelpful message.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="health-probes-and-lifecycle"&gt;3. Health probes and lifecycle &lt;a href="#health-probes-and-lifecycle" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Readiness probes reflect the ability to serve a real request&lt;/strong&gt; — not a static &lt;code&gt;200&lt;/code&gt; from a handler that ignores dependency state.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Liveness probes do not check downstream dependencies&lt;/strong&gt; — a shared dependency outage otherwise restart-loops every healthy pod in the fleet and turns a partial failure into a total one.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A startup probe covers slow initialisation&lt;/strong&gt; — otherwise the liveness probe kills a container that was simply still warming up.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Probe timeouts, periods, and failure thresholds are tuned to real timings&lt;/strong&gt; — the defaults are frequently too aggressive for JVM and heavy framework start-ups.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt; exceeds the longest in-flight request plus drain time&lt;/strong&gt; — otherwise every deploy severs live connections.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;preStop&lt;/code&gt; hook gives the service mesh or load balancer time to deregister&lt;/strong&gt; — endpoint removal and container termination are concurrent, so a short sleep prevents requests being routed to a shutting-down pod.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The application handles &lt;code&gt;SIGTERM&lt;/code&gt; and stops accepting new work while draining&lt;/strong&gt; — verify by deleting a pod under load and watching for errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="scheduling-and-availability"&gt;4. Scheduling and availability &lt;a href="#scheduling-and-availability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;PodDisruptionBudget&lt;/code&gt; protects the workload during node drains&lt;/strong&gt; — without one, a cluster upgrade can evict every replica simultaneously.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The disruption budget cannot deadlock the cluster&lt;/strong&gt; — &lt;code&gt;minAvailable&lt;/code&gt; equal to the replica count blocks all voluntary evictions and stalls node maintenance.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Pod anti-affinity or topology spread constraints distribute replicas across nodes and zones&lt;/strong&gt; — two replicas on the same node is one node failure away from an outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Tolerations and node selectors are minimal and documented&lt;/strong&gt; — a broad toleration can land a workload on a node pool it was never meant to touch.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Priority classes are set deliberately for critical workloads&lt;/strong&gt; — so that under node pressure the right things are evicted.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Behaviour during a cluster autoscaler scale-down has been considered&lt;/strong&gt; — pods with local storage or restrictive budgets can block node removal indefinitely.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; a production workload with no readiness probe and no PodDisruptionBudget will drop traffic during every routine node upgrade. Neither is optional for a service that carries user requests.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="configuration-and-secrets"&gt;5. Configuration and secrets &lt;a href="#configuration-and-secrets" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets come from a secret manager through an operator or CSI driver, or are encrypted in git via a sealed-secrets style tool&lt;/strong&gt; — plain base64 in a manifest is encoding, not encryption.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Etcd encryption at rest is enabled on the cluster for secret resources&lt;/strong&gt; — confirm with the platform team rather than assuming.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets are mounted as files rather than environment variables where practical&lt;/strong&gt; — environment variables leak through crash dumps, child processes, and debug endpoints.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secret rotation does not require a manual redeploy&lt;/strong&gt; — either the application reloads mounted files or rotation triggers a controlled rollout.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Config differences between environments live in an overlay or values file, not in duplicated manifests&lt;/strong&gt; — divergence between copies is how staging stops predicting production.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No service account token is mounted unless the pod calls the Kubernetes API&lt;/strong&gt; — set &lt;code&gt;automountServiceAccountToken: false&lt;/code&gt; by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="pod-and-container-security"&gt;6. Pod and container security &lt;a href="#pod-and-container-security" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pod security context sets &lt;code&gt;runAsNonRoot&lt;/code&gt;, a numeric &lt;code&gt;runAsUser&lt;/code&gt;, and &lt;code&gt;fsGroup&lt;/code&gt; where volumes are written&lt;/strong&gt; — and the image actually supports it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;allowPrivilegeEscalation&lt;/code&gt; is false and all Linux capabilities are dropped, adding back only what is needed&lt;/strong&gt; — most workloads need none.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The root filesystem is read-only with explicit &lt;code&gt;emptyDir&lt;/code&gt; mounts for writable paths&lt;/strong&gt; — this removes the simplest persistence mechanism for an attacker.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A seccomp profile is applied&lt;/strong&gt; — &lt;code&gt;RuntimeDefault&lt;/code&gt; at minimum, which is not the default in older clusters.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No host namespaces, host paths, or privileged containers are used&lt;/strong&gt; — each of these is effectively a route to the node, and any exception needs written approval.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The namespace enforces Pod Security Admission at the restricted level where possible&lt;/strong&gt; — a policy that only warns will be ignored.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pod&amp;rsquo;s service account has a least-privilege &lt;code&gt;Role&lt;/code&gt; binding&lt;/strong&gt; — never &lt;code&gt;cluster-admin&lt;/code&gt;, and never a wildcard verb on a wildcard resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="networking-and-traffic"&gt;7. Networking and traffic &lt;a href="#networking-and-traffic" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A default-deny &lt;code&gt;NetworkPolicy&lt;/code&gt; exists in the namespace, with explicit allow rules&lt;/strong&gt; — without a default deny, every pod can reach every other pod in the cluster.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Egress is restricted to the dependencies the service actually needs&lt;/strong&gt; — including DNS, which is the rule people forget and then spend an hour debugging.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The &lt;code&gt;Service&lt;/code&gt; selector matches the pod labels and resolves to the expected endpoints&lt;/strong&gt; — verify with &lt;code&gt;kubectl get endpoints&lt;/code&gt;, since a typo produces a silent black hole.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Ingress terminates TLS with a certificate that renews automatically&lt;/strong&gt; — and the renewal has been observed to work at least once.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Timeouts and retry behaviour at the ingress or mesh layer are aligned with the application&amp;rsquo;s own timeouts&lt;/strong&gt; — mismatched layers turn one slow request into an amplified retry storm.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Session requirements are explicit&lt;/strong&gt; — if the application needs sticky sessions or long-lived connections, the load balancing configuration reflects that.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="storage-and-state"&gt;8. Storage and state &lt;a href="#storage-and-state" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;PersistentVolumeClaim&lt;/code&gt; storage classes are chosen deliberately, including the reclaim policy&lt;/strong&gt; — a &lt;code&gt;Delete&lt;/code&gt; policy on production data is one &lt;code&gt;kubectl delete&lt;/code&gt; from permanent loss.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Access modes match the topology&lt;/strong&gt; — a &lt;code&gt;ReadWriteOnce&lt;/code&gt; volume ties the pod to a single node and constrains rolling updates.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Volume expansion is supported and the procedure has been tested&lt;/strong&gt; — a full volume at 2am is not the moment to discover the storage class forbids resizing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backups of persistent volumes are configured and a restore has been performed&lt;/strong&gt; — snapshots that have never been restored are untested.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;StatefulSet&lt;/code&gt; scale-down behaviour is understood&lt;/strong&gt; — orphaned volumes remain and cost money, or are reclaimed and destroy data, depending on configuration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;emptyDir&lt;/code&gt; usage is bounded with a size limit&lt;/strong&gt; — an unbounded &lt;code&gt;emptyDir&lt;/code&gt; can fill the node disk and evict unrelated pods.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rollout-observability-and-operations"&gt;9. Rollout, observability, and operations &lt;a href="#rollout-observability-and-operations" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The rolling update strategy sets &lt;code&gt;maxUnavailable&lt;/code&gt; and &lt;code&gt;maxSurge&lt;/code&gt; deliberately&lt;/strong&gt; — and the cluster has capacity for the surge.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A failing rollout stops rather than replacing every healthy pod&lt;/strong&gt; — &lt;code&gt;progressDeadlineSeconds&lt;/code&gt; is set and the rollout status is checked by the pipeline.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback to the previous revision has been rehearsed&lt;/strong&gt; — and the revision history limit retains enough revisions to do it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Metrics, logs, and traces from the pod reach the platform&amp;rsquo;s collectors&lt;/strong&gt; — confirmed by looking at a dashboard, not by reading configuration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Horizontal autoscaling targets a metric that actually reflects load&lt;/strong&gt; — CPU is a poor proxy for an IO-bound service, and scaling on the wrong signal amplifies incidents.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Autoscaler minimum and maximum replicas are set, and the maximum is affordable and schedulable.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alerts exist for crash-looping pods, pending pods, and failed rollouts&lt;/strong&gt; — these are the platform-level symptoms that precede user-visible failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Workload definition&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Resource requests and limits&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Health probes and lifecycle&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Scheduling and availability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Configuration and secrets&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pod and container security&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Networking and traffic&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Storage and state&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Rollout, observability, and operations&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner before the workload is approved for production traffic.&lt;/p&gt;</description></item><item><title>Infrastructure as Code Review</title><link>https://checklists.metacog.co.kr/docs/devops/infrastructure-as-code/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/devops/infrastructure-as-code/</guid><description>&lt;p&gt;Infrastructure as code turns a cloud console mistake into a reviewable diff, but only if the review is real. The dangerous changes are rarely the ones that create resources; they are the ones that quietly destroy and recreate a database, widen a security group, or drift a state file away from reality. Use this when reviewing an infrastructure change and when assessing whether a repository&amp;rsquo;s practices are sound.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the engineer proposing the change plus a reviewer who did not write it. &lt;strong&gt;When:&lt;/strong&gt; on every pull request that touches infrastructure code, with the module and state sections reviewed quarterly.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="repository-structure-and-module-design"&gt;1. Repository structure and module design &lt;a href="#repository-structure-and-module-design" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Environments are separated by directory or workspace with their own state, not by a single configuration with a conditional&lt;/strong&gt; — a shared configuration means a staging change can plan destructive edits to production.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Reusable modules are versioned and consumed by version constraint, not by a branch reference&lt;/strong&gt; — a module sourced from &lt;code&gt;main&lt;/code&gt; changes under every consumer without a diff.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Module inputs are typed, validated, and documented&lt;/strong&gt; — an untyped map input is where undocumented behaviour accumulates.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Modules do not hard-code account IDs, regions, or environment names&lt;/strong&gt; — these belong in the calling configuration or the change is not reusable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Provider and language versions are pinned with a lockfile committed to the repository&lt;/strong&gt; — a provider minor release can change default behaviour and produce an unexpected plan.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The repository has an owner and &lt;code&gt;CODEOWNERS&lt;/code&gt; covers production configuration&lt;/strong&gt; — infrastructure code without an owner is applied by whoever is desperate enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="state-management"&gt;2. State management &lt;a href="#state-management" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;State is stored remotely with versioning enabled&lt;/strong&gt; — local state on a laptop is a single point of failure for the entire environment.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;State locking is enabled and has been observed to work&lt;/strong&gt; — two concurrent applies against one state produce corruption that is painful to unwind.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The state backend is encrypted at rest and access is restricted to the automation identity and a small break-glass group&lt;/strong&gt; — state files contain secrets in plain text, including generated passwords and keys.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;State backups exist and a restore from a previous state version has been rehearsed&lt;/strong&gt; — recovering from a bad &lt;code&gt;terraform state rm&lt;/code&gt; depends on this.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;State is split so that a blast radius is bounded&lt;/strong&gt; — one monolithic state for an entire organisation makes every change a high-risk change and every plan slow.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Manual state manipulation is documented and audited&lt;/strong&gt; — &lt;code&gt;state rm&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, and &lt;code&gt;taint&lt;/code&gt; are legitimate tools that also silently rewrite reality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-plan-output"&gt;3. The plan output &lt;a href="#the-plan-output" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The plan has been read line by line, not just the summary counts&lt;/strong&gt; — the resource count tells you nothing about whether the right resources are changing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every destroy and every replace in the plan is justified in the pull request description&lt;/strong&gt; — a forced replacement of a database, a load balancer, or a key is the classic accidental outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The cause of each replacement is understood&lt;/strong&gt; — which attribute forces new, and whether a &lt;code&gt;lifecycle&lt;/code&gt; block or a change of approach avoids it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No unexplained changes appear that the diff does not account for&lt;/strong&gt; — unexplained drift means someone changed something by hand, and applying will revert it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The plan is generated against the same state and variables that will be applied&lt;/strong&gt; — a plan file is saved and applied, rather than re-planning at apply time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data source lookups resolve to what you expect&lt;/strong&gt; — a filter that matches the wrong AMI or the wrong subnet produces a plan that looks harmless.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; never approve a plan containing a resource replacement you cannot explain. Replacement of stateful resources — databases, volumes, certificates, load balancers with static addresses — is data loss or an outage, and it is the most common cause of self-inflicted infrastructure incidents.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="secrets-and-sensitive-data"&gt;4. Secrets and sensitive data &lt;a href="#secrets-and-sensitive-data" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No credential, key, or certificate is committed in a &lt;code&gt;.tf&lt;/code&gt; or &lt;code&gt;.tfvars&lt;/code&gt; file&lt;/strong&gt; — including in examples and test fixtures.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets are read at apply time from a secret manager, not passed as plain variables&lt;/strong&gt; — and the reference, not the value, lives in the repository.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Outputs containing sensitive values are marked sensitive&lt;/strong&gt; — otherwise they are printed in logs and stored in plan artefacts.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Generated passwords are written directly to a secret manager rather than surfaced as outputs&lt;/strong&gt; — anything in state or output is readable by anyone with state access.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Plan artefacts are treated as sensitive and have a short retention&lt;/strong&gt; — a saved plan can contain the values being written.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secret scanning runs on the repository history, not only on new commits&lt;/strong&gt; — infrastructure repositories accumulate old test credentials.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security-and-compliance-of-the-resources"&gt;5. Security and compliance of the resources &lt;a href="#security-and-compliance-of-the-resources" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A policy-as-code check runs in the pipeline and blocks on violations&lt;/strong&gt; — encryption at rest, no public object storage, no unrestricted ingress, mandatory tags.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No security group, firewall rule, or bucket policy allows &lt;code&gt;0.0.0.0/0&lt;/code&gt; except where explicitly documented and approved&lt;/strong&gt; — and never for administrative ports.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;IAM policies are least-privilege with no wildcard action on a wildcard resource&lt;/strong&gt; — an over-broad role created by IaC is durable in a way an ad-hoc one is not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Encryption at rest is enabled for every storage, database, and queue resource, with the key management model chosen deliberately.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Logging and audit trails are enabled on the resources being created&lt;/strong&gt; — a resource created without logging is invisible during an incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Public exposure of any new endpoint is intentional and reviewed&lt;/strong&gt; — load balancers, managed database public accessibility, and function URLs each default differently.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deletion protection is enabled on stateful production resources&lt;/strong&gt; — it is the last defence against a mistaken destroy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="change-safety-and-reversibility"&gt;6. Change safety and reversibility &lt;a href="#change-safety-and-reversibility" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The rollback path is described in the pull request&lt;/strong&gt; — reverting the commit is not always sufficient when data or DNS is involved.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;prevent_destroy&lt;/code&gt; or the equivalent guard is set on irreplaceable resources&lt;/strong&gt; — databases, root DNS zones, and key management keys.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Changes are applied to a non-production environment first and the result observed&lt;/strong&gt; — an environment that never receives the change first is not a testing environment.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The change is small enough to reason about&lt;/strong&gt; — combining a provider upgrade, a refactor, and a functional change in one pull request makes the plan unreadable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Resource moves use a &lt;code&gt;moved&lt;/code&gt; block or a documented state move rather than a destroy and recreate&lt;/strong&gt; — renaming a resource in code otherwise destroys the real one.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependencies between changes are sequenced explicitly&lt;/strong&gt; — if a network change must land before a workload change, say so and order the merges.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Timing is considered&lt;/strong&gt; — infrastructure changes touching networking, DNS, or certificates should not land immediately before a peak period or a holiday.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="automation-and-access-control"&gt;7. Automation and access control &lt;a href="#automation-and-access-control" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Apply runs in a pipeline with a federated short-lived identity, not from a workstation with a long-lived key&lt;/strong&gt; — and the pipeline identity is the only one with production write access under normal conditions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Production apply requires an explicit approval separate from the code review&lt;/strong&gt; — plan on pull request, apply on merge with a gate.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Direct human write access to production cloud accounts is break-glass only, time-limited, and alerted on&lt;/strong&gt; — otherwise drift is inevitable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Drift detection runs on a schedule and reports differences between code and reality&lt;/strong&gt; — drift discovered during an incident is drift discovered too late.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Formatting, validation, and linting run automatically&lt;/strong&gt; — so reviews discuss behaviour rather than whitespace.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline fails closed&lt;/strong&gt; — an error in the plan step must not proceed to apply.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="documentation-and-operability"&gt;8. Documentation and operability &lt;a href="#documentation-and-operability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The repository README explains how to run a plan, where state lives, and who to ask&lt;/strong&gt; — onboarding cost is a reliability property.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every resource carries required tags&lt;/strong&gt; — owner, environment, service, and cost centre, enforced by policy rather than by convention.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cost impact of the change is estimated for anything that adds significant resources&lt;/strong&gt; — instance families, provisioned throughput, and inter-zone traffic in particular.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Architecture documentation is updated in the same change&lt;/strong&gt; — a diagram that lags the code is worse than no diagram.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deprecated resources and modules are removed rather than left commented out&lt;/strong&gt; — commented-out infrastructure is ambiguous during an incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The change is recorded in the change management system where one applies&lt;/strong&gt; — with the plan output attached as evidence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Repository structure and module design&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;State management&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;The plan output&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Secrets and sensitive data&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Security and compliance of the resources&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Change safety and reversibility&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Automation and access control&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Documentation and operability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner before the change is applied to production.&lt;/p&gt;</description></item><item><title>Release Day Runbook</title><link>https://checklists.metacog.co.kr/docs/devops/release-day/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/devops/release-day/</guid><description>&lt;p&gt;Release day goes badly when decisions that should have been made yesterday are made under time pressure with an audience watching. This runbook is ordered by time rather than by topic: work down it from the day before the release to the point where the release is declared done. Assign a single release conductor who owns the sequence and the go/no-go call.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; a named release conductor, with the owning engineers and the on-call responder present. &lt;strong&gt;When:&lt;/strong&gt; starting the day before the deploy window and continuing through the soak period.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="t-1-day-scope-and-readiness"&gt;1. T-1 day: scope and readiness &lt;a href="#t-1-day-scope-and-readiness" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The release contents are frozen and the change list is published&lt;/strong&gt; — every merged commit, with the pull requests and tickets it closes, so nobody discovers an unexpected change mid-incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every change in the release has been through code review and the pipeline is green on the release commit&lt;/strong&gt; — a green build from an earlier commit does not count.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The exact artefact digest to be deployed is recorded&lt;/strong&gt; — not a tag, so the thing you tested and the thing you ship are provably identical.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The release has been running in a staging environment with production-like data and traffic for long enough to expose slow failures&lt;/strong&gt; — memory leaks and connection pool exhaustion do not appear in a ten-minute smoke test.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Risky changes are behind feature flags that default to off&lt;/strong&gt; — this converts a deploy decision into a separate, reversible enablement decision.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Database migrations are backward compatible and have been timed against a production-sized dataset&lt;/strong&gt; — a migration that locks a large table for minutes is an outage regardless of how correct it is.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any dependency on another team&amp;rsquo;s release is confirmed in writing, including its ordering.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="t-1-day-communication-and-logistics"&gt;2. T-1 day: communication and logistics &lt;a href="#t-1-day-communication-and-logistics" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The deploy window is agreed and published&lt;/strong&gt; — with the timezone stated explicitly and confirmed against any change freeze.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The window avoids peak traffic, the end of a shift, and the hours before a weekend or holiday&lt;/strong&gt; — deploying at 5pm on a Friday leaves nobody to watch the soak.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Named people are assigned to each role&lt;/strong&gt; — release conductor, deployer, verifier, and the on-call responder who will own anything that goes wrong afterwards.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Everyone in those roles has confirmed availability for the deploy window plus the soak period.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Support, customer-facing, and dependent teams have been notified with what user-visible change to expect&lt;/strong&gt; — including anything they should not raise as a bug.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The incident channel and bridge are created in advance&lt;/strong&gt; — creating communication channels during an incident wastes the first ten minutes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Anything requiring a maintenance window or a status page notice has been scheduled and drafted.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="t-1-day-rollback-preparation"&gt;3. T-1 day: rollback preparation &lt;a href="#t-1-day-rollback-preparation" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The rollback procedure is written down as concrete commands, not as a description&lt;/strong&gt; — the person running it may not be the person who wrote it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The previous artefact version and its digest are recorded and confirmed to still exist in the registry&lt;/strong&gt; — retention policies have deleted rollback targets before.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback has been rehearsed in staging within the last release cycle&lt;/strong&gt; — an unrehearsed rollback is a hypothesis.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The data implications of a rollback are understood&lt;/strong&gt; — if the new version writes data or schema the old version cannot read, rollback is not actually available and you need a forward-fix plan instead.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The rollback trigger conditions are written down in advance&lt;/strong&gt; — specific thresholds such as error rate above a stated value for a stated duration, not a judgement call made while stressed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The maximum acceptable time to decide on rollback is agreed&lt;/strong&gt; — typically minutes, and stated before anyone is emotionally invested in the release.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A feature flag kill switch is tested if the release relies on one&lt;/strong&gt; — verify it takes effect without a redeploy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="go-no-go-immediately-before-the-window"&gt;4. Go/no-go, immediately before the window &lt;a href="#go-no-go-immediately-before-the-window" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline is still green and no new commits have landed on the release branch since the freeze.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No active incident is in progress in this service or its critical dependencies&lt;/strong&gt; — check the incident tracker rather than assuming.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependent services and infrastructure are healthy&lt;/strong&gt; — a deploy into a degraded platform makes attribution impossible when something breaks.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No conflicting change is being applied at the same time&lt;/strong&gt; — infrastructure, DNS, certificate, or database maintenance from another team.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Current error rate, latency, and traffic levels are captured as the pre-deploy baseline&lt;/strong&gt; — you cannot judge a regression without the number from before.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All named roles are present and acknowledge the go decision explicitly&lt;/strong&gt; — silence is not consent.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The conductor states the abort criteria out loud before starting&lt;/strong&gt; — so everyone is holding the same decision rule.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;No-go conditions:&lt;/strong&gt; an active incident anywhere in the critical dependency chain, a rollback path that has not been verified, or a key person unavailable for the soak period. Any one of these is enough to postpone. Postponing costs a day; a bad release with nobody watching costs far more.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="deploy-window-execution"&gt;5. Deploy window: execution &lt;a href="#deploy-window-execution" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every step is announced in the release channel as it starts and as it completes&lt;/strong&gt; — with timestamps, because the timeline is what you will reconstruct later.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backward-compatible schema migrations run and complete before the application deploy&lt;/strong&gt; — expand first, contract in a later release.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Migration duration and lock behaviour are watched live&lt;/strong&gt; — abort criteria for the migration are separate from those for the deploy.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The deploy uses the recorded artefact digest through the normal automated pipeline&lt;/strong&gt; — no manual steps, no local builds, no shortcuts because it is a special release.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The rollout is progressive and paused at the first stage for verification&lt;/strong&gt; — canary, one instance, or a small traffic percentage before proceeding.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Canary health is compared against the rest of the fleet, not against the baseline alone&lt;/strong&gt; — a fleet-wide change in traffic pattern otherwise looks like a canary regression.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deploy progress is watched actively, not started and left&lt;/strong&gt; — the person who ran the command stays until the rollout completes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;If anything unexpected occurs, the rollout is paused rather than pushed through&lt;/strong&gt; — a paused rollout is cheap; a completed bad rollout is not.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="immediately-after-rollout-verification"&gt;6. Immediately after rollout: verification &lt;a href="#immediately-after-rollout-verification" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The running version is confirmed on every instance or replica&lt;/strong&gt; — a partially completed rollout serving two versions is a real and frequently missed state.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The critical user journey is exercised end to end by a human, not only by a synthetic probe&lt;/strong&gt; — log in, complete the primary action, confirm the result persisted.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Error rate, latency percentiles, and traffic are compared against the pre-deploy baseline&lt;/strong&gt; — looking at absolute values without the baseline hides small but real regressions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Application logs are checked for new error signatures&lt;/strong&gt; — a new stack trace at low volume is often the first sign of a problem that grows with traffic.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependency health is checked from the caller&amp;rsquo;s perspective&lt;/strong&gt; — connection pool saturation, downstream error rates, and queue depth.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Background jobs, scheduled tasks, and consumers are confirmed to be running and keeping up&lt;/strong&gt; — these fail quietly because no user is waiting on them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any feature flags intended to be enabled with this release are turned on one at a time, with verification between each.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cache and configuration invalidation has taken effect where required&lt;/strong&gt; — including content delivery network caches for front-end changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="soak-period-monitoring"&gt;7. Soak period: monitoring &lt;a href="#soak-period-monitoring" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A defined soak duration is agreed before the release is declared done&lt;/strong&gt; — long enough to cover at least one full traffic cycle for the service, and never less than the time it takes for slow failure modes to appear.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A named person is actively watching dashboards for the soak, not relying on alerts alone&lt;/strong&gt; — alerts catch what you predicted; a human catches what you did not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Resource saturation trends are watched&lt;/strong&gt; — memory growth, file descriptors, thread counts, and connection pools reveal leaks that error rates do not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Latency at the tail is watched, not just the average&lt;/strong&gt; — p99 regressions affect the users most likely to complain publicly.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Business metrics are watched alongside technical ones&lt;/strong&gt; — sign-ups, orders, or messages sent, because a technically healthy release can still break the product.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Support and customer-facing channels are monitored for reports that dashboards will not show&lt;/strong&gt; — a broken payment flow for one card type is invisible in aggregate.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The on-call responder is briefed on what changed and what to do about it before the conductor stands down.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rollback-decision"&gt;8. Rollback decision &lt;a href="#rollback-decision" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pre-agreed trigger conditions are applied as written, without renegotiation&lt;/strong&gt; — the whole purpose of setting them in advance is to remove judgement under pressure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback is the default response to an unexplained regression&lt;/strong&gt; — diagnose after service is restored, not before.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The decision is made within the agreed time limit&lt;/strong&gt; — an hour spent debugging a live regression is an hour of user impact you chose to accept.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;If rollback is not possible because of data or schema changes, the forward-fix path is executed with the same discipline&lt;/strong&gt; — including its own verification and abort criteria.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback execution is verified the same way the deploy was&lt;/strong&gt; — version confirmed everywhere, critical journey exercised, metrics compared to baseline.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The decision, its reasoning, and its timeline are recorded in the release channel as they happen.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;If rolling back, feature flags enabled during the release are also reverted&lt;/strong&gt; — a flag left on against an old binary is an untested combination.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="release-closure"&gt;9. Release closure &lt;a href="#release-closure" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The release is explicitly declared complete or rolled back in the release channel&lt;/strong&gt; — an ambiguous ending leaves the on-call responder unsure of the current state.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The deployed version, artefact digest, and timestamp are recorded in the change log or change management system.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Stakeholders and support teams are notified of the outcome&lt;/strong&gt; — including anything that behaves differently than announced.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Temporary measures are reverted&lt;/strong&gt; — paused autoscaling, silenced alerts, extended timeouts, and any maintenance page.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Feature flags that are now permanent are scheduled for removal&lt;/strong&gt; — a flag that outlives its purpose is a permanently untested code path.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Anything that went wrong, including near misses, is recorded for the retrospective&lt;/strong&gt; — a release that worked out despite a scare still contains the lesson.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Improvements to this runbook are made while the details are fresh&lt;/strong&gt; — the best time to fix a runbook is the day you used it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;T-1 day: scope and readiness&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;T-1 day: communication and logistics&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;T-1 day: rollback preparation&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Go/no-go decision&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Deploy window: execution&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Post-rollout verification&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Soak period monitoring&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Rollback decision&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Release closure&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner, and treat any unresolved item in the go/no-go or rollback preparation sections as a no-go rather than a follow-up.&lt;/p&gt;</description></item><item><title>Cloud Landing Zone Setup</title><link>https://checklists.metacog.co.kr/docs/cloud/aws-landing-zone/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/cloud/aws-landing-zone/</guid><description>&lt;p&gt;A landing zone is the part of your cloud estate that nobody wants to rebuild later. Account boundaries, identity, network address space, and the audit trail are all decisions that become progressively more expensive to change once real workloads depend on them. This checklist is written primarily against AWS, with the Azure and Google Cloud equivalents called out where the concept maps cleanly, and assumes you are building the foundation before the first production workload rather than retrofitting one.&lt;/p&gt;</description></item><item><title>Cloud Cost Optimisation</title><link>https://checklists.metacog.co.kr/docs/cloud/cloud-cost-optimization/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/cloud/cloud-cost-optimization/</guid><description>&lt;p&gt;Most cloud cost programmes fail in the same way: someone is asked to cut 30%, they turn off a few instances, and six months later spend is back where it started. Durable savings come from attribution first, then waste removal, then rightsizing, then commitments — in that order, because buying a three-year commitment for an oversized fleet locks in the waste. Work through this in sequence rather than jumping to the discount instruments.&lt;/p&gt;</description></item><item><title>Cloud Migration Cutover</title><link>https://checklists.metacog.co.kr/docs/cloud/cloud-migration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/cloud/cloud-migration/</guid><description>&lt;p&gt;Migration projects rarely fail at the technology; they fail in the hour when traffic actually moves. This checklist is ordered as a timeline rather than by topic — assessment, dependency mapping, target build, rehearsal, freeze, the cutover window itself, validation, and rollback — so it can be worked through as the plan takes shape and then read top to bottom on the day. Adapt the timings to your change window, but do not reorder the phases.&lt;/p&gt;</description></item><item><title>Serverless Readiness</title><link>https://checklists.metacog.co.kr/docs/cloud/serverless-readiness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/cloud/serverless-readiness/</guid><description>&lt;p&gt;Serverless removes the servers, not the distributed systems problems. What it changes is which problems bite you: concurrency limits instead of instance counts, at-least-once delivery instead of a request-response call, and a cost model where an infinite retry loop bills by the millisecond. This checklist covers function-as-a-service workloads on AWS Lambda, Azure Functions, and Google Cloud Run functions, along with the event sources that trigger them.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the owning engineering team, with a reviewer who has operated an event-driven system before. &lt;strong&gt;When:&lt;/strong&gt; before the workload takes production traffic, and again after any change to its event sources or concurrency configuration.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="workload-fit"&gt;1. Workload fit &lt;a href="#workload-fit" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The workload&amp;rsquo;s execution profile fits within the platform&amp;rsquo;s timeout and payload limits&lt;/strong&gt; — with headroom, because a job that takes 12 minutes against a 15-minute ceiling will time out the first time a dependency is slow.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Long-running or steady high-throughput work has been compared against containers on cost and latency&lt;/strong&gt; — serverless wins on spiky and low-duty-cycle workloads; a service at constant high utilisation is usually cheaper and faster on provisioned compute.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The function does one thing&lt;/strong&gt; — a single function fronting a dozen routes with a switch statement inherits the union of every route&amp;rsquo;s permissions, memory profile, and blast radius.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Orchestration of multi-step workflows uses a workflow service, not chained function invocations&lt;/strong&gt; — Step Functions, Durable Functions, or Workflows give you state, retries, and visibility that a function calling a function does not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;State lives outside the function&lt;/strong&gt; — anything cached in the execution environment survives only until the platform recycles it, which it will do without warning and at the worst time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependencies that hold connection pools have a strategy&lt;/strong&gt; — a relational database behind a function that scales to a thousand concurrent executions needs a proxy or a data API, or it will exhaust connections.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="configuration-and-packaging"&gt;2. Configuration and packaging &lt;a href="#configuration-and-packaging" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Memory is tuned by measurement, not left at the default&lt;/strong&gt; — CPU is allocated proportionally to memory, so more memory often reduces both duration and total cost; run a power-tuning sweep rather than guessing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Timeout is set to a realistic ceiling per function, not the platform maximum&lt;/strong&gt; — a long timeout means a stuck invocation bills for minutes and holds a concurrency slot the whole time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The deployment package excludes development dependencies, tests, and the provider SDK where the runtime supplies it&lt;/strong&gt; — package size directly affects cold start.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Shared code is in a layer or an internal package with a pinned version&lt;/strong&gt; — a layer that changes underneath deployed functions is an untracked production change.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The runtime version is current and there is a plan for its deprecation date&lt;/strong&gt; — providers force-migrate deprecated runtimes on a published schedule, and being surprised by it is avoidable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Configuration comes from environment variables or a parameter store, and secrets from a secret manager&lt;/strong&gt; — with the fetch cached outside the handler so it does not run on every invocation.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Ephemeral storage size and usage are known&lt;/strong&gt; — the writable temporary directory is shared across invocations in the same environment and does not empty itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cold-starts-and-latency"&gt;3. Cold starts and latency &lt;a href="#cold-starts-and-latency" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cold start latency has been measured, not assumed&lt;/strong&gt; — measure the p99 of the initialisation phase separately from execution, because averages hide it entirely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Initialisation work happens outside the handler&lt;/strong&gt; — SDK clients, database connections, and configuration loading belong in the module scope so they are reused across warm invocations.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The cold start contribution to the user-facing latency SLO is quantified&lt;/strong&gt; — for an asynchronous consumer it may be irrelevant; for a synchronous API path it may be the dominant term.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Provisioned or minimum-instance concurrency is configured where cold start would breach the SLO&lt;/strong&gt; — and its cost is understood, since it bills whether or not it is used.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Functions in a VPC have been checked for the network initialisation penalty and only use a VPC when they need private resources.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Ahead-of-time compilation or a lighter runtime has been considered for latency-critical paths&lt;/strong&gt; — startup-optimised runtimes and native images cut initialisation by an order of magnitude for JVM and .NET workloads.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="concurrency-scaling-and-downstream-protection"&gt;4. Concurrency, scaling, and downstream protection &lt;a href="#concurrency-scaling-and-downstream-protection" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The account-level concurrency limit is known and the headroom across all functions is calculated&lt;/strong&gt; — concurrency is a shared account quota, so one runaway function can starve every other function in the account.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Reserved concurrency is set on critical functions to guarantee capacity&lt;/strong&gt; — and on risky ones to cap their blast radius.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Downstream capacity has been checked against the function&amp;rsquo;s maximum concurrency&lt;/strong&gt; — a function scaling to 1,000 concurrent executions against a database that accepts 100 connections is a self-inflicted outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Burst scaling behaviour is understood for the region&lt;/strong&gt; — platforms scale in bursts then at a rate limit, so a traffic spike produces throttling before it produces capacity.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Throttling is monitored and alerted on&lt;/strong&gt; — a throttled synchronous invocation is a user-facing error; a throttled asynchronous one is a delayed or eventually dropped event.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Batch size and batching window for stream and queue sources are tuned deliberately&lt;/strong&gt; — larger batches improve throughput and cost but increase the amount of work lost or retried on a single failure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A load test has driven the function to its concurrency ceiling&lt;/strong&gt; — the interesting failures all happen at the limit, not below it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="event-sources-delivery-and-idempotency"&gt;5. Event sources, delivery, and idempotency &lt;a href="#event-sources-delivery-and-idempotency" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Delivery semantics are known per event source and written down&lt;/strong&gt; — at-least-once for most queue and stream sources means duplicate invocations are normal operation, not an incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every handler with a side effect is idempotent&lt;/strong&gt; — deduplicate on an event identifier in a store with a TTL, or make the write naturally idempotent; retries will otherwise double-charge a customer.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Ordering assumptions are explicit&lt;/strong&gt; — only partitioned stream sources preserve order, and only within a partition; standard queues do not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Partition or shard key choice distributes load evenly&lt;/strong&gt; — a hot key serialises an entire workload behind one consumer regardless of how much the platform scales.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Event schemas are versioned and consumers tolerate unknown fields&lt;/strong&gt; — a producer adding a field should never break a consumer.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Queue visibility timeout is at least the function timeout, usually a multiple of it&lt;/strong&gt; — a shorter visibility timeout means the message is redelivered while the first invocation is still processing it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Stream consumers handle a poison record&lt;/strong&gt; — without bisect-on-error or a failure destination, one unparseable record blocks its shard until the retention period expires.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Fan-out patterns are checked for accidental recursion&lt;/strong&gt; — a function writing to the bucket that triggers it is the classic infinite loop, and it bills continuously until someone notices.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; a function that writes to its own trigger source without a guard is a recursive invocation loop. Verify the write path cannot re-trigger the function, and set reserved concurrency as a hard ceiling before deploying.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="failure-handling"&gt;6. Failure handling &lt;a href="#failure-handling" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every asynchronous invocation path has a dead letter queue or an on-failure destination&lt;/strong&gt; — without one, an event that fails all retries is silently discarded and you will never know it existed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The dead letter queue has an alarm on depth greater than zero and a documented owner&lt;/strong&gt; — an unmonitored DLQ is a data loss mechanism with extra steps.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A tested procedure exists for inspecting and replaying dead-lettered events&lt;/strong&gt; — replay is not automatic and writing the tooling during an incident is too late.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retry counts and backoff are configured deliberately per source&lt;/strong&gt; — the platform defaults are rarely right, and retrying a permanent validation failure twice is wasted spend plus delay.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Transient and permanent errors are distinguished in code&lt;/strong&gt; — a malformed payload should go straight to the DLQ; a downstream timeout should retry.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Partial batch failure reporting is implemented for batched sources&lt;/strong&gt; — otherwise one bad record in a batch of a hundred causes all hundred to be reprocessed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Downstream calls have explicit timeouts shorter than the function timeout&lt;/strong&gt; — a default-infinite SDK client will burn the entire timeout and then fail with no useful error.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Circuit-breaking or shedding protects a failing downstream&lt;/strong&gt; — thousands of concurrent executions all retrying a struggling dependency will keep it down.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security"&gt;7. Security &lt;a href="#security" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each function has its own execution role scoped to the specific resources it uses&lt;/strong&gt; — a shared role across functions grants every function the union of all permissions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Wildcard resource ARNs have been eliminated or justified&lt;/strong&gt; — &lt;code&gt;Resource: &amp;quot;*&amp;quot;&lt;/code&gt; on a data action is the finding every audit will raise.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Resource policies restrict who can invoke the function&lt;/strong&gt; — the invoker principal, source ARN, and source account should all be constrained.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Input from event sources is validated and treated as untrusted&lt;/strong&gt; — an event body from a queue is user input that has travelled through one more hop.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Secrets are fetched at runtime from a secret manager, cached with a bounded TTL, and never logged&lt;/strong&gt; — environment variables are visible to anyone with read access to the function configuration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependencies are scanned in the pipeline and the package is rebuilt on a schedule&lt;/strong&gt; — a function deployed a year ago is still running a year-old dependency tree.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Functions in a VPC use security groups that permit only the required egress&lt;/strong&gt; — and a function that needs no private resource stays out of the VPC.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;API-fronted functions have authentication, authorisation, and rate limiting at the gateway&lt;/strong&gt; — the gateway is the only place you can reject traffic before it costs you an invocation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="observability"&gt;8. Observability &lt;a href="#observability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Structured JSON logging is used with a correlation identifier propagated from the event&lt;/strong&gt; — free-text logs across hundreds of short-lived invocations are unsearchable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Log retention is set explicitly on every log group&lt;/strong&gt; — the default in several platforms is to never expire, and high-volume function logs become a significant line item.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Distributed tracing is enabled and covers the asynchronous hops&lt;/strong&gt; — an event-driven system where the trace stops at the queue tells you nothing about end-to-end latency.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alarms cover errors, throttles, duration approaching timeout, and DLQ depth&lt;/strong&gt; — duration approaching timeout is the leading indicator that catches the failure before it happens.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Business-level metrics are emitted from the function&lt;/strong&gt; — events processed, events rejected, and end-to-end age of the oldest processed event.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Iterator age or queue age is alerted on for stream and queue consumers&lt;/strong&gt; — a consumer keeping up at a steadily growing lag is the failure mode invisible to error-rate alerts.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A method exists to reproduce an invocation locally from a captured event payload&lt;/strong&gt; — debugging by redeploying is unbearably slow.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="deployment-cost-and-operations"&gt;9. Deployment, cost, and operations &lt;a href="#deployment-cost-and-operations" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Infrastructure and functions are deployed together as code from a pipeline&lt;/strong&gt; — a function edited in the console is a change nobody can review or reproduce.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deployments are progressive with automatic rollback on an error-rate alarm&lt;/strong&gt; — weighted aliases or traffic-splitting revisions make this cheap, so there is no reason not to.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Function versions are immutable and aliases point at a specific version&lt;/strong&gt; — deploying to a mutable latest pointer removes your ability to roll back precisely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cost per million invocations has been estimated including the event sources and log ingestion&lt;/strong&gt; — the function is often the cheapest part of the bill; the queue, gateway, and logs are not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A budget alarm and a concurrency ceiling limit the cost of a runaway loop&lt;/strong&gt; — serverless removes the natural ceiling that a fixed fleet used to provide.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A runbook covers how to stop the workload&lt;/strong&gt; — setting reserved concurrency to zero or disabling the event source mapping is the emergency brake, and the on-call engineer must know which one applies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Workload fit&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Configuration and packaging&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cold starts and latency&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Concurrency, scaling, and downstream protection&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Event sources, delivery, and idempotency&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Failure handling&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Security&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Observability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Deployment, cost, and operations&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with an owner before the workload is approved for production traffic.&lt;/p&gt;</description></item><item><title>Code Review</title><link>https://checklists.metacog.co.kr/docs/development/code-review/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/code-review/</guid><description>&lt;p&gt;Code review is the cheapest place to catch a defect and the most expensive place to argue about brace style. This checklist is what a reviewer should hold in their head while reading a change: does it do what it claims, will it survive contact with production, and can the next person understand it. It also covers the author&amp;rsquo;s side, because most slow reviews are caused by a pull request that was never made reviewable.&lt;/p&gt;</description></item><item><title>REST API Design</title><link>https://checklists.metacog.co.kr/docs/development/rest-api-design/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/rest-api-design/</guid><description>&lt;p&gt;An HTTP API is the hardest kind of code to change, because the people who depend on it do not deploy when you do. Most of the cost of a bad API is paid years later, in compatibility shims and support tickets. Work through this before the first consumer outside your team integrates, and again before any version is declared stable.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the owning team plus one reviewer who will have to consume the API. &lt;strong&gt;When:&lt;/strong&gt; at design review, before the first endpoint ships, and again before the API is published externally.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="resources-and-url-structure"&gt;1. Resources and URL structure &lt;a href="#resources-and-url-structure" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Paths name resources, not actions&lt;/strong&gt; — &lt;code&gt;POST /orders/42/refunds&lt;/code&gt; beats &lt;code&gt;POST /refundOrder&lt;/code&gt;, because the resource model composes and the verb list does not.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Collections are plural and consistently cased&lt;/strong&gt; — pick one convention for multi-word segments and apply it everywhere; mixed &lt;code&gt;user_profiles&lt;/code&gt; and &lt;code&gt;userProfiles&lt;/code&gt; guarantees integration bugs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Nesting stops at one level&lt;/strong&gt; — &lt;code&gt;/customers/{id}/orders&lt;/code&gt; is useful, &lt;code&gt;/customers/{id}/orders/{id}/lines/{id}/taxes&lt;/code&gt; forces callers to know an identifier hierarchy they should not need.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Identifiers in URLs are opaque to the client&lt;/strong&gt; — exposing an auto-incrementing primary key leaks your record count and invites enumeration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A resource has exactly one canonical URL&lt;/strong&gt; — multiple aliases fragment caching, logging, and authorisation rules.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Genuinely non-CRUD operations are modelled as subordinate resources&lt;/strong&gt; — a state transition can be a &lt;code&gt;POST&lt;/code&gt; to &lt;code&gt;/subscriptions/{id}/cancellations&lt;/code&gt; rather than an RPC verb bolted onto the path.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Trailing slash, casing, and encoding behaviour is defined and consistent&lt;/strong&gt; — decide whether &lt;code&gt;/Orders&lt;/code&gt; redirects or 404s, and make the router enforce it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="http-semantics"&gt;2. HTTP semantics &lt;a href="#http-semantics" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Method semantics are respected&lt;/strong&gt; — &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;HEAD&lt;/code&gt; never change state, &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; are idempotent, and &lt;code&gt;POST&lt;/code&gt; is the only method allowed to be neither safe nor idempotent.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;GET&lt;/code&gt; requests carry no request body and no side effects&lt;/strong&gt; — intermediaries are entitled to retry, cache, and prefetch them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Status codes distinguish the failure classes callers must handle differently&lt;/strong&gt; — 400 for a malformed request, 401 for missing or invalid authentication, 403 for authenticated but not permitted, 404 for absent, 409 for a state conflict, 422 for semantically invalid content, 429 for rate limiting.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;201 responses carry a &lt;code&gt;Location&lt;/code&gt; header&lt;/strong&gt; — the caller should not have to guess the URL of what it just created.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;204 is used only when there is genuinely no body&lt;/strong&gt; — returning 200 with an empty body forces every client to special-case parsing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;5xx is reserved for server faults&lt;/strong&gt; — returning 500 for a validation failure trains callers to retry something that will never succeed and pollutes your error budget.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Long-running work returns 202 with a status resource&lt;/strong&gt; — a synchronous request that blocks for minutes will be killed by some proxy in the path.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Partial updates use a defined patch format&lt;/strong&gt; — &lt;code&gt;PATCH&lt;/code&gt; with an ad-hoc merge dialect makes clearing a field to null indistinguishable from omitting it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="request-and-response-payloads"&gt;3. Request and response payloads &lt;a href="#request-and-response-payloads" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;One media type is the default and it is negotiated properly&lt;/strong&gt; — honour &lt;code&gt;Accept&lt;/code&gt;, and return 415 for an unsupported &lt;code&gt;Content-Type&lt;/code&gt; rather than silently attempting to parse it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Field naming is consistent across every endpoint&lt;/strong&gt; — one casing convention, and the same concept has the same field name everywhere.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Timestamps are RFC 3339 in UTC with an explicit offset&lt;/strong&gt; — a bare local datetime is the most common cross-team integration defect.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Monetary amounts carry an explicit currency and use a string or minor-unit integer&lt;/strong&gt; — a JSON number for money will be parsed as a float by somebody.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Enumerated values are documented and clients are told to tolerate unknown members&lt;/strong&gt; — otherwise adding a value becomes a breaking change.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Top-level responses are objects, never bare arrays&lt;/strong&gt; — an object leaves room to add pagination metadata later without breaking parsers.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Absent, null, and empty are distinguished deliberately&lt;/strong&gt; — document what each means for every optional field, because callers will infer something.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Request bodies have a maximum size enforced before parsing&lt;/strong&gt; — unbounded parsing is a trivially exploitable denial of service.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="errors"&gt;4. Errors &lt;a href="#errors" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Errors use a single machine-readable structure across the whole API&lt;/strong&gt; — RFC 9457 problem details is a reasonable default and saves every client writing a bespoke parser.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every error carries a stable, documented error code&lt;/strong&gt; — clients must be able to branch on something other than the human-readable message, which you will want to reword.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Validation errors identify the offending field&lt;/strong&gt; — a 400 saying only &amp;ldquo;invalid request&amp;rdquo; turns integration into guesswork.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Error messages do not leak internals&lt;/strong&gt; — stack traces, SQL fragments, internal hostnames, and library versions are reconnaissance material.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Errors include a correlation identifier that also appears in your logs&lt;/strong&gt; — so a support ticket can be traced without asking the caller to reproduce.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retryable and non-retryable failures are distinguishable&lt;/strong&gt; — pair 429 and 503 with &lt;code&gt;Retry-After&lt;/code&gt; so well-behaved clients back off correctly.&lt;/li&gt;
&lt;/ul&gt;



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock "&gt;
 &lt;pre id="1622451" class="language-http "&gt;
 &lt;code&gt;HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem&amp;#43;json

{
 &amp;#34;type&amp;#34;: &amp;#34;https://api.example.com/problems/invalid-field&amp;#34;,
 &amp;#34;title&amp;#34;: &amp;#34;Validation failed&amp;#34;,
 &amp;#34;status&amp;#34;: 422,
 &amp;#34;code&amp;#34;: &amp;#34;order.line_items.empty&amp;#34;,
 &amp;#34;detail&amp;#34;: &amp;#34;An order must contain at least one line item.&amp;#34;,
 &amp;#34;instance&amp;#34;: &amp;#34;/orders&amp;#34;,
 &amp;#34;trace_id&amp;#34;: &amp;#34;3f9a1c8e&amp;#34;
}&lt;/code&gt;
 &lt;/pre&gt;
 &lt;/div&gt;
&lt;h2 id="pagination-filtering-and-sorting"&gt;5. Pagination, filtering, and sorting &lt;a href="#pagination-filtering-and-sorting" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Collection endpoints are paginated by default with a documented maximum page size&lt;/strong&gt; — an unpaginated collection is a time bomb attached to your slowest table.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Pagination uses a stable cursor rather than an offset&lt;/strong&gt; — with offsets, rows inserted or deleted mid-scan cause results to shift, duplicate, or be skipped entirely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The cursor is opaque and its encoding is not part of the contract&lt;/strong&gt; — clients that decode it will break when you change the sort key.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A total count is either omitted or explicitly approximate&lt;/strong&gt; — an exact count over a large filtered set is often more expensive than the page itself.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Sorting is limited to indexed fields&lt;/strong&gt; — arbitrary sort parameters let a caller table-scan your production database.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Filter syntax is simple and closed&lt;/strong&gt; — a bespoke query language on a query string becomes an injection surface and an optimiser problem.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deep pagination is bounded&lt;/strong&gt; — either cap the total traversable depth or require a narrower filter, rather than letting page 10,000 melt the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="versioning-and-evolution"&gt;6. Versioning and evolution &lt;a href="#versioning-and-evolution" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The versioning strategy is decided and documented before launch&lt;/strong&gt; — retrofitting versioning onto a live API is far more expensive than choosing wrongly at the start.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;What counts as a breaking change is written down&lt;/strong&gt; — removing or renaming a field, tightening validation, changing a status code, or adding a required request field all break existing callers.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Additive changes are safe because clients are documented as tolerant readers&lt;/strong&gt; — state explicitly that unknown response fields must be ignored.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deprecation has a published policy with a minimum notice period&lt;/strong&gt; — and deprecated endpoints emit &lt;code&gt;Deprecation&lt;/code&gt; and &lt;code&gt;Sunset&lt;/code&gt; headers so callers can find them programmatically.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Usage per endpoint and per client is measured&lt;/strong&gt; — you cannot retire anything you cannot prove nobody is calling.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Old versions have a defined end-of-life date, not an open-ended one&lt;/strong&gt; — versions you never remove are versions you maintain forever.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Common mistake:&lt;/strong&gt; treating a change as non-breaking because your own client still works. Tightening a validation rule, narrowing an enum, or making an optional response field disappear will break somebody, even though your tests stay green.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="security-and-access-control"&gt;7. Security and access control &lt;a href="#security-and-access-control" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every endpoint requires authentication unless it is deliberately public&lt;/strong&gt; — the default in the router should be deny, with public routes as explicit exceptions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Authorisation is enforced per object, not per route&lt;/strong&gt; — object-level authorisation failure is the most commonly exploited API vulnerability, and it always looks fine in a route table.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;TLS is required and plaintext requests are rejected, not redirected&lt;/strong&gt; — a redirect has already exposed the credential.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Tokens are short-lived and scoped&lt;/strong&gt; — a long-lived token with full account scope turns a single leaked log line into a breach.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rate limits exist per client and are communicated in response headers&lt;/strong&gt; — including the limit, the remaining quota, and the reset time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Mass assignment is prevented by an explicit allowlist of writable fields&lt;/strong&gt; — binding a request body straight onto a model lets callers set &lt;code&gt;role&lt;/code&gt; or &lt;code&gt;account_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;CORS policy names specific origins&lt;/strong&gt; — a wildcard combined with credentials is a mistake that survives review because it makes the browser errors stop.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Responses never include fields the caller is not entitled to see&lt;/strong&gt; — filtering in the client is not filtering.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="documentation-and-contract"&gt;8. Documentation and contract &lt;a href="#documentation-and-contract" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A machine-readable specification exists and is generated from or verified against the implementation&lt;/strong&gt; — hand-written OpenAPI drifts within one sprint.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every endpoint documents its error responses, not just the success case&lt;/strong&gt; — the error contract is the part integrators actually need.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Examples are real and executable&lt;/strong&gt; — copy a request from the integration test suite rather than writing one by hand.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Authentication is documented end to end&lt;/strong&gt; — how to obtain a credential, how to refresh it, and what happens when it expires mid-request.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rate limits, quotas, and pagination defaults are stated in the documentation&lt;/strong&gt; — not discovered in production by a caller who then files a support ticket.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A changelog records every change with its date and its compatibility impact.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="operability"&gt;9. Operability &lt;a href="#operability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Idempotency keys are supported on non-idempotent operations that create money movement or side effects&lt;/strong&gt; — clients will retry a timed-out &lt;code&gt;POST&lt;/code&gt;, and without a key you will charge twice.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cache behaviour is explicit on every response&lt;/strong&gt; — set &lt;code&gt;Cache-Control&lt;/code&gt; deliberately, and use &lt;code&gt;ETag&lt;/code&gt; with conditional requests where responses are expensive.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Request and response sizes, latency, and status code distribution are instrumented per endpoint&lt;/strong&gt; — aggregate API metrics hide the one endpoint that is failing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Timeouts are defined at every layer and the client-facing timeout is documented&lt;/strong&gt; — so callers can set their own budget below yours rather than above it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A load test has established the per-endpoint breaking point&lt;/strong&gt; — particularly for the endpoints that fan out to other services.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Contract tests run in CI against the published specification&lt;/strong&gt; — so a schema-breaking change fails the build rather than a customer&amp;rsquo;s integration.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Resources and URL structure&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;HTTP semantics&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Request and response payloads&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Errors&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pagination, filtering, and sorting&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Versioning and evolution&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Security and access control&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Documentation and contract&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Operability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record each &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with an owner; anything unresolved in the versioning or security sections should block publication.&lt;/p&gt;</description></item><item><title>Database Schema Migration</title><link>https://checklists.metacog.co.kr/docs/development/database-schema-migration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/database-schema-migration/</guid><description>&lt;p&gt;A schema migration is the one deployment step that is not trivially reversible. Code can be rolled back in seconds; a dropped column cannot. The two failure modes that cause almost every migration incident are the same every time: a lock held long enough to stall the application, and a schema change deployed in the wrong order relative to the code that reads it. This checklist is built around avoiding both.&lt;/p&gt;</description></item><item><title>New Service Bootstrap</title><link>https://checklists.metacog.co.kr/docs/development/new-service-bootstrap/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/new-service-bootstrap/</guid><description>&lt;p&gt;Everything a service is missing on its first day it will still be missing two years later, because nobody gets funded to retrofit a health endpoint. The point of a bootstrap checklist is to make the boring scaffolding a precondition of the first commit rather than a cleanup task. This covers the repository, the pipeline, and the operational hooks; the go-live decision itself belongs to the production readiness review.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;p&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the engineer creating the service, with a platform or infrastructure reviewer. &lt;strong&gt;When:&lt;/strong&gt; in the first week of the repository existing, well before any traffic. See also the &lt;a data-bs-delay="{&amp;#34;hide&amp;#34;:300,&amp;#34;show&amp;#34;:550}" data-bs-html="true" data-bs-title="&lt;a href='https://checklists.metacog.co.kr/docs/devops/production-readiness/'&gt;&lt;p&gt;DEVOPS &amp; DELIVERY&lt;/p&gt;</description></item><item><title>Open Source Release</title><link>https://checklists.metacog.co.kr/docs/development/open-source-release/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/open-source-release/</guid><description>&lt;p&gt;Publishing a repository is a one-way door. Git history is permanent, package registries generally do not allow a version to be quietly replaced, and the first thing a stranger does with new code is read it for credentials. This checklist covers the legal review, the history scrub, the packaging, and the governance commitments you are making by putting your name on a public project.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the maintaining team, with sign-off from legal or open source programme office and a security reviewer. &lt;strong&gt;When:&lt;/strong&gt; at least two weeks before the intended publication date, because licence and history findings are slow to resolve.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="legal-and-licensing"&gt;1. Legal and licensing &lt;a href="#legal-and-licensing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The licence is chosen deliberately and approved by whoever owns that decision&lt;/strong&gt; — permissive and copyleft licences make materially different commitments, and changing later requires the agreement of every contributor.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;LICENSE&lt;/code&gt; file with the full, unmodified licence text is at the repository root&lt;/strong&gt; — package managers, scanners, and GitHub&amp;rsquo;s licence detection all key off it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every dependency&amp;rsquo;s licence is compatible with your chosen licence&lt;/strong&gt; — a copyleft dependency inside a permissively licensed project is the finding that most often stops a release.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Vendored, copied, or generated third-party code retains its original licence and attribution&lt;/strong&gt; — including code pasted from an answer site or produced from a licensed template.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;NOTICE&lt;/code&gt; file exists where any dependency licence requires attribution&lt;/strong&gt; — Apache-2.0 in particular obliges you to carry it forward.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Contributions from outside the organisation are covered by a CLA or a DCO sign-off&lt;/strong&gt; — decide before the first pull request, not after.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Trademarks, product names, and logos are used according to policy&lt;/strong&gt; — the code licence does not grant trademark rights, and the distinction confuses almost everyone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Patent implications have been reviewed if the project implements anything patented in-house.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="history-and-secret-scrubbing"&gt;2. History and secret scrubbing &lt;a href="#history-and-secret-scrubbing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The entire git history has been scanned for secrets, not just the current tree&lt;/strong&gt; — a key deleted in a later commit is still trivially retrievable from the history the moment the repository is public.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Automated secret scanning has been run with more than one tool&lt;/strong&gt; — detectors have different rule sets, and the cost of a second run is minutes.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any credential that ever appeared in the history is rotated regardless of scrub outcome&lt;/strong&gt; — assume it is compromised; a rewritten history does not help if a fork or a mirror already exists.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Internal hostnames, IP ranges, internal URLs, and infrastructure identifiers are removed&lt;/strong&gt; — these are reconnaissance material and are rarely caught by secret scanners.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Customer names, personal data, and real datasets are removed from fixtures, tests, and documentation&lt;/strong&gt; — test fixtures are the most overlooked source of a personal data disclosure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Internal commit messages and branch names have been reviewed&lt;/strong&gt; — they routinely reference ticket systems, incidents, security findings, and individuals by name.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;If the history cannot be cleaned, publish from a squashed initial commit&lt;/strong&gt; — losing history is preferable to publishing a leak, and it is the honest default for code extracted from a monorepo.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Push protection and secret scanning are enabled on the public repository before the first push&lt;/strong&gt; — the protection has to exist before the commit that would need it.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; never publish before rotating every credential that has appeared anywhere in the repository history. Public repositories are indexed by automated scrapers within minutes, and a rewritten history does not un-publish anything that was already fetched or forked.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="documentation"&gt;3. Documentation &lt;a href="#documentation" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The &lt;code&gt;README&lt;/code&gt; states what the project does and who it is for in the first three lines&lt;/strong&gt; — a visitor decides whether to keep reading in about ten seconds.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Installation and a minimal working example are copy-pasteable and have been tested on a clean machine&lt;/strong&gt; — by someone who did not write them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Supported versions, platforms, and runtimes are stated explicitly&lt;/strong&gt; — otherwise every unsupported combination becomes an issue in your tracker.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The project&amp;rsquo;s scope and non-goals are documented&lt;/strong&gt; — the cheapest way to decline a feature request is to have said no to that category in advance.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;&lt;code&gt;CONTRIBUTING.md&lt;/code&gt; covers how to build, test, and submit a change, and what makes a change acceptable&lt;/strong&gt; — including whether you want unsolicited feature pull requests at all.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;CODE_OF_CONDUCT.md&lt;/code&gt; is present with a working, monitored reporting address&lt;/strong&gt; — a reporting alias nobody reads is worse than none.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Documentation is versioned with the code&lt;/strong&gt; — documentation describing an unreleased API is a support burden from day one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="code-and-repository-quality"&gt;4. Code and repository quality &lt;a href="#code-and-repository-quality" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The code builds from a clean clone with only the documented prerequisites&lt;/strong&gt; — no internal package registry, no internal base image, no company-only tooling.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All internal dependencies have been removed or replaced with public equivalents&lt;/strong&gt; — an internal utility library referenced in &lt;code&gt;go.mod&lt;/code&gt; or &lt;code&gt;package.json&lt;/code&gt; will break every external build immediately.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Comments, identifiers, and error messages are in the project&amp;rsquo;s stated language and free of internal jargon&lt;/strong&gt; — internal codenames make code unreadable to outsiders.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Tests run in CI on the public repository, on the platforms you claim to support&lt;/strong&gt; — a badge that reflects an internal pipeline nobody can see is not evidence.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;CI on pull requests from forks is configured safely&lt;/strong&gt; — workflows that run untrusted code with access to repository secrets are a well-understood supply chain attack.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The default branch is protected and direct pushes are disabled, including for maintainers.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependency update automation and vulnerability alerts are enabled&lt;/strong&gt; — public projects are scanned by everyone, and a stale vulnerable dependency will be reported publicly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="versioning-and-releases"&gt;5. Versioning and releases &lt;a href="#versioning-and-releases" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The project follows semantic versioning and says so&lt;/strong&gt; — and the meaning of the major, minor, and patch positions for this project is documented.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The initial version signals stability honestly&lt;/strong&gt; — publishing &lt;code&gt;1.0.0&lt;/code&gt; commits you to a stable public interface; use &lt;code&gt;0.x&lt;/code&gt; if you are not ready for that.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;What constitutes the public API is defined&lt;/strong&gt; — which packages, modules, and symbols are covered by the compatibility promise, and which are internal.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;CHANGELOG.md&lt;/code&gt; is maintained in a keep-a-changelog style with the changes grouped by type&lt;/strong&gt; — generated commit logs are not a changelog because they are written for the wrong audience.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Releases are tagged, signed, and immutable&lt;/strong&gt; — and the tag matches the artefact published to the package registry.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The release process is automated and documented&lt;/strong&gt; — a release only one person can perform is a bus-factor problem and an inconsistency generator.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Build provenance or an SBOM is published with the artefacts&lt;/strong&gt; — consumers increasingly require it, and generating it later for old releases is impossible.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The package registry namespace and account are owned by the organisation, not by an individual&amp;rsquo;s personal account.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="security-posture"&gt;6. Security posture &lt;a href="#security-posture" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A &lt;code&gt;SECURITY.md&lt;/code&gt; states how to report a vulnerability and what response time to expect&lt;/strong&gt; — without it, reporters disclose publicly by default.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A private disclosure channel exists and is monitored by more than one person&lt;/strong&gt; — a single monitored inbox means a report sits unread while the reporter&amp;rsquo;s disclosure clock runs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;An embargo and coordinated disclosure process is agreed before you need it&lt;/strong&gt; — the first report is a bad time to invent a process.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Static analysis and dependency scanning run on the public repository&lt;/strong&gt; — outsiders will scan it anyway, and it is better to find the issue before they file it publicly.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Publishing credentials for the package registry are scoped, stored in a secret manager, and protected by multi-factor authentication&lt;/strong&gt; — a compromised publish token lets an attacker ship malware under your name.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Maintainer accounts with publish rights all have phishing-resistant multi-factor authentication enabled.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The threat model of running this code is documented if it processes untrusted input&lt;/strong&gt; — users need to know what guarantees you do and do not make.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="governance-and-sustainability"&gt;7. Governance and sustainability &lt;a href="#governance-and-sustainability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Maintainers are named and there is more than one with full access&lt;/strong&gt; — a single-maintainer project with a single publish key is one lost laptop from being abandoned.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The decision-making process for accepting changes is written down&lt;/strong&gt; — even if it is &amp;ldquo;the maintainers decide&amp;rdquo;, stating it prevents a lot of friction.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Expected response times for issues and pull requests are stated&lt;/strong&gt; — under-promising is fine; silence is what drives contributors away.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The support commitment is explicit&lt;/strong&gt; — which versions receive fixes, and for how long.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The internal cost of maintenance has an owner and allocated time&lt;/strong&gt; — an open source project without funded maintenance time degrades into an unanswered issue tracker.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;An archival or transfer plan exists for when the project is no longer maintained&lt;/strong&gt; — deciding in advance is far kinder to users than silent abandonment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="launch-and-after"&gt;8. Launch and after &lt;a href="#launch-and-after" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A pre-publication dry run has been done on a private repository with the same settings&lt;/strong&gt; — including a full release to a registry&amp;rsquo;s test channel where one exists.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Issue templates and a pull request template are configured&lt;/strong&gt; — they measurably improve the quality of what arrives.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Repository topics, description, and homepage are set&lt;/strong&gt; — this is how the project is found.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A rollback plan exists for the release itself&lt;/strong&gt; — know your registry&amp;rsquo;s rules on unpublishing and yanking before you need them, because most do not allow a version to be replaced.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Someone is on hand for the first week to answer issues&lt;/strong&gt; — the first days after publication determine whether the project attracts contributors or a backlog.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Internal teams that depend on the code know it is now public&lt;/strong&gt; — so they stop making internal-only assumptions in their pull requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Legal and licensing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;History and secret scrubbing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Documentation&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Code and repository quality&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Versioning and releases&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Security posture&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Governance and sustainability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Launch and after&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Legal and secret-scrubbing sections must be a clear pass; everything else may carry a dated follow-up ticket with a named owner.&lt;/p&gt;</description></item><item><title>Frontend Performance</title><link>https://checklists.metacog.co.kr/docs/development/frontend-performance/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/frontend-performance/</guid><description>&lt;p&gt;Frontend performance is decided by a small number of choices — how much JavaScript ships, when fonts and images load, and what blocks the main thread — and then eroded by a thousand small additions nobody measured. This checklist is organised around what the browser actually does with your page, and around the Core Web Vitals as the shared measurement, not as a scoring game. Measure on a mid-range Android device on a throttled connection, because that is what most of your users have.&lt;/p&gt;</description></item><item><title>Web Accessibility (WCAG)</title><link>https://checklists.metacog.co.kr/docs/development/web-accessibility/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/development/web-accessibility/</guid><description>&lt;p&gt;Automated tools catch roughly a third of accessibility defects, and almost none of the ones that actually stop somebody completing a task. This checklist is organised around how the interface is used — keyboard, screen reader, zoom, forms — rather than around the numbering of the specification, and it covers the success criteria added in WCAG 2.2 that most existing components fail. Target level AA unless a legal obligation says otherwise.&lt;/p&gt;</description></item><item><title>Observability</title><link>https://checklists.metacog.co.kr/docs/operations/observability/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/operations/observability/</guid><description>&lt;p&gt;Monitoring answers questions you thought of in advance. Observability is whether you can answer a question you have never asked before, at 3am, without deploying anything. This checklist covers the instrumentation, the pipeline that carries it, and the dashboards and alerts built on top — in the order you would build them.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the owning team, reviewed by whoever is on call for the service. &lt;strong&gt;When:&lt;/strong&gt; before a production readiness review, and again after any incident where the answer was &lt;em&gt;we could not tell&lt;/em&gt;.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="signal-coverage"&gt;1. Signal coverage &lt;a href="#signal-coverage" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The four golden signals exist for every user-facing entry point&lt;/strong&gt; — traffic, error rate, latency distribution, and saturation of the constraining resource, per endpoint rather than only in aggregate.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Latency is recorded as a histogram, not an average&lt;/strong&gt; — averages hide the tail, and the tail is what your users are complaining about.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Errors are split by cause&lt;/strong&gt; — client error, dependency failure, timeout, and unhandled exception behave differently and need different responses.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Queue depth and consumer lag are instrumented for every asynchronous path&lt;/strong&gt; — an async system fails silently by falling behind, not by returning errors.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Business-level counters exist alongside technical ones&lt;/strong&gt; — orders placed, sign-ups completed, payments settled; a drop here is real even when every technical metric looks green.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Batch and scheduled jobs emit start, finish, duration, and record counts&lt;/strong&gt; — a cron job that stopped running produces no signal at all unless you explicitly watch for its absence.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependency calls are instrumented on the client side&lt;/strong&gt; — a downstream service that reports itself healthy can still be unreachable from your network position.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="metrics"&gt;2. Metrics &lt;a href="#metrics" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Metric names follow one documented convention&lt;/strong&gt; — unit suffix, consistent prefix, and the same label spelling across services, or cross-service queries silently return nothing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cardinality is bounded and reviewed&lt;/strong&gt; — never label a metric with user ID, request ID, URL path with embedded IDs, or anything unbounded; this is the single most common way to take down a metrics backend.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Counters are monotonic and reset-safe&lt;/strong&gt; — use rate functions over counters rather than gauges that your code decrements, so a restart does not produce a negative spike.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Scrape or push interval is short enough to see the incidents you care about&lt;/strong&gt; — a 60-second interval cannot show you a 30-second outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Recording rules pre-compute the expensive queries used by dashboards and alerts&lt;/strong&gt; — a dashboard that takes 40 seconds to load will not be opened during an incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retention is tiered deliberately&lt;/strong&gt; — high resolution for recent debugging, downsampled long-term series for capacity and trend work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="logs"&gt;3. Logs &lt;a href="#logs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;All logs are structured&lt;/strong&gt; — JSON or an equivalent key-value format, so that fields can be filtered and aggregated rather than grepped.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every log line carries a trace ID and a request or job ID&lt;/strong&gt; — without a correlation key, a distributed request becomes a hundred unlinked lines across a dozen services.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Log levels are used consistently and documented&lt;/strong&gt; — if everything is logged at ERROR, error-rate panels and log-based alerts are worthless.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No secrets, credentials, tokens, or personal data reach the log pipeline&lt;/strong&gt; — audit request-body logging and auth-header logging specifically, and add a redaction filter at the collector as a backstop.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Log volume per request is bounded&lt;/strong&gt; — a debug-level loop inside a hot path can cost more than the service itself and will be discovered on the invoice.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retention satisfies both the investigation need and the data retention policy&lt;/strong&gt; — long enough to chase a slow-burning bug, short enough to be defensible.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Log ingestion failure is itself monitored&lt;/strong&gt; — a full disk or a rejected batch means you are flying blind precisely when things are going wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="distributed-tracing"&gt;4. Distributed tracing &lt;a href="#distributed-tracing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Trace context propagates across every hop&lt;/strong&gt; — HTTP, gRPC, message queues, and background workers; a trace that stops at the first hop tells you nothing you did not already know.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Spans are created for outbound calls, database queries, and cache lookups&lt;/strong&gt; — the point of tracing is attributing latency to a component, which needs spans at component boundaries.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Sampling is head-based with a tail-based override for errors and slow requests&lt;/strong&gt; — uniform 1% sampling reliably discards the exact traces you want.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Span attributes include the things you would filter on&lt;/strong&gt; — tenant, region, endpoint, and version, without embedding unbounded values.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Instrumentation uses OpenTelemetry or another vendor-neutral SDK&lt;/strong&gt; — so that changing backend does not mean re-instrumenting every service.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Trace IDs are surfaced to users or in error responses&lt;/strong&gt; — a support ticket that quotes a trace ID turns a two-hour investigation into a two-minute one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dashboards"&gt;5. Dashboards &lt;a href="#dashboards" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every service has one overview dashboard that fits on a single screen&lt;/strong&gt; — golden signals plus dependency health, with no scrolling required.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dashboards are ordered top-down&lt;/strong&gt; — user-visible symptoms first, then service internals, then infrastructure, matching how you actually diagnose.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each panel has a stated purpose and a known-good range&lt;/strong&gt; — a graph nobody can interpret under pressure is decoration.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deploy and configuration-change markers are overlaid on the time axis&lt;/strong&gt; — most incidents correlate with a change, and this makes the correlation instant.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dashboards are defined as code and version-controlled&lt;/strong&gt; — a hand-edited dashboard is lost the first time someone else edits it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A cross-service view exists for the critical user journey&lt;/strong&gt; — end-to-end latency and success rate for the journey, not just for individual services.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="alerting"&gt;6. Alerting &lt;a href="#alerting" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alerts fire on user-visible symptoms, not on causes&lt;/strong&gt; — high CPU is only worth paging about if it is degrading something a user can perceive.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every alert that pages links to the runbook section that resolves it&lt;/strong&gt; — an alert with no documented response should be downgraded to a ticket.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Paging alerts and ticketing alerts are separate channels with separate severities&lt;/strong&gt; — if everything pages, nothing pages.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alert conditions include a duration so transient blips do not page&lt;/strong&gt; — and the duration is short enough that the alert still fires inside the error budget window.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Absence of data triggers an alert&lt;/strong&gt; — a crashed exporter looks exactly like a perfectly healthy system on most dashboards.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alert rules are tested by deliberately breaking something in staging&lt;/strong&gt; — an untested alert rule is a hypothesis about a query language.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alert volume per shift is measured and reviewed monthly&lt;/strong&gt; — track the noisiest alerts and either fix, retune, or delete them.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Common mistake:&lt;/strong&gt; alerting on every metric that has a threshold. Each new page must be justified against the question &lt;em&gt;what would the responder do differently in the next five minutes?&lt;/em&gt; If there is no answer, it is a dashboard panel, not an alert.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="slos-and-error-budgets"&gt;7. SLOs and error budgets &lt;a href="#slos-and-error-budgets" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each critical user journey has an SLI defined as good events divided by valid events&lt;/strong&gt; — with an explicit definition of what counts as good and what requests are excluded.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;SLO targets are set from what users need, not from what the system currently does&lt;/strong&gt; — and they are achievable, since an SLO that is permanently breached is ignored.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The error budget and its burn rate are visible on the service dashboard&lt;/strong&gt; — a burn-rate alert catches fast-burning incidents far earlier than a raw threshold.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Multi-window multi-burn-rate alerting is configured&lt;/strong&gt; — a fast window for outages and a slow window for chronic degradation, so both are caught without false pages.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A policy exists for what happens when the budget is exhausted&lt;/strong&gt; — typically freezing feature releases in favour of reliability work, agreed with the product owner in advance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="synthetic-monitoring-and-the-pipeline-itself"&gt;8. Synthetic monitoring and the pipeline itself &lt;a href="#synthetic-monitoring-and-the-pipeline-itself" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A synthetic probe exercises the critical user journey from outside the network&lt;/strong&gt; — real user traffic can drop to zero while every internal metric stays green.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Probes run from more than one region or provider&lt;/strong&gt; — so that a probe failure is distinguishable from an outage in the probing infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The telemetry pipeline has its own monitoring and its own alerting path&lt;/strong&gt; — collector health, drop rates, and backend ingestion latency, alerted through a channel that does not depend on the pipeline.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Observability cost is attributed per service and reviewed&lt;/strong&gt; — telemetry regularly becomes a top-three line item and is best trimmed before finance asks.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data survives the loss of the primary region&lt;/strong&gt; — if the observability stack lives only in the region that just failed, you will debug the outage from memory.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;On-call engineers have read access to every signal without raising a request&lt;/strong&gt; — an access-request queue during an incident is an outage extender.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Signal coverage&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Metrics&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Logs&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Distributed tracing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Dashboards&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Alerting&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;SLOs and error budgets&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Synthetic monitoring and the pipeline itself&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner, and re-review any area marked Fail before the service is treated as observable.&lt;/p&gt;</description></item><item><title>On-Call Handover</title><link>https://checklists.metacog.co.kr/docs/operations/on-call-handover/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/operations/on-call-handover/</guid><description>&lt;p&gt;Most on-call failures are not heroic technical failures. They are an ongoing issue that the outgoing engineer knew about, forgot to mention, and that paged the incoming engineer at 2am with no context. A handover is a short, structured conversation with a written artefact attached; this checklist covers what each side owes the other and what has to be true before the pager actually moves.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the outgoing and incoming on-call engineers together, with the team lead as escalation if something cannot be handed over cleanly. &lt;strong&gt;When:&lt;/strong&gt; at a fixed time at the end of every shift, before the rotation flips in the paging tool.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="before-the-handover-meeting"&gt;1. Before the handover meeting &lt;a href="#before-the-handover-meeting" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The handover happens at a scheduled time, not whenever the rotation silently flips&lt;/strong&gt; — an automatic rotation change with no conversation is how context is lost.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The outgoing engineer has written the handover note before the meeting starts&lt;/strong&gt; — the meeting is for questions and clarification, not for composing the note live.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The handover note lives in a persistent, searchable place&lt;/strong&gt; — a ticket, a channel with retention, or the runbook repository, not a direct message that nobody else can find.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Both engineers have the shift open in front of them&lt;/strong&gt; — the alert history, the incident tracker, and the change log for the period, so nothing is recalled from memory alone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The meeting is time-boxed to fifteen minutes&lt;/strong&gt; — if it needs longer, that is a signal to escalate an unresolved issue rather than to talk for an hour.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A handover is still held when the shift was quiet&lt;/strong&gt; — the absence of pages is itself information, and skipping the ritual is how the ritual dies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-the-outgoing-engineer-hands-over"&gt;2. What the outgoing engineer hands over &lt;a href="#what-the-outgoing-engineer-hands-over" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every page received during the shift, with what was done about it&lt;/strong&gt; — including pages that were acknowledged and ignored, which are the most likely to recur.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Open incidents with current status, severity, and who else is involved&lt;/strong&gt; — never hand over an active incident by pager alone; brief the incoming engineer directly.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any temporary mitigation still in place&lt;/strong&gt; — a scaled-up cluster, a disabled feature flag, a paused consumer, or a manually restarted job, each with the condition for reverting it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Silenced or suppressed alerts, with the expiry time for each silence&lt;/strong&gt; — a permanent silence created at 3am is a future outage nobody will see coming.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Anything that looked odd but did not page&lt;/strong&gt; — an unexplained latency step, a growing queue, a new error signature; these are the early warning that the next shift will need.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Manual work in flight&lt;/strong&gt; — a half-finished migration, a partially applied configuration change, or a rollback that was started and not finished.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Tickets raised during the shift, with links&lt;/strong&gt; — so follow-up work does not have to be reconstructed from the chat history.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-the-incoming-engineer-confirms"&gt;3. What the incoming engineer confirms &lt;a href="#what-the-incoming-engineer-confirms" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pager actually reaches them&lt;/strong&gt; — send a test notification and confirm it arrives on the phone that will be in the room, with the ringer on and do-not-disturb bypassed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Access works before it is needed&lt;/strong&gt; — production console, cluster credentials, VPN, the incident tool, and any break-glass procedure, all exercised now rather than mid-incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;They can reach the escalation path&lt;/strong&gt; — the secondary on-call, the incident commander pool, and the vendor support contact, with numbers that have been dialled at least once.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;They have read the handover note and asked their questions&lt;/strong&gt; — the handover is complete when the incoming engineer can restate the open items, not when the outgoing engineer stops talking.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;They know which changes are planned during their shift&lt;/strong&gt; — releases, migrations, certificate rotations, and third-party maintenance windows all raise the probability of a page.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;They confirm their own availability constraints&lt;/strong&gt; — travel, poor signal, or personal commitments must be flagged now so cover can be arranged, not discovered when a page goes unanswered.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; do not flip the rotation until the incoming engineer has confirmed a test page arrived and that production access works. A silent pager is indistinguishable from a healthy system until the outage is already an hour old.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="system-state-review"&gt;4. System state review &lt;a href="#system-state-review" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The service dashboards are walked through together&lt;/strong&gt; — current error rate and latency versus the same time last week, so a slow drift is visible rather than normalised.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Error budget consumption for the shift is reported&lt;/strong&gt; — a large burn during a quiet shift means something is degrading without paging.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Capacity headroom is checked&lt;/strong&gt; — disk, database connections, queue depth, and any resource that is consumed monotonically and cannot be recovered without action.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Certificate and credential expiries within the next fourteen days are listed&lt;/strong&gt; — expiry-driven outages are entirely predictable and entirely avoidable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backlogs and dead letter queues are reported with their trend&lt;/strong&gt; — a dead letter queue that grew during the shift is a customer-impacting bug that has not surfaced yet.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Known-degraded dependencies are named&lt;/strong&gt; — including third-party providers currently on a status-page incident, so the next page is not misdiagnosed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="alerting-and-paging-hygiene"&gt;5. Alerting and paging hygiene &lt;a href="#alerting-and-paging-hygiene" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alerts that fired more than twice this shift are flagged as noisy&lt;/strong&gt; — repeated pages for the same non-actionable condition are the main driver of on-call attrition.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every silence created during the shift has an owner and an expiry&lt;/strong&gt; — and silences that are about to expire are transferred explicitly.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;New alerts added during the shift are reviewed for a runbook link&lt;/strong&gt; — an alert authored at 3am usually has no documented response yet.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;False positives are ticketed, not just tolerated&lt;/strong&gt; — if it is not written down, the same alert will wake five more people before anyone fixes it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The paging tool&amp;rsquo;s schedule shows the correct people for the next fourteen days&lt;/strong&gt; — including holiday cover, and with an override rather than a private arrangement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="documentation-and-runbooks"&gt;6. Documentation and runbooks &lt;a href="#documentation-and-runbooks" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any runbook used during the shift was corrected where it was wrong&lt;/strong&gt; — the moment you discover a stale step is the only moment you will reliably remember to fix it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any incident resolved without a runbook produced one&lt;/strong&gt; — even a rough set of commands is better than the next responder starting from nothing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;New or changed escalation contacts are recorded in the shared directory&lt;/strong&gt; — not in one engineer&amp;rsquo;s phone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Links in the handover note resolve&lt;/strong&gt; — dashboards, tickets, and runbooks should be checked, since a dead link during an incident costs minutes you do not have.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Manual steps performed during the shift are captured as automation candidates&lt;/strong&gt; — the third time a human runs the same recovery command, it should become a script.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The runbook index reflects any service added or retired since the last shift&lt;/strong&gt; — responders will search the index first, and a missing entry reads as no procedure exists.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="escalation-and-follow-up-ownership"&gt;7. Escalation and follow-up ownership &lt;a href="#escalation-and-follow-up-ownership" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each open item has exactly one named owner after the handover&lt;/strong&gt; — either the incoming engineer or a specific person on the team, never &amp;ldquo;on-call&amp;rdquo; as an abstraction.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Items that need daytime engineering work are moved into the team backlog, not carried in the pager&lt;/strong&gt; — on-call is for response; recurring toil belongs in sprint planning.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Anything unresolved for more than two consecutive shifts is escalated to the team lead&lt;/strong&gt; — repeated handover of the same problem is the signal that on-call cannot fix it alone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Incidents from the shift have a postmortem owner assigned where the severity threshold was met&lt;/strong&gt; — postmortems left unassigned at handover are rarely written.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Follow-up actions from previous postmortems that are now overdue are surfaced&lt;/strong&gt; — the same incident recurring is almost always an unimplemented action item.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="shift-health-and-sustainability"&gt;8. Shift health and sustainability &lt;a href="#shift-health-and-sustainability" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Overnight pages are recorded with their timestamps&lt;/strong&gt; — sleep interruption is the metric that predicts burnout, and it is invisible unless it is counted.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The outgoing engineer takes compensating rest after a disrupted night&lt;/strong&gt; — agreed as team policy, so that taking it does not require asking permission.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The number of actionable versus non-actionable pages is tracked per shift&lt;/strong&gt; — the ratio, not the raw count, tells you whether alerting is working.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;On-call load is reviewed at least monthly against a target&lt;/strong&gt; — a commonly used ceiling is around two pages per shift; sustained breaches justify pausing feature work.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;No single person holds the pager for consecutive rotations without agreement&lt;/strong&gt; — informal cover arrangements hide load from everyone who could fix it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Before the handover meeting&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;What the outgoing engineer hands over&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;What the incoming engineer confirms&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;System state review&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Alerting and paging hygiene&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Documentation and runbooks&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Escalation and follow-up ownership&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Shift health and sustainability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Attach the completed table to the handover note and raise a dated ticket for every item marked &amp;ldquo;Pass with actions&amp;rdquo; before the rotation flips.&lt;/p&gt;</description></item><item><title>Incident Management</title><link>https://checklists.metacog.co.kr/docs/operations/incident-management/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/operations/incident-management/</guid><description>&lt;p&gt;An incident process exists so that nobody has to invent one under pressure. This checklist follows the shape of a real incident in order — detection, triage, roles, mitigation, communication, resolution, and the handover to a postmortem — and is meant to be worked through top to bottom while the incident is live, not read afterwards.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the incident commander, supported by the ops lead and comms lead. &lt;strong&gt;When:&lt;/strong&gt; from the moment an incident is declared until the postmortem owner has accepted the handover.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="detection-and-declaration"&gt;1. Detection and declaration &lt;a href="#detection-and-declaration" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The incident has an explicit declaration, not a gradual realisation&lt;/strong&gt; — someone says the words and starts the clock, because an undeclared incident has no commander and no communications.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Anyone can declare an incident without asking permission&lt;/strong&gt; — the cost of a false declaration is a short call; the cost of a delayed one is measured in hours of customer impact.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Declaration creates the incident record automatically&lt;/strong&gt; — a ticket, a dedicated channel, and a bridge, so the responders spend their first minutes diagnosing rather than setting up tooling.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The detection source is recorded&lt;/strong&gt; — alert, synthetic probe, customer report, or internal observation; detection by customer report is itself a finding for the postmortem.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Time of first customer impact is estimated early and refined later&lt;/strong&gt; — it drives severity, SLA obligations, and any regulatory reporting clock.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Recent changes are pulled up immediately&lt;/strong&gt; — deploys, feature flag flips, configuration and infrastructure changes in the last few hours account for the large majority of incidents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="triage-and-severity"&gt;2. Triage and severity &lt;a href="#triage-and-severity" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Severity is assigned from a written matrix, not by feel&lt;/strong&gt; — the matrix should key on customer impact and scope, so that two different commanders reach the same answer.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Severity is set within the first few minutes and revised openly when it changes&lt;/strong&gt; — under-declaring to avoid waking people is the most expensive mistake in this process.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Blast radius is scoped explicitly&lt;/strong&gt; — which customers, which regions, which features, and whether the impact is total or partial degradation.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data loss, data corruption, and security compromise are checked for by name&lt;/strong&gt; — each of these changes the response entirely and cannot be discovered late.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each severity level maps to a defined response&lt;/strong&gt; — who is paged, how often updates go out, and whether executives and legal are notified.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Regulatory and contractual notification clocks are identified at triage&lt;/strong&gt; — breach notification and SLA credit windows start at impact, not at your convenience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="roles"&gt;3. Roles &lt;a href="#roles" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;An incident commander is named out loud and acknowledged by everyone on the call&lt;/strong&gt; — the commander coordinates and decides; they do not debug, because a commander with their head in a terminal is not commanding.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;An ops lead owns the hands-on-keyboard work&lt;/strong&gt; — all changes to production during the incident go through this person, so that two responders never fight over the same system.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A comms lead owns all outward communication&lt;/strong&gt; — status page, customer messaging, and internal stakeholder updates, so responders are not interrupted to answer questions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A scribe records a timestamped log of observations, decisions, and actions&lt;/strong&gt; — memory is unreliable and the postmortem timeline is impossible to reconstruct afterwards.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Roles are handed over explicitly when someone tires or leaves&lt;/strong&gt; — with a verbal summary and confirmation, never by simply going quiet.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Subject matter experts are pulled in on request and released when done&lt;/strong&gt; — an open call full of idle observers degrades signal for everyone remaining.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The commander role is separated from seniority&lt;/strong&gt; — the most senior person in the room is often the most useful debugging, and command is a distinct skill.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Common failure:&lt;/strong&gt; nobody takes the commander role because everyone assumes someone else has it. If ten minutes pass with no named commander, the most recently paged responder takes it by default and says so in the channel.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="mitigation"&gt;4. Mitigation &lt;a href="#mitigation" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Restoring service takes priority over understanding the cause&lt;/strong&gt; — the investigation continues in parallel, but mitigation is not blocked on a diagnosis.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rollback is considered as the first option for any change-correlated incident&lt;/strong&gt; — reverting to a known-good state is faster and far less risky than fixing forward under pressure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;One change is made at a time, announced before and confirmed after&lt;/strong&gt; — simultaneous changes make it impossible to tell what worked and can compound the damage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every mitigating action is logged with its timestamp and its effect&lt;/strong&gt; — including actions that made no difference, which are just as important in the postmortem.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Emergency changes bypassing normal review are recorded for retrospective approval&lt;/strong&gt; — break-glass access should be usable and auditable, not blocked.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Temporary mitigations are ticketed for reversal at the moment they are applied&lt;/strong&gt; — an emergency capacity increase or disabled feature that nobody revisits becomes permanent cost or permanent breakage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Evidence is preserved before destructive remediation&lt;/strong&gt; — capture logs, heap dumps, and a snapshot of the failing node before restarting or replacing it, or the cause is gone forever.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="communication-cadence"&gt;5. Communication cadence &lt;a href="#communication-cadence" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The status page is updated within the response window defined for the severity&lt;/strong&gt; — customers who cannot tell whether the problem is yours will flood support and assume the worst.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Updates go out on a fixed cadence even when there is nothing new&lt;/strong&gt; — an update saying the investigation continues and the next update is in thirty minutes prevents the escalation phone calls.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Customer-facing messages describe impact and workaround, not internal architecture&lt;/strong&gt; — say which features are affected and what a user can do, and avoid speculating about cause.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Internal and external communications are consistent&lt;/strong&gt; — leaked contradictions between an internal channel and a public status page cost more trust than the outage did.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Support and account teams get a briefing they can paste to customers&lt;/strong&gt; — otherwise each one improvises a different and probably wrong answer.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;One channel is designated as the source of truth&lt;/strong&gt; — side conversations in direct messages fragment the record and hide decisions from the scribe.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Executives receive a summary on a separate track from the response channel&lt;/strong&gt; — so that stakeholder questions do not interrupt the responders.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="resolution"&gt;6. Resolution &lt;a href="#resolution" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Recovery is verified from the customer&amp;rsquo;s perspective before declaring resolution&lt;/strong&gt; — check the synthetic probe and a real user journey, not just that the error graph came down.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backlogs, queues, and retry storms are drained and confirmed healthy&lt;/strong&gt; — a restored service can immediately fall over again under the queued load released at recovery.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data written during the incident is checked for correctness&lt;/strong&gt; — partially processed transactions, duplicated messages, and skipped records need explicit reconciliation.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The all-clear is announced in every channel where the incident was announced&lt;/strong&gt; — including the status page, which is commonly left showing a resolved incident as ongoing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Monitoring is watched for an agreed stabilisation period before standing down&lt;/strong&gt; — resolving too early and re-declaring twenty minutes later damages credibility more than waiting.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Total impact is quantified before the call ends&lt;/strong&gt; — duration, affected users or requests, and error budget consumed, while the numbers are still easy to query.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="handover-to-postmortem"&gt;7. Handover to postmortem &lt;a href="#handover-to-postmortem" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A postmortem owner is named before the incident call ends&lt;/strong&gt; — an unassigned postmortem is a postmortem that does not get written.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The severity threshold that requires a postmortem is written policy&lt;/strong&gt; — so it is not renegotiated case by case by whoever is tired.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The scribe&amp;rsquo;s timeline, the chat log, and relevant graphs are attached to the incident record immediately&lt;/strong&gt; — dashboards roll off and chat retention expires faster than postmortems get written.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Temporary mitigations still in place are listed explicitly for the postmortem to track to reversal.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A due date for the postmortem draft is set, typically within five working days&lt;/strong&gt; — accuracy of recall drops sharply after the first few days.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Open follow-up work is ticketed now rather than deferred to the postmortem&lt;/strong&gt; — anything genuinely urgent should not wait for a document to be written.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="process-health"&gt;8. Process health &lt;a href="#process-health" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The incident process is rehearsed, not only exercised in production&lt;/strong&gt; — run game days or tabletop exercises so that first-time commanders are not learning during a real outage.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;New joiners shadow an incident before commanding one&lt;/strong&gt; — and shadowing is scheduled rather than left to chance.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Incident metrics are tracked over time&lt;/strong&gt; — time to detect, time to acknowledge, time to mitigate, and how many incidents were customer-reported rather than alert-detected.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Repeat incidents are counted separately&lt;/strong&gt; — a rising repeat rate means postmortem actions are not being completed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The process documentation is short enough to be read during an incident&lt;/strong&gt; — a forty-page policy is not an incident process, it is an audit artefact.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Detection and declaration&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Triage and severity&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Roles&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Mitigation&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Communication cadence&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Resolution&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Handover to postmortem&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Process health&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Review this table at the postmortem and raise a dated ticket with a named owner for every item that did not pass.&lt;/p&gt;</description></item><item><title>Postmortem</title><link>https://checklists.metacog.co.kr/docs/operations/postmortem/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/operations/postmortem/</guid><description>&lt;p&gt;A postmortem is not a report you file to prove the incident was handled. It is the mechanism by which an organisation converts one expensive outage into knowledge that prevents the next several. This checklist covers the writing, the analysis, the action items, and the review meeting — in the order the document is produced.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the postmortem owner named at the end of the incident, with the incident commander and responders as contributors. &lt;strong&gt;When:&lt;/strong&gt; draft within five working days of resolution, reviewed within ten.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="scope-ownership-and-timing"&gt;1. Scope, ownership, and timing &lt;a href="#scope-ownership-and-timing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A single named owner is responsible for the document&lt;/strong&gt; — shared ownership reliably produces no document at all.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The trigger threshold for writing a postmortem is written policy&lt;/strong&gt; — typically any customer-visible incident above a defined severity, any data loss, and any incident that recurred.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The draft is written within five working days&lt;/strong&gt; — recall degrades quickly and responders move on to other work.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Contributors are given time to write it as part of their normal workload&lt;/strong&gt; — a postmortem written entirely in someone&amp;rsquo;s evenings is a postmortem that gets skipped next time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A near miss can be written up voluntarily&lt;/strong&gt; — the cheapest lessons come from incidents that were caught before customers noticed, and these only surface if writing them is welcomed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The document lives in a searchable shared archive&lt;/strong&gt; — the value compounds only if a future engineer can find the one from eighteen months ago.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="blameless-writing"&gt;2. Blameless writing &lt;a href="#blameless-writing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The document describes systems and decisions, not people&lt;/strong&gt; — name roles or teams rather than individuals, since the goal is a system that tolerates ordinary human error.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every human action is framed with the information available at the time&lt;/strong&gt; — someone acted reasonably given what their dashboard showed, and the fix belongs to the dashboard.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Counterfactuals are removed from the analysis&lt;/strong&gt; — sentences beginning &amp;ldquo;if only they had&amp;rdquo; describe a world that did not exist and produce no actionable change.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The words &amp;ldquo;human error&amp;rdquo; and &amp;ldquo;operator mistake&amp;rdquo; do not appear as conclusions&lt;/strong&gt; — they are the point at which analysis stops rather than the point at which it should start.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Hindsight-loaded language is edited out&lt;/strong&gt; — &amp;ldquo;obviously&amp;rdquo;, &amp;ldquo;clearly&amp;rdquo;, and &amp;ldquo;should have known&amp;rdquo; all signal that the writer is judging rather than explaining.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The review confirms that responders would be comfortable if the document were read widely&lt;/strong&gt; — if people would hesitate to be named, the culture is not yet blameless and the next incident will be reported late or not at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;This is the load-bearing item on the page.&lt;/strong&gt; The moment a postmortem is used in a performance conversation, engineers start hiding incidents, and every subsequent postmortem becomes fiction. Blamelessness is not politeness; it is what makes the data trustworthy.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="timeline-construction"&gt;3. Timeline construction &lt;a href="#timeline-construction" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The timeline is built from sources, not from memory&lt;/strong&gt; — chat transcripts, alert history, deploy logs, and the scribe&amp;rsquo;s notes, each entry linked to its evidence.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every entry carries an absolute timestamp with a stated timezone&lt;/strong&gt; — mixed local times across a distributed team make the sequence unreconstructable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The timeline starts before the incident&lt;/strong&gt; — include the change, the configuration edit, or the traffic shift that set up the failure, which is often days earlier.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Key markers are called out explicitly&lt;/strong&gt; — first customer impact, first alert, first human acknowledgement, mitigation applied, and full recovery.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;What responders believed at each point is recorded alongside what was actually true&lt;/strong&gt; — the gap between the two is usually the richest source of findings.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Detection delay and mitigation delay are stated as numbers&lt;/strong&gt; — these are the two levers you can actually pull, and they need to be measurable to be improved.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Actions that had no effect are included&lt;/strong&gt; — the dead ends explain where diagnosis time went and often point at missing signals.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="impact"&gt;4. Impact &lt;a href="#impact" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Customer impact is quantified, not described&lt;/strong&gt; — affected users or requests, duration, and which functionality was degraded versus fully unavailable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Error budget consumed is reported against the relevant SLO&lt;/strong&gt; — this connects the incident to the reliability decisions the team has already agreed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data impact is stated explicitly&lt;/strong&gt; — records lost, duplicated, or corrupted, and whether reconciliation was completed or is still outstanding.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Internal cost is recorded&lt;/strong&gt; — responder hours, work displaced, and the number of people who lost sleep, since this is what justifies the prevention work.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Financial and contractual consequences are noted where they apply&lt;/strong&gt; — SLA credits, lost transactions, and any regulatory notification that was triggered.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="contributing-factors-and-root-cause"&gt;5. Contributing factors and root cause &lt;a href="#contributing-factors-and-root-cause" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Multiple contributing factors are identified, not a single root cause&lt;/strong&gt; — complex systems fail through combinations, and a single-cause narrative closes the analysis prematurely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each contributing factor is categorised&lt;/strong&gt; — trigger, latent condition, missing safeguard, detection gap, or response impediment, since each category attracts a different kind of fix.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Latent conditions that existed long before the incident are named&lt;/strong&gt; — the missing timeout, the unbounded queue, or the untested failover was there for months and will still be there tomorrow.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The analysis asks why the safeguards did not work, not only why the failure happened&lt;/strong&gt; — every serious incident passed through defences that were supposed to stop it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Detection and response are analysed separately from causation&lt;/strong&gt; — an incident that would have lasted two minutes with better alerting is primarily a detection problem.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Any recurrence of a previous incident is linked to it&lt;/strong&gt; — and the action items from that earlier postmortem are checked for completion, which is usually where the answer is.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Speculation is labelled as speculation&lt;/strong&gt; — where the cause could not be conclusively determined, say so rather than committing to a plausible guess that ends the investigation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="action-items"&gt;6. Action items &lt;a href="#action-items" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every action item has one named individual owner and a due date&lt;/strong&gt; — a team name is not an owner and &amp;ldquo;next quarter&amp;rdquo; is not a date.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Action items are tracked in the normal backlog, not only inside the document&lt;/strong&gt; — work that lives in a wiki page is work that does not get scheduled.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each item is classified by whether it prevents, detects, or mitigates&lt;/strong&gt; — a set of items that are all detection improvements means nothing is actually being fixed.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Items are specific enough to be verifiably complete&lt;/strong&gt; — &amp;ldquo;improve monitoring&amp;rdquo; cannot be closed honestly, whereas &amp;ldquo;add a burn-rate alert on the checkout SLO&amp;rdquo; can.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The list is prioritised and deliberately short&lt;/strong&gt; — twenty low-priority items produce nothing; three completed high-priority items prevent the recurrence.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Items intentionally not being done are recorded as accepted risk with a decision-maker&lt;/strong&gt; — an explicit acceptance is far better than an item that quietly ages out.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Reverting temporary mitigations from the incident appears as an action item&lt;/strong&gt; — the emergency capacity increase and the disabled feature flag both need an owner.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Overdue action items are escalated on a schedule&lt;/strong&gt; — a monthly review of open postmortem actions catches the drift before the incident repeats.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-review-meeting"&gt;7. The review meeting &lt;a href="#the-review-meeting" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The draft is circulated for reading before the meeting&lt;/strong&gt; — reading the document aloud consumes the whole session and prevents discussion.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Everyone who responded is invited, plus someone from outside the team&lt;/strong&gt; — an outsider asks the questions insiders have stopped noticing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The meeting focuses on the analysis and the action items, not on re-narrating the timeline&lt;/strong&gt; — the timeline should be settled in the draft, with corrections collected in writing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Disagreements about contributing factors are recorded in the document rather than resolved by seniority&lt;/strong&gt; — a documented disagreement is more useful than a false consensus.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Action items are agreed with their owners present and consenting&lt;/strong&gt; — an owner assigned in absentia has not accepted anything.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The meeting is time-boxed and ends with an explicit decision to publish&lt;/strong&gt; — postmortems that stay in draft indefinitely deliver none of their value.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="publication-and-organisational-learning"&gt;8. Publication and organisational learning &lt;a href="#publication-and-organisational-learning" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The final document is published to the whole engineering organisation&lt;/strong&gt; — the audience that learns most is the teams who were not involved.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A short summary is written for non-engineering stakeholders where impact warrants it&lt;/strong&gt; — support, sales, and leadership need the impact and the prevention plan, not the stack traces.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Findings that apply to other services are routed to those teams explicitly&lt;/strong&gt; — the same missing timeout usually exists in four other places.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Runbooks and alerts are updated as part of closing the postmortem&lt;/strong&gt; — the knowledge is only durable once it lives where the next responder will look.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Postmortems are reviewed in aggregate at least quarterly&lt;/strong&gt; — themes across ten incidents reveal systemic problems that no single review can see.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Action item completion rate is tracked as a team metric&lt;/strong&gt; — a low completion rate is the single best predictor that the same incident will happen again.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Scope, ownership, and timing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Blameless writing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Timeline construction&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Impact&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Contributing factors and root cause&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Action items&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;The review meeting&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Publication and organisational learning&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Do not publish the postmortem until every row reads Pass or has a dated ticket attached to its outstanding actions.&lt;/p&gt;</description></item><item><title>Backup and Recovery</title><link>https://checklists.metacog.co.kr/docs/operations/backup-and-recovery/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/operations/backup-and-recovery/</guid><description>&lt;p&gt;Nobody wants backups; everybody wants restores. The distinction matters because a backup job that reports success every night proves only that a job ran, not that the data inside it is readable, complete, or recoverable within the window the business assumes. This checklist works from what you are protecting, through how it is stored and secured, to the only test that counts.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the service owner together with whoever operates the data platform, reviewed by someone outside the team. &lt;strong&gt;When:&lt;/strong&gt; before go-live, after any change to storage or retention, and at least once a year regardless.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="scope-and-inventory"&gt;1. Scope and inventory &lt;a href="#scope-and-inventory" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every data store the service depends on is listed&lt;/strong&gt; — databases, object storage, search indexes, message queues with durable state, and the caches that cannot be rebuilt from source.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Configuration and infrastructure state are in scope, not just user data&lt;/strong&gt; — Terraform state, secret manager contents, DNS zones, IAM policies, and CI/CD configuration are all restore-critical.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Each dataset has a named owner and a classification&lt;/strong&gt; — the owner decides retention and approves restores, and the classification determines encryption and access requirements.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Data that is deliberately not backed up is documented as an accepted loss&lt;/strong&gt; — derived data and rebuildable caches are legitimate exclusions, but only when written down.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependencies between datasets are recorded&lt;/strong&gt; — restoring a database without the object storage its rows reference produces a consistent-looking but broken system.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The inventory is generated or verified automatically&lt;/strong&gt; — a hand-maintained list will silently miss the database that was created last quarter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="recovery-objectives"&gt;2. Recovery objectives &lt;a href="#recovery-objectives" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;An RPO and RTO are agreed per dataset with the business, in writing&lt;/strong&gt; — engineering cannot invent an acceptable data loss window on the business&amp;rsquo;s behalf.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The objectives are derived from actual impact, not from what the current tooling happens to deliver&lt;/strong&gt; — a 24-hour RPO for payments data is a decision, and it should be a conscious one.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The measured recovery time is compared against the RTO after every restore test&lt;/strong&gt; — most teams discover their real RTO is several times their stated one.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Recovery time includes everything, not just the restore command&lt;/strong&gt; — detection, decision, provisioning, restore, replay, validation, and cutover all consume the window.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Objectives for a full regional loss are separate from those for a single-table deletion&lt;/strong&gt; — they are different scenarios with different mechanisms and different costs.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The cost of meeting each objective is known and accepted&lt;/strong&gt; — a one-minute RPO is achievable and expensive, and the trade-off belongs to the data owner.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="backup-implementation"&gt;3. Backup implementation &lt;a href="#backup-implementation" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backup frequency actually satisfies the stated RPO&lt;/strong&gt; — a nightly snapshot cannot deliver a four-hour RPO, no matter what the policy document says.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Point-in-time recovery is enabled where the RPO is shorter than the snapshot interval&lt;/strong&gt; — continuous transaction log archiving is what closes the gap between snapshots.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backups are consistent, not merely copied&lt;/strong&gt; — use the database&amp;rsquo;s own snapshot mechanism or quiesce writes, since a file-level copy of a running database is often unrecoverable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Related datasets are captured at a coordinated point in time&lt;/strong&gt; — otherwise restoring produces referential inconsistency that is discovered days later.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backup jobs alert on failure and on unexpected success characteristics&lt;/strong&gt; — a job that completes in a tenth of the usual time and produces a tenth of the usual bytes has failed silently.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Missing backups are alerted on, not just failing ones&lt;/strong&gt; — a job that stopped being scheduled generates no failure event at all.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backup duration and size are trended&lt;/strong&gt; — steady growth predicts the day the job stops fitting inside its window.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="storage-isolation-and-retention"&gt;4. Storage, isolation, and retention &lt;a href="#storage-isolation-and-retention" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;At least one copy is in a different region or physical location&lt;/strong&gt; — a backup stored beside the primary shares its failure domain.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;At least one copy is in an account or subscription with separate credentials&lt;/strong&gt; — an attacker or a runaway script with production credentials must not be able to delete the backups.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Object lock or immutability is enabled for the retention period&lt;/strong&gt; — this is the control that survives ransomware and a compromised administrator, and it cannot be added after the fact.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Deletion of backups requires a second approval and is logged&lt;/strong&gt; — and lifecycle rules that expire data are reviewed, since a misconfigured rule deletes quietly and permanently.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retention satisfies both recovery needs and legal obligations&lt;/strong&gt; — long enough to recover from corruption discovered late, and short enough to satisfy data protection commitments.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retention is enforced by an automated job rather than by intention&lt;/strong&gt; — unbounded retention is a compliance liability and an unbounded bill.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Storage costs are attributed and reviewed&lt;/strong&gt; — backup storage grows monotonically and is a common source of budget surprises.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-danger d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 report
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; if the credentials that run production can also delete the backups, you do not have backups. Immutable storage in a separately credentialed account is the minimum bar for anything you would be unwilling to lose.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="encryption-and-access-control"&gt;5. Encryption and access control &lt;a href="#encryption-and-access-control" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backups are encrypted at rest and in transit&lt;/strong&gt; — including snapshots, exports, and any temporary staging bucket used during the copy.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Encryption keys are stored separately from the backups and are themselves backed up&lt;/strong&gt; — an unrecoverable key makes an intact backup worthless, which is the most avoidable form of total data loss.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Key rotation does not orphan older backups&lt;/strong&gt; — verify that a backup taken before the last rotation is still decryptable, by decrypting one.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Access to backups is least-privilege and audited&lt;/strong&gt; — a full backup is the most concentrated copy of your data that exists, and it is frequently the least protected.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Restores into non-production environments anonymise or mask personal data&lt;/strong&gt; — copying production data into a development account is a common and serious breach path.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Break-glass access to backups is documented and tested&lt;/strong&gt; — including how to restore when the normal identity provider is the thing that is down.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="restore-testing"&gt;6. Restore testing &lt;a href="#restore-testing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A full restore has been performed end to end, into a clean environment&lt;/strong&gt; — an untested backup is a hypothesis, and the failure rate of first restores is high.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Restore tests run on a schedule, at least quarterly, and after every major version upgrade&lt;/strong&gt; — a database engine upgrade can silently break compatibility with older backup formats.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The restore is validated by data content, not by job exit code&lt;/strong&gt; — check row counts, run a checksum or reconciliation query, and exercise a real application read path.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Partial restores are tested as well as full ones&lt;/strong&gt; — the far more common real-world case is one table or one bucket prefix deleted by mistake.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Point-in-time recovery is tested by restoring to a specific timestamp&lt;/strong&gt; — including replaying transaction logs, which is the step that usually turns out to be misconfigured.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The restore is performed by someone who did not build it, following only the runbook&lt;/strong&gt; — this is how you find the undocumented step that lives in one person&amp;rsquo;s head.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Measured restore time is recorded and compared to the RTO&lt;/strong&gt; — with any gap raised as a ticket rather than quietly normalised.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="runbooks-and-decision-making"&gt;7. Runbooks and decision-making &lt;a href="#runbooks-and-decision-making" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A restore runbook exists per dataset with exact commands&lt;/strong&gt; — during a data-loss incident nobody should be reading vendor documentation for the first time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The runbook states who authorises a restore&lt;/strong&gt; — overwriting production with a backup is itself destructive and needs a named decision-maker.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rolling back to a backup and rolling forward are both covered&lt;/strong&gt; — including how to reconcile writes that happened after the restore point.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The runbook is stored where it can be read while the primary systems are down&lt;/strong&gt; — an incident guide that only exists in the wiki hosted on the failed cluster is not a guide.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Vendor support paths and account identifiers are recorded in the runbook&lt;/strong&gt; — some restores require the provider, and finding the support contract number under pressure wastes the window.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Communication expectations during a restore are defined&lt;/strong&gt; — restores are slow, and stakeholders need a cadence rather than silence.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="failover-and-disaster-scenarios"&gt;8. Failover and disaster scenarios &lt;a href="#failover-and-disaster-scenarios" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Loss of an entire region has a documented and rehearsed response&lt;/strong&gt; — including how DNS, certificates, and secrets are made available in the recovery region.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The recovery environment can actually be provisioned&lt;/strong&gt; — check service quotas, instance availability, and image replication in the target region before you need them.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Failback is planned, not just failover&lt;/strong&gt; — returning to the primary region with reconciled data is usually the harder half and is frequently unplanned.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Ransomware and malicious deletion are treated as distinct scenarios&lt;/strong&gt; — they require immutable copies and a known-clean recovery point, not simply the most recent backup.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Dependencies on third parties are included in the disaster plan&lt;/strong&gt; — an identity provider, payment processor, or DNS provider outage needs a documented response of its own.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A full disaster recovery exercise is run at least annually with the outcome recorded&lt;/strong&gt; — with findings ticketed exactly as they would be after a real incident.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Scope and inventory&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Recovery objectives&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Backup implementation&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Storage, isolation, and retention&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Encryption and access control&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Restore testing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Runbooks and decision-making&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Failover and disaster scenarios&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record the date and measured duration of the most recent successful restore alongside the sign-off, and treat any area without a completed restore test as Fail.&lt;/p&gt;</description></item><item><title>Capacity Planning</title><link>https://checklists.metacog.co.kr/docs/operations/capacity-planning/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/operations/capacity-planning/</guid><description>&lt;p&gt;Capacity planning is the discipline of knowing, before your users find out, where the system breaks and how long you have until you get there. It sits between load testing and cost management: measure what you have, forecast what you will need, and make sure the difference is bought or engineered with time to spare. This checklist follows that order.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the service owner with input from finance and whoever owns the infrastructure budget. &lt;strong&gt;When:&lt;/strong&gt; quarterly, before any expected demand event, and after any architectural change that alters the constraining resource.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="demand-model"&gt;1. Demand model &lt;a href="#demand-model" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The unit of demand is defined in business terms&lt;/strong&gt; — orders per minute, active sessions, or documents indexed, so that a product forecast translates directly into infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The peak-to-average ratio is measured, not assumed&lt;/strong&gt; — provisioning to the daily average guarantees failure at the daily peak, which is the only hour that matters.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Seasonal and weekly patterns are documented&lt;/strong&gt; — month-end batch runs, payday spikes, and campaign traffic each have a shape that averages hide entirely.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Known future events are on a calendar with expected multipliers&lt;/strong&gt; — marketing launches, partner integrations, migrations, and regulatory deadlines all have owners who can be asked.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Growth is forecast from at least twelve months of history where it exists&lt;/strong&gt; — a trend fitted to one quarter will mislead in either direction.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Internal demand is modelled alongside customer demand&lt;/strong&gt; — analytics jobs, backfills, and your own retrying clients frequently dominate the peak.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The forecast records its assumptions explicitly&lt;/strong&gt; — so that when reality diverges you can tell which assumption was wrong rather than rebuilding it from scratch.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="current-utilisation-and-the-constraining-resource"&gt;2. Current utilisation and the constraining resource &lt;a href="#current-utilisation-and-the-constraining-resource" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The constraining resource is identified per service&lt;/strong&gt; — CPU, memory, disk IOPS, network, database connections, or a third-party rate limit; everything else is secondary.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Utilisation is measured at peak, not averaged over the day&lt;/strong&gt; — an instance at 40% daily average can be saturated for two hours every evening.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Utilisation is tracked per instance as well as in aggregate&lt;/strong&gt; — an unbalanced shard or a hot partition saturates while the fleet average looks comfortable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Resources that are consumed monotonically have their own tracking&lt;/strong&gt; — disk usage, table sizes, and index growth only ever go one way and produce entirely predictable outages.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Connection pools and thread pools are counted as capacity&lt;/strong&gt; — database connection exhaustion is a far more common ceiling than raw CPU.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Provider quotas and service limits are inventoried&lt;/strong&gt; — API rate limits, instances per region, IP addresses, and load balancer rules all become the binding constraint eventually.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Efficiency is tracked as demand per unit of resource&lt;/strong&gt; — this is what tells you whether growth in cost is growth in traffic or growth in waste.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="headroom-and-safety-margins"&gt;3. Headroom and safety margins &lt;a href="#headroom-and-safety-margins" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A target headroom is defined and justified&lt;/strong&gt; — enough to absorb the loss of an availability zone plus the largest plausible traffic spike, not a number copied from another team.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Headroom accounts for the failure of the largest single unit&lt;/strong&gt; — losing one of three zones means the surviving two must carry the full peak.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The time required to add capacity is measured&lt;/strong&gt; — if provisioning takes two hours, headroom must cover two hours of growth plus the detection delay.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alerts fire on projected exhaustion, not only on current utilisation&lt;/strong&gt; — an alert saying disk will be full in six days is actionable; one saying disk is 95% full is an incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Headroom is validated after each scaling change&lt;/strong&gt; — reducing instance count for cost reasons quietly consumes the margin that was there for zone failure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Stateful components have separate, larger margins&lt;/strong&gt; — adding a database replica or resharding takes hours or days, unlike adding a stateless instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="load-testing-and-the-breaking-point"&gt;4. Load testing and the breaking point &lt;a href="#load-testing-and-the-breaking-point" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Load tests run against production-like infrastructure&lt;/strong&gt; — same instance classes, same database tier, same network topology, or the results describe a system you do not operate.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The test uses a realistic traffic mix&lt;/strong&gt; — replayed or modelled from production, since a single-endpoint benchmark tells you nothing about contention between endpoints.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The breaking point is known as a number&lt;/strong&gt; — the request rate at which latency crosses the SLO, and which component fails first when you get there.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Behaviour beyond the breaking point is characterised&lt;/strong&gt; — the system should degrade and shed load rather than collapse into a retry storm it cannot recover from.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Recovery from overload is tested, not just the overload itself&lt;/strong&gt; — many systems survive the spike and then fall over on the queued backlog when traffic returns to normal.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Soak tests run long enough to reveal leaks&lt;/strong&gt; — memory growth, file descriptor exhaustion, and connection leaks appear over hours, not over a ten-minute test.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Load test results are dated and re-run after significant changes&lt;/strong&gt; — a benchmark from two releases ago describes a system that no longer exists.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Common mistake:&lt;/strong&gt; load testing one service in isolation. The interesting failures happen at shared dependencies — the database, the cache, the identity provider — under the combined load of every caller, which single-service tests never produce.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="scaling-mechanisms"&gt;5. Scaling mechanisms &lt;a href="#scaling-mechanisms" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Autoscaling triggers on the constraining resource&lt;/strong&gt; — scaling on CPU when the bottleneck is database connections adds load to the thing that is already failing.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Scale-up is fast and scale-down is slow&lt;/strong&gt; — aggressive scale-down causes thrashing and leaves you short at the start of the next spike.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Maximum scaling limits are set and are affordable&lt;/strong&gt; — check the ceiling against the monthly budget, not only against the technical limit.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The system has been observed actually scaling under load&lt;/strong&gt; — autoscaling configuration is frequently wrong in ways only a real scale event reveals.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Cold start and warm-up time are accounted for&lt;/strong&gt; — an instance that takes three minutes to become useful cannot respond to a sixty-second spike.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Scaling one tier does not overwhelm another&lt;/strong&gt; — more application instances mean more database connections, and the database rarely scales on the same timescale.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Manual scaling procedures exist for when autoscaling fails or is too slow&lt;/strong&gt; — documented, and tested by someone who is not the person who wrote them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="protection-under-overload"&gt;6. Protection under overload &lt;a href="#protection-under-overload" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rate limiting protects the service from any single client&lt;/strong&gt; — including your own internal callers and your own retrying clients, which are the usual culprits.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Load shedding drops the least important work first&lt;/strong&gt; — a documented priority order lets you keep checkout working while analytics queries are rejected.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backpressure propagates rather than being absorbed silently&lt;/strong&gt; — an unbounded internal queue converts an overload into an unbounded latency increase and eventually a memory failure.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retries have a budget and use exponential backoff with jitter&lt;/strong&gt; — synchronised naive retries turn a brief slowdown into a self-inflicted denial of service.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Circuit breakers protect against a slow dependency&lt;/strong&gt; — timeouts alone still consume every thread while waiting.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Rejection under load is fast and cheap&lt;/strong&gt; — a request that is going to fail should fail immediately rather than consuming a connection for thirty seconds first.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cost-and-procurement"&gt;7. Cost and procurement &lt;a href="#cost-and-procurement" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Capacity cost per unit of demand is calculated&lt;/strong&gt; — cost per thousand requests or per active user is the number that makes a forecast financially meaningful.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The forecast is translated into a budget and shared with finance before the spend arrives&lt;/strong&gt; — capacity surprises are usually organisational failures rather than technical ones.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Committed-use discounts and reservations are sized against the forecast floor, not the peak&lt;/strong&gt; — over-committing is as costly as not committing at all.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Lead times for anything not instantly available are known&lt;/strong&gt; — GPU capacity, reserved instances, licences, and physical hardware all have procurement delays measured in weeks.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Budget alerts are configured at thresholds that leave time to react&lt;/strong&gt; — an alert at 100% of budget is a report, not a warning.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Idle and over-provisioned resources are reviewed regularly&lt;/strong&gt; — waste consumes the budget that would otherwise fund genuine headroom.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="review-cadence-and-ownership"&gt;8. Review cadence and ownership &lt;a href="#review-cadence-and-ownership" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Capacity is reviewed on a fixed schedule with a named owner&lt;/strong&gt; — quarterly for most services, monthly for anything growing quickly.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Forecast accuracy is measured against actuals each cycle&lt;/strong&gt; — a forecast that is never scored never improves.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A dashboard shows current utilisation against forecast demand and the breaking point&lt;/strong&gt; — so headroom is visible without anyone having to assemble it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Product roadmap changes trigger a capacity review&lt;/strong&gt; — a new feature that multiplies read volume needs to be known before it ships, not after.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Capacity findings feed the risk register with owners and dates&lt;/strong&gt; — an exhaustion date more than one review cycle away is a plan; one inside the cycle is an incident waiting.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;On-call engineers know the current headroom and where the limits are&lt;/strong&gt; — this is the context that turns an ambiguous latency page into a fast diagnosis.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Demand model&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Current utilisation and the constraining resource&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Headroom and safety margins&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Load testing and the breaking point&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Scaling mechanisms&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Protection under overload&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cost and procurement&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Review cadence and ownership&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record the projected exhaustion date for the constraining resource alongside the sign-off, and raise a dated ticket for every item marked &amp;ldquo;Pass with actions&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Data Pipeline Review</title><link>https://checklists.metacog.co.kr/docs/data/data-pipeline/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/data/data-pipeline/</guid><description>&lt;p&gt;Most data pipelines do not fail loudly. They succeed, quietly emit the wrong numbers, and nobody notices until a finance report disagrees with itself three weeks later. This review is about making a pipeline re-runnable, correct under late and duplicated input, and observable enough that a silent failure becomes a page. Work through it before the pipeline feeds a dashboard, a model, or a downstream team.&lt;/p&gt;

&lt;div class="alert alert-info d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 info
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Who runs this:&lt;/strong&gt; the owning data engineer plus one reviewer who consumes the output. &lt;strong&gt;When:&lt;/strong&gt; before the pipeline is promoted to production, and again whenever its source system or partitioning scheme changes.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="contracts-and-sources"&gt;1. Contracts and sources &lt;a href="#contracts-and-sources" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every source has a named owner and a documented delivery expectation&lt;/strong&gt; — what arrives, how often, and by what time, so a missing file is a broken promise rather than a surprise.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The read pattern from each source is agreed with its owner&lt;/strong&gt; — replica versus primary, snapshot versus CDC, and whether your query load is acceptable at their peak.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A data contract exists for each critical input&lt;/strong&gt; — column names, types, nullability, and semantic meaning, checked in with the pipeline rather than living in a wiki page nobody edits.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The pipeline pins an explicit column list rather than &lt;code&gt;SELECT *&lt;/code&gt;&lt;/strong&gt; — a new upstream column should not silently widen your table or reorder positional consumers.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Source-side deletes are handled deliberately&lt;/strong&gt; — decide whether a row disappearing upstream means soft delete, hard delete, or ignore, because CDC and snapshot loads behave differently here.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Timezone and clock semantics are documented per source&lt;/strong&gt; — whether timestamps are UTC, local, or session-dependent, and which clock (event, ingest, or processing) each column represents.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="idempotency-and-reprocessing"&gt;2. Idempotency and reprocessing &lt;a href="#idempotency-and-reprocessing" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Every ingestion job is idempotent on its partition key&lt;/strong&gt; — re-running a failed day must produce the same table state, not a second copy of the rows.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Writes use delete-and-insert per partition, &lt;code&gt;MERGE&lt;/code&gt; on a stable key, or an atomic partition swap&lt;/strong&gt; — plain &lt;code&gt;INSERT&lt;/code&gt; into a shared table is what turns a retry into duplicated revenue.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The natural key that identifies a record is defined and enforced&lt;/strong&gt; — a uniqueness test on that key is the cheapest duplicate detector you will ever write.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Re-running a task never depends on the outcome of a previous run&lt;/strong&gt; — no in-place counters, no reading the target table to decide what to write, no state hidden in a scratch file.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Output is written to a temporary location and promoted atomically&lt;/strong&gt; — a job that dies halfway must not leave a half-written table that a consumer can read.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Reprocessing a historical window is a documented, parameterised operation&lt;/strong&gt; — not a hand-edited copy of the DAG with the dates changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="alert alert-warning d-flex" role="alert"&gt;
 &lt;div class="flex-shrink-1 alert-icon"&gt;
 
 &lt;span class="material-icons size-20 me-2"&gt;
 warning
 &lt;/span&gt;&lt;/div&gt;
 
 &lt;div class="w-100"&gt;&lt;strong&gt;Blocking:&lt;/strong&gt; a pipeline whose re-run duplicates rows must not go to production. Every other item here can carry a dated follow-up ticket; non-idempotent writes cannot, because the first retry silently corrupts the table.&lt;/div&gt;
 &lt;/div&gt;
&lt;h2 id="late-and-out-of-order-data"&gt;3. Late and out-of-order data &lt;a href="#late-and-out-of-order-data" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Event time and processing time are separate columns&lt;/strong&gt; — conflating them makes every late arrival look like it happened when you happened to read it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The allowed lateness window is an explicit, documented number&lt;/strong&gt; — and it is derived from measured arrival distributions, not from a round number that felt safe.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Records arriving after the lateness window are routed somewhere visible&lt;/strong&gt; — a side-output table or dead-letter topic, counted and alerted on, never silently dropped.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Aggregates over a window are recomputed when late data lands&lt;/strong&gt; — or the window is explicitly declared immutable and consumers are told that late facts are lost.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Watermark or high-water-mark logic is tested against out-of-order input&lt;/strong&gt; — replay a shuffled batch in staging and assert the output matches the ordered run.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Restatement of already-published numbers has an agreed process&lt;/strong&gt; — who is told, how the correction is versioned, and whether downstream extracts are refreshed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="schema-evolution"&gt;4. Schema evolution &lt;a href="#schema-evolution" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Additive schema changes flow through without a manual deploy&lt;/strong&gt; — a new nullable upstream column should not break the load, and it should not silently vanish either.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Breaking changes are detected before the write, not after&lt;/strong&gt; — a type change or dropped column fails the run with a clear error rather than writing nulls.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A schema registry or equivalent enforces compatibility for streaming sources&lt;/strong&gt; — backward compatibility for consumers, forward compatibility for producers, chosen deliberately.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Column type widening is planned rather than discovered&lt;/strong&gt; — an integer id that becomes a string upstream will otherwise fail at the worst possible time.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Schema changes are versioned in the repository and reviewed like code&lt;/strong&gt; — including the migration for any already-written historical partitions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Downstream consumers are notified before a column is renamed or removed&lt;/strong&gt; — with a deprecation period long enough for them to actually act.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="partitioning-storage-and-layout"&gt;5. Partitioning, storage, and layout &lt;a href="#partitioning-storage-and-layout" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The partition column matches the dominant query filter&lt;/strong&gt; — partitioning by ingest date while every consumer filters on event date guarantees full scans.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Partition granularity is chosen against data volume&lt;/strong&gt; — hourly partitions on a small table produce millions of tiny files and a metadata problem worse than the scan you avoided.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Small-file compaction runs on a schedule for streaming or micro-batch outputs&lt;/strong&gt; — file count, not row count, is what eventually makes the table unqueryable.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;File format and compression are deliberate&lt;/strong&gt; — columnar formats such as Parquet or ORC for analytical reads, with a codec chosen for the read/write ratio you actually have.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Table statistics or manifests are refreshed after each load&lt;/strong&gt; — a stale catalogue makes the query planner choose badly and hides newly written partitions.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retention and archival are enforced by a job&lt;/strong&gt; — an unbounded table is a cost problem and, where personal data is involved, a compliance problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="orchestration-retries-and-dependencies"&gt;6. Orchestration, retries, and dependencies &lt;a href="#orchestration-retries-and-dependencies" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Tasks declare their data dependencies rather than relying on schedule ordering&lt;/strong&gt; — a job that starts at 02:00 because the upstream usually finishes at 01:45 will eventually read yesterday&amp;rsquo;s data.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Retries use bounded attempts with exponential backoff&lt;/strong&gt; — and retry only on transient errors, because retrying a schema violation twelve times just delays the alert.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A task that is already running cannot be started twice&lt;/strong&gt; — concurrency limits and run-key locking prevent two backfills writing the same partition simultaneously.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Task timeouts are set below the point at which the run blocks the next scheduled run&lt;/strong&gt; — a hung task with no timeout silently stops the whole schedule.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Sensors and polling have a deadline and a failure path&lt;/strong&gt; — an infinite wait for a file that will never arrive is an outage that never pages anyone.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The DAG can be resumed from the failed task&lt;/strong&gt; — a four-hour pipeline that must restart from step one after a step-nine failure will not be recoverable during an incident.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Credentials come from a secret manager at run time&lt;/strong&gt; — not from connection strings in the DAG file or variables committed to the repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="backfills"&gt;7. Backfills &lt;a href="#backfills" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A backfill runs through the same code path as the scheduled run&lt;/strong&gt; — a separate backfill script drifts from production logic and produces history that does not match the present.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backfills are rate-limited and resource-capped&lt;/strong&gt; — an unthrottled 400-day backfill will saturate the warehouse and take the daily load down with it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The backfill is tested on one partition and verified before the full range is launched&lt;/strong&gt; — compare row counts and a few aggregates against the existing data.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Downstream consumers are informed before a backfill overwrites published history&lt;/strong&gt; — dashboards and extracts change underneath people otherwise.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Backfills can be paused and resumed&lt;/strong&gt; — and a partially completed backfill leaves the table in a consistent, identifiable state.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The cost of the backfill is estimated before it is run&lt;/strong&gt; — full-history reprocessing on a metered warehouse is one of the most common surprise invoices.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="freshness-quality-gates-and-monitoring"&gt;8. Freshness, quality gates, and monitoring &lt;a href="#freshness-quality-gates-and-monitoring" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A freshness SLA is defined per output table&lt;/strong&gt; — the maximum acceptable age of the newest record, agreed with the consumers who depend on it.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Freshness is monitored from the table, not from the scheduler&lt;/strong&gt; — a green DAG run that wrote zero rows is the failure mode this catches.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Row-count anomaly detection is in place for each load&lt;/strong&gt; — an absolute floor plus a deviation band against the trailing average catches both empty and duplicated loads.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Quality tests run as a gate before publication, not as a report afterwards&lt;/strong&gt; — failing tests should stop the swap into the consumer-visible table.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Null rate, distinct count, and range checks are asserted on business-critical columns&lt;/strong&gt; — the ones that feed revenue, headcount, or a regulatory report.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Pipeline logs are structured and carry the run id and partition&lt;/strong&gt; — so an investigation starts from a query rather than from scrolling.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Alerts distinguish a failed run from a stale table&lt;/strong&gt; — they have different causes and different responders, and one can happen without the other.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Column-level lineage is available for critical outputs&lt;/strong&gt; — when a number looks wrong, tracing it to the source column should take minutes, not a day.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cost-and-efficiency"&gt;9. Cost and efficiency &lt;a href="#cost-and-efficiency" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;The cost per run is measured and attributed to the pipeline&lt;/strong&gt; — query tags, job labels, or a dedicated warehouse make this attributable rather than a shared mystery.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Incremental processing is used wherever the source supports it&lt;/strong&gt; — full-table reloads scale linearly with history and eventually stop finishing overnight.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Queries prune partitions as intended&lt;/strong&gt; — check the query plan or bytes-scanned figure rather than assuming the filter was pushed down.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;Compute is sized against the job rather than the largest job on the platform&lt;/strong&gt; — and it scales down or shuts off when idle.&lt;/li&gt;
&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; &lt;strong&gt;A budget alert exists for the pipeline&amp;rsquo;s warehouse or cluster&lt;/strong&gt; — set at a threshold that leaves time to react before month end.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sign-off"&gt;Sign-off &lt;a href="#sign-off" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Area&lt;/th&gt;
 &lt;th&gt;Reviewer&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Outcome&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Contracts and sources&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Idempotency and reprocessing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Late and out-of-order data&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Schema evolution&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Partitioning, storage, and layout&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Orchestration, retries, and dependencies&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Backfills&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Freshness, quality gates, and monitoring&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cost and efficiency&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Pass / Pass with actions / Fail&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Record every &amp;ldquo;Pass with actions&amp;rdquo; as a dated ticket with a named owner before the pipeline is scheduled in production.&lt;/p&gt;</description></item><item><title>Data Quality</title><link>https://checklists.metacog.co.kr/docs/data/data-quality/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/data/data-quality/</guid><description>&lt;p&gt;Data quality work fails in a predictable way: a team writes a hundred tests, they all run after publication, half of them are noisy, and everyone learns to ignore the channel they post to. This checklist is about the opposite — a small set of tests that block publication, clear ownership of what &amp;ldquo;correct&amp;rdquo; means, and a way to tell whether trust in a dataset is going up or down. Use it when adopting a new critical dataset, or when a set of numbers has lost the confidence of the people who use it.&lt;/p&gt;</description></item><item><title>ML Model Deployment</title><link>https://checklists.metacog.co.kr/docs/data/ml-model-deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/data/ml-model-deployment/</guid><description>&lt;p&gt;A model that scores well offline can still be a bad deployment: the features it sees in production differ from the ones it trained on, nobody can reproduce the artefact six months later, and there is no way back once traffic is on it. This checklist treats the model as a production service with unusual failure modes — silent degradation, feedback loops, and correctness that depends on data you do not control. Work through it before the model serves real decisions.&lt;/p&gt;</description></item><item><title>Data Warehouse Migration</title><link>https://checklists.metacog.co.kr/docs/data/data-warehouse-migration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/data/data-warehouse-migration/</guid><description>&lt;p&gt;Warehouse migrations rarely fail on the technical load. They fail because nobody knew who used the seventeen-year-old table, because the two systems round differently and the numbers never quite matched, or because the old platform stayed switched on for three years after cutover. This checklist follows the migration in the order it actually happens — inventory, build, dual-run, reconcile, cut over, decommission — and assumes you will need to prove equivalence to people who do not trust the new system yet.&lt;/p&gt;</description></item><item><title>Network Change</title><link>https://checklists.metacog.co.kr/docs/networking/network-change/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/networking/network-change/</guid><description>&lt;p&gt;Network changes are unusual among production changes because the thing you are modifying is the same thing carrying your management session. A bad line in an access list, a VLAN typo, or a routing policy that withdraws the wrong prefix can remove your own path to the device a fraction of a second after you press enter. This checklist is a change-window runbook: capture a baseline, understand the blast radius, arrange a way back in, make the change, verify it, and know exactly how to undo it.&lt;/p&gt;</description></item><item><title>DNS Migration</title><link>https://checklists.metacog.co.kr/docs/networking/dns-migration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/networking/dns-migration/</guid><description>&lt;p&gt;DNS migrations are unforgiving because the mistake is invisible at the moment you make it and becomes visible to users hours later, spread unevenly across the internet as caches expire. The work that determines whether a migration is boring happens days before the cutover: lowering TTLs, inventorying every record, and proving the new provider answers identically to the old one. This checklist is ordered in time, from roughly a week out to a week after.&lt;/p&gt;</description></item><item><title>TLS Certificate Management</title><link>https://checklists.metacog.co.kr/docs/networking/tls-certificate/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/networking/tls-certificate/</guid><description>&lt;p&gt;Almost every certificate outage has the same shape: something was issued once by hand, the person who did it moved on, and the calendar reminder went to a mailbox nobody reads. The rest are caused by an incomplete chain that works in a browser and fails in every non-browser client. This checklist covers issuance and key handling, chain and SAN correctness, automated renewal and the monitoring that proves it is working, the TLS configuration itself, and what to do when a certificate expires anyway.&lt;/p&gt;</description></item><item><title>Load Balancer Configuration</title><link>https://checklists.metacog.co.kr/docs/networking/load-balancer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/networking/load-balancer/</guid><description>&lt;p&gt;A load balancer is the component most likely to be blamed for an outage and least likely to have caused it on its own. Its defaults are chosen to be safe for a generic workload, and almost every one of them — health check interval, idle timeout, draining period, stickiness — interacts with something specific about your backend. This checklist works through those interactions, with particular attention to the relationship between the load balancer&amp;rsquo;s timeouts and the backend&amp;rsquo;s own.&lt;/p&gt;</description></item><item><title>GDPR Readiness</title><link>https://checklists.metacog.co.kr/docs/compliance/gdpr-readiness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/compliance/gdpr-readiness/</guid><description>&lt;p&gt;GDPR compliance is not a document exercise. A supervisory authority asking questions after a complaint will want to see the record of processing, the retention job that actually deletes data, the ticket trail behind a subject access request, and the transfer assessment behind the analytics vendor in the United States. This checklist covers the engineering and operational work that makes those artefacts real rather than aspirational, and is aimed at teams that build and run the systems where personal data lives.&lt;/p&gt;</description></item><item><title>ISO/IEC 27001 ISMS</title><link>https://checklists.metacog.co.kr/docs/compliance/iso27001-isms/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/compliance/iso27001-isms/</guid><description>&lt;p&gt;An ISO/IEC 27001 certification audit does not test whether your security is good. It tests whether you have a management system that identifies risk, treats it deliberately, checks itself, and corrects itself — and whether you can prove all of that with records. Most first-time failures are not control failures; they are missing evidence that the management cycle actually ran. This checklist walks the clauses and the Annex A implementation work in the order an auditor tends to open them.&lt;/p&gt;</description></item><item><title>SOC 2 Audit Readiness</title><link>https://checklists.metacog.co.kr/docs/compliance/soc2-audit-readiness/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/compliance/soc2-audit-readiness/</guid><description>&lt;p&gt;A SOC 2 Type II report is an opinion on whether your controls operated effectively over a period, and the auditor forms that opinion by sampling evidence from across the window. The window is unforgiving: a control that started working in month five leaves four months of exceptions that cannot be repaired afterwards. This checklist is about getting the control set, the narratives, and the evidence pipeline in place before the clock starts, and keeping them intact while it runs.&lt;/p&gt;</description></item><item><title>Vendor Security Assessment</title><link>https://checklists.metacog.co.kr/docs/compliance/vendor-security-assessment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/compliance/vendor-security-assessment/</guid><description>&lt;p&gt;Most organisations lose control of their data at the third hop: a vendor you assessed uses a sub-processor you never saw, running in a region you did not approve. Third-party assessment is worth doing properly only if the effort is proportionate to what the vendor can actually reach, and only if the assessment carries through into the contract, the monitoring, and the day the relationship ends. This checklist covers that full lifecycle for engineering and procurement teams.&lt;/p&gt;</description></item><item><title>Employee IT Onboarding</title><link>https://checklists.metacog.co.kr/docs/itsm/employee-it-onboarding/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/itsm/employee-it-onboarding/</guid><description>&lt;p&gt;Onboarding is the moment an organisation decides how much access a stranger gets, usually under time pressure and usually by copying somebody else&amp;rsquo;s permissions. Done well it is boring: the account, the device, and the entitlements all exist before the person does, and each one is traceable to an approved request. Work through this in time order — before day one, day one, first week, first month — and treat the manager attestation at the end as the real completion criterion, not the laptop handover.&lt;/p&gt;</description></item><item><title>Employee IT Offboarding</title><link>https://checklists.metacog.co.kr/docs/itsm/employee-it-offboarding/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/itsm/employee-it-offboarding/</guid><description>&lt;p&gt;Offboarding is judged on two axes: speed and completeness. Speed matters because the risk window is the gap between the person&amp;rsquo;s last moment of goodwill and the moment their last credential stops working. Completeness matters because attackers and disgruntled leavers do not use the front door you remembered to lock — they use the forgotten local account, the personal access token, the shared credential nobody rotated. Run this the same way every time, whether the departure is amicable or not.&lt;/p&gt;</description></item><item><title>Change Management</title><link>https://checklists.metacog.co.kr/docs/itsm/change-management/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/itsm/change-management/</guid><description>&lt;p&gt;Change management exists to stop two failure modes: the risky change that nobody reviewed, and the review process so heavy that people route around it. The balance comes from classification — most changes should be pre-approved standard changes that flow through automation, leaving human attention for the genuinely novel ones. Use this checklist for a normal change heading to a change advisory board, and use the emergency section when something is already on fire.&lt;/p&gt;</description></item><item><title>Disaster Recovery Drill</title><link>https://checklists.metacog.co.kr/docs/itsm/disaster-recovery-drill/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/itsm/disaster-recovery-drill/</guid><description>&lt;p&gt;A disaster recovery plan that has never been executed is a document, not a capability. The point of a drill is to convert assumptions into measurements: how long recovery actually takes, how much data is actually lost, and which step in the runbook turns out to reference a server that was decommissioned two years ago. Run this in time order — choose the scenario, bound the blast radius, tell the right people, execute, measure, and write it up — and resist the urge to pick a scenario you already know you will pass.&lt;/p&gt;</description></item><item><title>IT Asset Management</title><link>https://checklists.metacog.co.kr/docs/itsm/it-asset-management/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://checklists.metacog.co.kr/docs/itsm/it-asset-management/</guid><description>&lt;p&gt;Asset management is unglamorous until the moment it matters: a vulnerability advisory lands and you need to know which machines are affected, a vendor opens a licence audit, or a leaver fails to return a laptop that nobody recorded issuing. The register is not the goal — an accurate register that reconciles against the systems that actually see the assets is. Work through this as a periodic review of the asset management practice rather than as a one-off inventory exercise.&lt;/p&gt;</description></item></channel></rss>