Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when changing the database schema - detect the repo's migration tool, ship a new migration in its layout, never edit an applied one, and avoid lock-unsafe DDL on a live table
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Migrations are append-only history that must replay identically on every environment, forever. The cardinal sin is editing a migration that has already run somewhere — it makes environments diverge silently. The second most common mistake is DDL that locks a live table for longer than the app can tolerate.
Core principle: a wrong migration is fixed by a NEW migration, never by editing the old one; and rollback_release reverts code only, so the schema your migration leaves behind must keep working with the previous release's code until a later task removes what it replaced.
| Tool | How to recognise it | Down migration | Outside a transaction |
|---|---|---|---|
| golang-migrate | *.up.sql / *.down.sql pairs | its own .down.sql file | each CONCURRENTLY statement needs its own migration file (no implicit transaction wrapping across files) |
| goose | -- +goose Up / -- +goose Down in one file | same file, Down section | -- +goose NO TRANSACTION directive |
| Flyway | V<n>__name.sql | none in the open-source edition | follow Flyway's own non-transactional DDL rules |
| Liquibase | changesets (XML/YAML/SQL) | rollback block | per changeset runInTransaction |
| Atlas | atlas.hcl + versioned migrations | — | — |
| Up-only numbered SQL | plain numbered .sql files, no down files (e.g. this repo's own server/migrations/) | none exists — don't invent one | — |
Never introduce a different migration tool into a repo that already has one, and never add down files to a repo that has none — follow what's there (rule repo-conventions-win).
hbm2ddl=update, Quarkus schema generation) outside tests — schema comes from migrations only (java-persistence).IF NOT EXISTS, ON CONFLICT, WHERE guards on backfills so a re-run does no harm.SET lock_timeout = '5s'; so a blocked ALTER fails fast and visibly instead of queueing behind other locks and blocking every other statement on the table.rollback_release actually doesrollback_release reverts the application code only — it never runs a down migration. Two consequences:
rollback_plan must say whether the down migration is actually safe to run, because by the time anyone reaches for it, the new schema may already hold data the down migration would silently drop. Write what you'd tell the human, e.g. "Migration 045 is additive; reverting the code is enough. Do NOT run its down migration — it drops the priority column and any values written to it since deploy." A migration that is purely additive needs no down-migration caveat at all; say that instead.migrate up with "no migration found for version 45" — decide whether to keep the schema (most common) and run migrate ... force 44 to re-sync the tool's bookkeeping, rather than trying to re-apply a file that no longer exists.| Change | Unsafe (locks / rewrites the table) | Safe |
|---|---|---|
| Add index | CREATE INDEX | CREATE INDEX CONCURRENTLY IF NOT EXISTS (its own migration, outside a transaction) |
| Foreign key | ADD CONSTRAINT ... FOREIGN KEY ... (validates existing rows under lock) | ... NOT VALID, then VALIDATE CONSTRAINT in a later migration |
NOT NULL on an existing column | ALTER COLUMN ... SET NOT NULL (full scan under lock on PG <12) | CHECK (col IS NOT NULL) NOT VALID → VALIDATE CONSTRAINT → SET NOT NULL (PG ≥12 skips the re-scan once validated); PG 18 also has SET NOT NULL ... NOT VALID directly |
| Add column | A volatile default (DEFAULT now(), DEFAULT random()) rewrites the table | A constant default is metadata-only since PG 11; for a volatile default, add the column nullable, backfill, then add the default/constraint |
| Change column type | ALTER COLUMN ... TYPE ... (table rewrite) | New column + backfill + switch reads/writes, drop the old one later |
| Rename or drop column/table | RENAME breaks the previous release's code immediately | Expand/contract: add the new name, dual-write/read, switch, drop later |
| Backfill existing rows | A single large UPDATE (long lock, huge transaction) | Batched UPDATE ... WHERE id IN (SELECT id FROM t WHERE ... LIMIT 5000), looped, outside the DDL transaction |
timestamptz (never bare timestamp); text with a CHECK constraint instead of varchar(n); bigint generated always as identity or uuid DEFAULT uuidv7() (PG 18+, time-ordered) / gen_random_uuid(); numeric for money, never float/money; UNIQUE NULLS NOT DISTINCT where NULL should count toward the uniqueness check (PG 15+).
Adding a required priority column with an index, on golang-migrate:
-- 043_task_priority.up.sql
ALTER TABLE tasks ADD COLUMN priority TEXT NOT NULL DEFAULT 'medium';
-- 043_task_priority.down.sql
ALTER TABLE tasks DROP COLUMN IF EXISTS priority;
-- 044_task_priority_index.up.sql
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_tasks_priority ON tasks (priority);
-- 044_task_priority_index.down.sql
DROP INDEX CONCURRENTLY IF EXISTS idx_tasks_priority;
NOT NULL ... DEFAULT 'medium' is a constant default: metadata-only on PG 11+, no table rewrite, every existing row reads as 'medium'. The index is a separate migration because CREATE INDEX CONCURRENTLY cannot run inside the transaction golang-migrate wraps each file in. rollback_plan: "045/044 are additive; reverting the code is enough, do not run the down migrations unless the column is confirmed unused."
❌ CREATE INDEX idx_tasks_priority ON tasks (priority); inside the same migration as the column add — locks the table for the full index build, and squawk's require-concurrent-index-creation flags exactly this.
npx --yes squawk-cli <new-file>.sql (or pip install squawk-cli) — fix or explicitly justify every warning it raises (rule IDs like require-concurrent-index-creation, constraint-missing-not-valid, adding-required-field, changing-column-type, renaming-column, ban-drop-column, prefer-identity, prefer-text-field, prefer-timestamptz, require-timeout-settings double as a checklist even without running the tool).postgres:18 container before calling it done.psql -c '\d+ <table>' to confirm the resulting schema matches what you intended.CREATE INDEX (not CONCURRENTLY) on a table already receiving traffic.UPDATE instead of batches.rollback_plan left blank on a migration task, or claiming the down migration is safe without checking whether data was written since deploy.hbm2ddl/auto-DDL thinking — schema comes from migrations only.NOT NULL or type-change migration with no expand/contract story and no mention in rollback_plan.squawk warnings left unaddressed with no comment explaining why.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
日本語の概要は準備中です。原文の説明を表示しています。
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
日本語の概要は準備中です。原文の説明を表示しています。
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
日本語の概要は準備中です。原文の説明を表示しています。
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
日本語の概要は準備中です。原文の説明を表示しています。
Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation
日本語の概要は準備中です。原文の説明を表示しています。