prisma-next-migration-review について
デプロイ時やブランチ間の変更が競合する際に、Prisma Next のマイグレーションをレビューするためのスキルです。状態、グラフ上の経路、ref、診断情報を解説し、マイグレーションの作成は扱いません。
主な機能
- 01起点、到達先、マイグレーショングラフの解説
- 02適用済み・保留・到達不能の確認
- 03構造化された診断情報の解釈
- 04並行マイグレーション競合のレビュー
- 05環境 ref の管理
活用シーン
- 01staging デプロイ時のマイグレーション確認
- 02複数環境のマイグレーション状態の把握
- 03並行ブランチのリベース後に古い計画を解消
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ prisma/ prisma-next --skill prisma-next-migration-reviewインストール後、Claude Code で/prisma-next-migration-reviewを入力して読み込まれたか確認します。
詳細
Prisma Next — マイグレーションレビュー(デプロイと並行作業)
データコントラクトを編集すれば、あとは Prisma に任せられます。
このスキルで扱うのは、マイグレーションの作成ではなくレビューです。デプロイ時や、複数の開発者が同時にマイグレーションを取り込むときに生じる疑問を扱います。
このスキルでは、システムのメンタルモデル、つまり ref とは何か、マーカーとは何か、マイグレーショングラフとは何かを学び、システムに状態を問い合わせる方法を紹介します。厳密な手順を順番に定めるものではありません。ほとんどの「レビュー」に関する疑問は、モデルを理解して適切な対象を問い合わせれば解決できます。厳密な手順を定めるのは、安全な方法が文字どおり一つしかないまれなケースに限られます。
使用する場面
- ユーザーが 「これをマージしたら、どのマイグレーションが実行されますか?」 や 「デプロイ時に何が実行されますか?」 と尋ねたとき。
- 並行マイグレーションの競合が発生したとき(ブランチを開いている間に
mainが進んだ場合)。 - CI からデプロイできるように、
staging/productionの ref を設定したいとき。 - ローカルの開発用 DB 以外の環境に対してマイグレーションを実行したいとき。
- マイグレーションの CI 連携について尋ねられたとき。
使用しない場面
- ユーザーがマイグレーションを作成したい →
prisma-next-migrations。 - ユーザーが単一環境のハッシュ不一致/ドリフトを修正したい →
prisma-next-migrations(再計画の手順)またはprisma-next-debug(エンベロープ主導)。 - ユーザーがコントラクトを編集したい →
prisma-next-contract。
主要な概念 — ナビゲーションモデル
すべてのマイグレーションに関する疑問は、起点から到達先へのナビゲーションです。 このモデルを理解すれば、このスキルの残りは「どのナビゲーションについて、どのコマンドでシステムに問い合わせるか」という話になります。
起点
起点は、データベースの現在のコントラクトハッシュです。データベースには PN のマーカー用テーブルの行があり、*「このデータベースはハッシュ X の状態です」*と記録されています。CLI がオンラインで実行される場合(--db <url> が指定されている、または prisma-next.config.ts に db.connection が設定されている場合)、PN はマーカーを読み取り、そのハッシュが起点になります。オフライン(DB 接続がない場合)では、起点は不明です。そのため、多くのコマンドはディスク上のマイグレーションの一覧表示にとどまり、エッジごとの適用済み/保留中のステータスを省略します。
したがって、稼働中の DB が起点の信頼できる情報源です。他のアーティファクト(refs、ローカルキャッシュ、ユーザーの想定)にある「記録されたマーカー」は作業用コピーであり、実際の状態からずれることがあります。稼働中の DB の状態がずれることはありません。
到達先
到達先は、データベースをその状態にしたいコントラクトハッシュです。到達先の指定方法は 2 通りあります。
--to <name>—migrations/app/refs/<name>に保存された、ハッシュを指す名前付きポインターです。ref は慣例として環境名(staging、production)を付け、*「ここが本番環境の想定される状態です」*と示します。ref 自体はハッシュと、任意で設定される必須不変条件のセットにすぎず、どの DB に接続するかとは関係ありません。- 現在のコントラクトヘッド —
--toを指定しない場合に暗黙的に使われます。これは、ディスク上の現在のcontract.jsonのハッシュです。
--to staging は「staging データベースに接続する」という意味ではありません。「接続したデータベース(--db または設定経由)を、この ref が指すハッシュに向けてナビゲートする」という意味です。データベースの選択は独立しているため、実際に staging を指定するには --db $STAGING_DATABASE_URL を渡します。
マイグレーショングラフ
ディスク上のマイグレーションは有向グラフを形成します。ノードはコントラクトハッシュ、エッジはマイグレーションです。 各マイグレーションには from ハッシュと to ハッシュが宣言されています。データベースの現在のマーカーがその from ハッシュと一致する場合にのみマイグレーションが適用され、実行されるとマーカーはその to ハッシュに進みます。
migration status は、起点から到達先までの経路をグラフに問い合わせ、エッジごとのステータスを報告します。
- applied —
EMPTY_CONTRACT_HASHからマーカーまでの経路上にあるもの(履歴)。 - pending — マーカーから到達先までの経路上にあるもの(実行されるマイグレーション)。
- unreachable —
EMPTY_CONTRACT_HASHから到達先までの経路上にあるものの、マーカーは別のブランチにあり、先に経路を変更しない限り到達しません。
診断コード
migration status は、結果エンベロープ(diagnostics[].code)に構造化された診断情報を出力します。これにより、エージェントは概要文を解析するのではなく、コードに基づいて処理を分岐できます。各診断には、severity(warn または info)、人が読める message、および hints(CLI が概要行の下に表示するものと同じヒント)も含まれます。
| コード | 重大度 | ナビゲーションモデルでの意味 | 次の操作 |
|---|---|---|---|
MIGRATION.UP_TO_DATE | info | マーカーは移行先と一致しています。たどるエッジはありません。 | 操作は不要です。 |
MIGRATION.DATABASE_BEHIND | info | マーカーは移行先の祖先です。その間に保留中のエッジが N 個あります。 | migrate --to <name> --db $URL。 |
MIGRATION.MISSING_INVARIANTS | info | マーカーは構造上は移行先に到達していますが、ref が宣言する必須の不変条件が不足しています。 | それらを網羅する経路をたどるには、migrate --to <name> --db $URL を実行します。 |
MIGRATION.NO_MARKER | warn | オンラインですが、データベースにマーカー行がありません。初期化されていません。 | migrate --db $URL(最初の適用時にマーカーが書き込まれます)。 |
MIGRATION.MARKER_NOT_IN_HISTORY | warn | オンラインですが、マーカーのハッシュがグラフ内のノードではありません。データベースが移行システム外で変更されています。 | どちらを正とするか判断します。db sign(DB を正として受け入れる)、db update(コントラクトを DB に反映する)、contract infer(DB からコントラクトを再導出する)、または db verify(まず状態を確認する)を実行します。MIGRATION.MARKER_MISMATCH とは異なります。MARKER_NOT_IN_HISTORY は、ライブマーカーがたどっている経路から外れている場合にランナーのグラフ探索中に出力されます。一方、MARKER_MISMATCH は、マーカーハッシュがグラフ内のどのノードでもない場合に、CLI の DDL 前ゲートでそれより先に出力されます。 |
MIGRATION.DIVERGED | warn | 有効なリーフが複数あるため、移行先があいまいです。 | --to <name> を渡すか、ref set <name> <hash> を実行して 1 つ作成します。 |
CONTRACT.AHEAD | warn | コントラクトのヘッドがグラフ内にありません。再計画せずにコントラクトが編集されています。 | migration plan を実行してグラフを拡張します。 |
CONTRACT.UNREADABLE | warn | contract.json を読み取れませんでした。 | contract emit を実行して再生成します。 |
グラフツリーの出力
migration status(および migration list)は、移行グラフをターミナル上に色分けされたレーンツリーとして表示します。表示方法は 2 つのフラグで制御できます。
--legend— ツリーの前に、ツリー記号とレーンの色を示す凡例を表示します。--ascii— 枠線用の記号をパイプで扱える ASCII 文字に置き換えます(CI ログや Unicode に対応していない環境で便利です)。
どちらのフラグも migration list と migration graph で使用できます。migration log がサポートするのは --ascii のみです(ツリーではなく、時系列順のフラットなテーブルを表示します)。
Plan および apply 時の診断
これらのコードは migration plan、ref set、migrate で表示されます。migration status では表示されません。Migration System § Recovery affordances と ADR 218 を参照してください。
| コード | 発生時 | 意味 | 次の手順 |
|---|---|---|---|
MIGRATION.HASH_NOT_IN_GRAPH | migration plan(グラフが空でない場合)または ref set | 解決されたハッシュがディスク上の移行グラフのノードではありません。通常は、開発時のみの db update サイクルの後、デフォルトの db ref がグラフの先端より先を指している場合に発生します。 | migration plan --from <reachable-ref>(例:--from production)を実行するか、ref set db <graph-node-hash> で ref を再調整します。 |
MIGRATION.SNAPSHOT_MISSING | migration plan | 名前付き ref にポインターファイル(<name>.json)がなく、解決対象のハッシュも移行グラフのノードではありません。 | ref set <name> <hash> で ref を作成するか、db update --advance-ref <name> で ref を進めるか、グラフのノードであるハッシュを渡します。 |
MIGRATION.MARKER_MISMATCH | migrate(ランナー実行前、DDL 前) | ライブ DB のマーカーハッシュがグラフのノードではありません。オフラインプランナーでは検知できないドリフトです。 | マーカーが正規のものであれば migration plan --from <graph-tip> を実行します。ディスク上のグラフが正規のものであれば ref set db <marker-hash> を実行します。範囲外で適用された変更を調査してください。 |
MIGRATION.PATH_UNREACHABLE | migrate(パス解決時) | 現在のマーカーから、解決されたターゲットまでの移行パスがディスク上のグラフにありません。 | 改善された fix ペイロードを確認してください。fromHash/targetHash が示され、migration plan --from <from> --to <target> が提案されます。migration list を実行してグラフを調べてください。 |
CI ゲートでは、--json 出力の diagnostics を読み取り、severity と code に基づいて判断してください。構造については、後述の Workflow — CI を参照してください。
ワークフロー — 「デプロイ時に実行される内容は?」
ユーザーからの質問:「この PR をマージしようとしています。ステージングにデプロイすると、どの移行が実行されますか?」
これはナビゲーションに関する質問です。起点 =ステージングのライブマーカー、宛先 =ref staging(設定していない場合はコントラクトヘッド)です。システムに問い合わせます。
pnpm prisma-next migration status --to staging --db "$STAGING_DATABASE_URL"
このコマンドは次の処理を行います。
- ステージング DB のマーカー(起点)を読み取ります。
stagingをコントラクトハッシュ(宛先)に解決します。- その間のパスを移行の順序付きリストとして表示し、各エッジの状態を
applied/pending/unreachableで示します。また、「ref 'staging' より N 件の移行が遅れています」 という形式の明示的なサマリー行も表示します。 - 設定、移行ディレクトリ、アクティブな ref、データベース接続(マスク済み)を示すヘッダーを表示するため、出力から状況を確認できます。
--db を省略すると、コマンドはオフラインで実行されます。ディスク上の移行を一覧表示しますが、起点がないため適用済みかどうかはわかりません。「このブランチには何がありますか?」 という質問にはこれで問題ありませんが、「ステージングで実行される内容は?」 という質問には不十分です。その場合は、ステージングのライブマーカーが必要です。
--to を省略すると、宛先はデフォルトでコントラクトヘッドになります。これは 「このブランチのコントラクトはデータベースから到達可能ですか?また、どのように到達しますか?」 という質問への答えであり、「デプロイ時に何が実行されますか?」 への答えではありません。特定の環境について質問する場合は、ref を明示的に渡してください。
migration status は、保留中の各移行の操作をクラス(additive、widening、data、destructive)ごとに要約し、破壊的な操作がある場合はその件数を報告します。マージまたはデプロイの前に、その件数をユーザーに提示してください。破壊的な操作は手動レビューが必要なクラスです。
ワークフロー — 「各環境の現在の状態は?」
環境ごとの DB に対して migration status --db $URL を実行するだけです。マーカー(起点)は DB 自体から返されます。サマリー行には、その環境がコントラクトヘッドにあるか、名前付き ref にあるか、ヘッドより先にあるか、分岐したブランチ上にあるかが示されます。
コンセプト — 同じ分岐点からの並行マイグレーション
一部の PN ドキュメントでは、以前これを ダイヤモンド収束 と呼んでいました。呼び方に関係なく、状況は同じです。
何が起きているか。 2 つのトピックブランチが、それぞれ同じ親コントラクトハッシュを基点としてマイグレーションを作成しました。先に一方のブランチが main にマージされ、宛先 ref(例:production)がそのブランチの to ハッシュに進みます。もう一方のブランチのマイグレーションでは、from ハッシュが引き続き 古い 親を指しています。リベース後のマイグレーショングラフでは、そのマイグレーションを経由するクリーンなパスがなくなっています。
- マイグレーションの
fromが、新しいヘッドの祖先ではなくなっています。 - または、マイグレーションの
fromには到達できますが、そのマイグレーションを経由するパスの到達先ハッシュが、両ブランチの変更を統合したものではありません。
どちらの場合も、ディスク上のプランは古くなっています。
解決方法。 from ハッシュがグラフのヘッドではなくなっているため、ディスク上のプランは古くなっています。リベース後の状態に対して、クラスター標準の 編集 → プラン → 適用 のループを実行すると、プランナーが新しいヘッドに from が一致する新しいマイグレーションを生成します。
プランナーが代わりにできない唯一のことは、破棄した migration.ts に含まれるカスタムのデータ変換ロジックを新しいマイグレーションに移植することです。スキーマ差分はコントラクトから導出されますが、手書きの data 操作は、適用前にご自身で引き継ぐ必要があります。別途「再検証」の手順はなく、特別な「ダイヤモンド適用」のフローもありません。
ワークフロー — ref の設定、一覧表示、取得、削除
ref は小さな成果物です。環境ごとのライフサイクルはなく、名前をハッシュに紐付けるだけです。
pnpm prisma-next ref set production <contract-hash>
pnpm prisma-next ref list
# `ref get` was removed — use `ref list` and filter by name
pnpm prisma-next ref list | grep production
pnpm prisma-next ref delete production
ref set は migrations/app/refs/<name> にファイルを作成し、ハッシュと必要な不変条件を記録します。ref はコミットしやすい成果物です。git に保存してください。production が何を指すかは、main が何であるかと同じように、チームで合意します。
ワークフロー — 環境に対してマイグレーションを適用する
pnpm prisma-next migrate --to production --db "$PRODUCTION_DATABASE_URL"
宛先は ref のハッシュ、起点は本番 DB のライブマーカーです。コマンドはその間のパスを計算し、保留中のマイグレーションを順番に適用して、マーカーを進めます。
--db は環境を選択するためのオプションです。--to は宛先ハッシュを指定するためのオプションです。この 2 つは独立しています。
コンセプト — CI/デプロイ時の ref 不一致
CI が次のように報告します:「記録されている ref production のハッシュは X ですが、ライブ DB のハッシュは Y です。」
この不一致は、一致しない 2 つの状態に関する事実です。どちらが誤っているかに関係なく、調査方法は同じです。
- DB が ref より先に進んでいる。 誰かが CI の外でマイグレーションを適用したものの、git の ref を更新していません。
prisma-next ref set <ref-name> <db-marker-hash>で ref を記録し直して(コミットしてプッシュ)、CI 外で適用が行われた経緯を監査します。 - DB が ref より遅れている。 以前のデプロイがロールバックされたか、古いバックアップから DB が復元されました。
prisma-next migrate --to <ref-name> --db $URLで前方に再適用するか、prisma-next ref set <ref-name> <db-marker-hash>で ref を実際のデプロイ状態に合わせて後方に戻します。どちらを選ぶかはユーザーが決めます。両方の選択肢を提示してください。 - DB が別のブランチにある。 通常の手順外で行われたスキーマ変更(手動 SQL、場当たり的なマイグレーション)によって、マイグレーショングラフではモデル化されていない変更が加えられています。
prisma-next db verifyを実行してドリフトを調べたうえで、prisma-next contract inferでデータベースからコントラクトを再導出するか、コントラクトを編集してprisma-next migration planを実行し、最終的にデータベースを宛先にします。
DB がたまたまどの状態にあるかに ref を黙って合わせるために ref set を使うのは、ほとんどの場合、適切ではありません。その場ではドリフトを覆い隠せますが、後でその代償を払うことになります。
ワークフロー — CI:ブランチがターゲット環境に進めることを検証する
ゲートとして使うのは migration status --to <env> --db $URL です。ライブマーカーから参照先までのパスを計算して報告しますが、何も変更しません。migrate に --dry-run フラグはありません。検査/ゲートのステップは migration status です。
適用前にマイグレーションパスを人が読みやすい順序付きプレビューで確認するには、migrate --show --db $URL を使います。デプロイ後に適用済みの履歴を確認するには、migration log --db $URL を使います(時系列順のフラットなテーブル)。
- name: Verify staging is reachable
run: |
pnpm prisma-next migration status \
--to staging --db "$STAGING_DATABASE_URL" --json > status.json
node -e '
const s = JSON.parse(require("fs").readFileSync("status.json", "utf8"));
const warns = (s.diagnostics ?? []).filter(d => d.severity === "warn");
if (warns.length) {
console.error("Blocking diagnostics:", warns);
process.exit(1);
}
'
- name: Apply
run: pnpm prisma-next migrate --to staging --db "$STAGING_DATABASE_URL"
migration status がゼロ以外の終了コードを返すのは、ハードエラー(読み取れないマイグレーションディレクトリ、満たせない不変条件、再構築できない履歴)が発生した場合だけです。MIGRATION.MARKER_NOT_IN_HISTORY、MIGRATION.DIVERGED、CONTRACT.AHEAD、MIGRATION.NO_MARKER のような診断は、severity: 'warn' とともに結果エンベロープで報告されますが、プロセスは 0 で終了します。エージェント(または CI ゲート)が diagnostics[] を調べて、ビルドを失敗させる必要があります。人が読む概要ではなく、構造化された形式をゲートで解析できるよう、--json を使ってください。
migrate は対話操作を必要とせず、破壊的操作の確認プロンプトもありません。破壊的な変更に対する安全策として確認を求めるのは db update です(prisma-next-migrations スキルを参照)。プランナーがマイグレーショングラフに設定した内容が、そのまま migrate によって実行されます。レビューは適用ステップの前、migration plan と migration status の実行時に行います。
よくある落とし穴
- デプロイについて確認する際に、
--toを付けずにmigration statusを読む。 これは「このブランチのコントラクトはヘッドに到達できるか?」を尋ねるものであり、「ステージングでこれから何が実行されるか?」を尋ねるものではありません。特定の環境について確認する場合は、必ず参照先を指定してください。 - デプロイについて確認する際に、
--dbを付けずにmigration statusを読む。 ライブ DB がなければ、起点がありません。出力にはディスク上の内容が表示されますが、その環境で何が適用済みかはわかりません。重要な判断では必ず--db $URLを渡してください。 - 参照先と DB 接続を混同する。
--to stagingは宛先ハッシュを選択するものであり、データベースを選択するものではありません。--toと--dbの両方を明示的に渡してください。 - ダイヤモンド状の収束を特別な手順として扱う。 そうではありません。リベース後の状態に対して通常の 編集 → 計画 → 適用 のループを行うだけです。追加の手順は「古い
migration.tsにあるデータ変換ロジックを移植すること」だけです。 - 原因を理解せずに、CI の不一致を解消するため
ref setを実行する。 これにより、範囲外で行われた変更やロールバックのずれが隠れてしまうことがあります。まず原因を調査してください。
Prisma Next がまだ対応していないこと
- デフォルトのチェーンを超える、環境ごとのマイグレーション順序。 ステージングではスキップし、本番環境では必要となるマイグレーションがある場合(またはその逆の場合)、サポートされている方法は、環境ごとの分岐を個別のマイグレーションとして作成し、デプロイスクリプトでゲートすることです。環境ごとのルーティングを標準機能として利用したい場合は、
prisma-next-feedbackスキルを通じて機能リクエストを提出してください。 - ブランチを並べて比較する、組み込みの「ブランチ差分」ビュー。 ブランチを表示するグラフ全体のレンダリング(
migration graph)はありますが、2 つのブランチのマイグレーションセットを比較するgit diff形式の機能はありません。回避策として、各ブランチでmigration statusを実行し、出力をdiffしてください。ブランチ比較ビューを標準機能として利用したい場合は、prisma-next-feedbackスキルを通じて機能リクエストを提出してください。
リファレンスファイル
このスキルは意図的に本文のみで構成されています。基盤となる CLI リファレンス(prisma-next migration status --help、migrate --help、ref --help)が、フラグの詳細に関する正式な情報源です。迷った場合は、推測でこのスキルを解釈するのではなく、--help を実行して実際のコマンドの説明を読んでください。
チェックリスト
- ユーザーの質問について、起点(ライブ DB のマーカー)と移行先(ref またはコントラクトの先頭)の両方を特定しました。
- 特定の環境が関係する質問では、
--db $URLを渡しました。 - 現在のブランチの先頭からの移行ではなく、名前付き環境へのデプロイに関する質問では、
--to <name>を渡しました。 - エッジごとの一覧を読む前に、
migration statusのヘッダー(設定、ref、データベースを記載)とサマリー行(起点と移行先の差分を記載)を読みました。 - マイグレーションの同時実行による競合では、記憶した「ダイヤモンド収束」の手順に従うのではなく、中核となるワークフロー(編集 → plan → apply)を再実行しました。中止した
migration.tsにあったデータ変換ロジックも移植しました。 - ref の不一致について、どの状態が間違っているのか(DB が先行、DB が遅延、DB が分岐したブランチ上にある)を調査しました。不一致を無視するために
ref setを実行しませんでした。 - ユーザーがマージまたはデプロイする前に、
migration statusの破壊的操作の件数(デプロイ前に手動確認が必要な唯一の操作クラス)を提示しました。 - CI では、
migration status --jsonのdiagnostics[]を解析し、severity === 'warn'を条件にゲートしました。migrateに--dry-runフラグがある(実際には存在しません)とは考えませんでした。 -
--toをデータベースの選択と混同しませんでした(--toは移行先のハッシュを選択し、--dbはデータベースを選択します)。 -
--refは使用しませんでした(削除済みです。--toを使用してください)。 - このスキルで言及されていない「ブランチ差分」の CLI サブコマンド、
migration revalidateの手順、その他の API を作り上げませんでした。