From 7dabcd1317555f026b97c1d8912781b384abd0d5 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Wed, 24 Jun 2026 14:39:00 +0200 Subject: [PATCH] chore: track the deploy-check skill in the repo The deploy-check skill is repo-specific: it encodes this project's hard-won pre-deploy runtime constraints (distroless nonroot, edge Alt-Svc/HTTP3, caddy recreate, DICT_VERSION boot, expand-contract migrations, the Telegram permission model) and points at deploy/README.md, docs/ARCHITECTURE.md, docs/EDGE_HTTP3.md and the agent memory files. It belongs with the deploy logic it guards, not in the global config, so it travels with the repo and stays versioned alongside it. --- .claude/skills/deploy-check/SKILL.md | 89 ++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .claude/skills/deploy-check/SKILL.md diff --git a/.claude/skills/deploy-check/SKILL.md b/.claude/skills/deploy-check/SKILL.md new file mode 100644 index 0000000..1983334 --- /dev/null +++ b/.claude/skills/deploy-check/SKILL.md @@ -0,0 +1,89 @@ +--- +name: deploy-check +description: "Use before any deploy-touching change to this repo — phrases like '/deploy-check', 'is this prod-safe', 'before we deploy', 'deploy safety review', 'проверь перед деплоем', 'это безопасно для прода'. Runs a pre-deploy checklist of this project's hard-won runtime constraints against the current diff, so the crash classes that have bitten live environments get caught before shipping instead of after." +--- + +# Pre-deploy runtime-constraint check + +Triggered before shipping anything that touches the deploy contour (Dockerfiles, +`deploy/`, Caddyfile, compose, migrations, boot guards, the Telegram side-service, +edge config). The worst frictions in this repo were never logic bugs — they were +**environment mismatches that crashed a live env and forced a redesign**. Run this +list against the diff first; turn crash-and-redesign into a single pass. + +This checklist is a prompt, **not** the source of truth. The canonical detail +lives in `deploy/README.md`, `docs/ARCHITECTURE.md`, `docs/EDGE_HTTP3.md`, and the +agent memory files referenced below — read them when an item is in play, and add a +new class here when a new incident teaches one. + +## How to run it + +1. `git diff ...HEAD --stat` to see what the change actually touches. +2. For every risk class below that the diff touches, perform the **Check** and + report PASS / FAIL with the exact file:line to fix. Skip classes the diff does + not touch — say which you skipped and why. +3. Remember: **deploy-job green ≠ healthy**. CI's deploy probe has historically + passed with a dead backend (it only checked static landing+gateway). Verify the + real feature live (`/readyz`, the actual flow) after deploy, not just the green. + +## Risk classes + +### 1. Container user — distroless nonroot UID 65532 +- **Bit us:** TLS keys `chmod 600` for the host owner crash-looped gateway + bot at + boot with "permission denied" — service images run UID 65532. +- **Check:** any new/changed mounted secret, key, or config file must be readable by + UID 65532 (`0644`, not `0600`). Scan the diff for file modes, `chmod`, and new + volume mounts. (memory: `distroless-nonroot-mounted-secrets`) + +### 2. Caddy header pipeline ordering +- **Bit us:** `header_up delete` after `set` nulled the value (the honeypot tag went + empty); it passed CI and only showed up live. +- **Check:** in any Caddyfile change, verify the `set` / `delete` / `header_up` + ordering for every affected route, and test the tripwire/route on the live + contour, not just CI. + +### 3. Edge Alt-Svc / HTTP3 +- **Bit us:** edge advertised `Alt-Svc: h3` while UDP/443 was never exposed + (docker tcp-only + ufw tcp-only); clients cached it 30 days and stalled on dead + QUIC before falling back to h2 — Mini App "hangs on load". +- **Check:** any edge/caddy change keeps `Alt-Svc: clear` (or only advertises h3 if + UDP/443 is genuinely exposed). (memory: `tg-app-load-stall-dead-http3-altsvc`, + `docs/EDGE_HTTP3.md`) + +### 4. Prod caddy config recreate +- **Bit us:** prod rolling deploy did **not** recreate caddy on a config-only change + (pinned `caddy:2-alpine` + `admin off`), so a new Caddyfile deployed GREEN but + stayed inert until a manual `docker restart`. +- **Check:** a config-only edge change must `--force-recreate` caddy in + `prod-deploy.sh` `roll()`; never trust deploy-green for edge config. + (memory: `prod-deploy-caddy-config-recreate`) + +### 5. DICT_VERSION / dictionary boot +- **Bit us:** an early `DICT_VERSION` refuse-boot guard was wrong and crashed the + live env when bumped on a seeded volume; it had to be redesigned to "marker-wins". +- **Check:** any change touching `DICT_VERSION`, dict load, or the boot guard must + keep marker-wins semantics and survive a seeded volume **and** an image rollback. + `DICT_VERSION` is a required build-arg (no default), single-sourced. A new dict + goes live via the admin console upload, not a redeploy. (memory: + `dict-version-deploy-verify`, `contour-schema-change-wipe`) + +### 6. Migrations — expand-contract + rollback safety +- **Bit us / risk:** a non-backward-compatible migration breaks image rollback (DB + ahead of rolled-back code). +- **Check:** migrations must be **expand-contract** (backward-compatible). A schema + change adds the maintenance window + a consistent `pg_dump` in prod-deploy. On the + **test contour**, a schema/wire-label change needs `DROP SCHEMA backend CASCADE` + + backend restart (new code vs old persisted DB), else the contour breaks. (memory: + `contour-schema-change-wipe`) + +### 7. Telegram permission model +- **Bit us:** permissions are an **AND-intersection** — default-allow with explicit + denies, not default-deny; inverting it broke access. +- **Check:** any change to the Telegram permission / relay logic preserves the + AND-intersection default-allow shape. (memory: `telegram-forum-relay-gotchas`) + +## Output + +A short PASS/FAIL table over the classes the diff touches, each FAIL with the exact +file:line and the fix. If every touched class passes, say so plainly and name the +post-deploy live check to run (not just "CI green"). -- 2.52.0