db-defaults-generated について
データベース監査向けのスキルで、デフォルト値、生成列、ID列やシーケンス設定に関する正確性リスクを確認します。アプリケーションコードごとに値を管理するのではなく、データベースで強制すべき値を判断するのに役立ちます。
主な機能
- 01タイムスタンプ列のデフォルト値を確認
- 02アプリ管理の派生値を特定
- 03空文字列やセンチネル値のデフォルトを検出
- 04ID列とシーケンスの設定をレビュー
- 05ブール値のデフォルトを確認
活用シーン
- 01書き込み元ごとのタイムスタンプ処理を監査
- 02保存された合計値や検索ベクトルを確認
- 03値の欠落を隠すデフォルトを発見
- 04シーケンスの所有関係やID列の選択を点検
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hainrixz/ claude-db --skill db-defaults-generatedインストール後、Claude Code で/db-defaults-generatedを入力して読み込まれたか確認します。
詳細
db-defaults-generated (M6)
デフォルト値と生成列は、正確性を保証できるソース側に配置します。created_at DEFAULT now() はすべての書き込み元で有効であり、GENERATED ALWAYS AS 列は入力値との不整合が生じることはありません。このロジックをアプリに移すと、書き込み元ごとに異なる誤りが起こり得ます。このモジュールは design 軸(Tipos カテゴリ)です。デフォルト値/生成列をサポートするエンジンに適用されます。
チェック内容
- タイムスタンプのデフォルト値:
created_at/updated_atがアプリケーションコードのみで設定されている(DEFAULT now()/CURRENT_TIMESTAMPもON UPDATE/トリガーもない)場合、書き込み元によって値が不整合になり、SQL を直接実行した INSERT では値が欠落します。 - 導出値は生成列にすべき:兄弟列から計算される保存列(
full_name、total = qty*price、search_vector)が、GENERATED ALWAYS AS ... STOREDではなくアプリケーションコードで同期されている場合、値がずれやすくなります(M1 の非正規化の規律に関連)。 - 非決定的/不適切なデフォルト値:動的であるべき値を固定するデフォルト値、必須の意図を隠すデフォルト値(例:
status DEFAULT 'active')、または NULL の代わりに設定されたDEFAULT ''。 - IDENTITY/シーケンスの適切な管理:
serialとGENERATED ... AS IDENTITYの比較、シーケンスの所有権の共有/誤設定。 - ブール値/フラグのデフォルト値の欠落:本来 2 値で扱う意図のところで、3 値論理を強いる状態。
軸と重大度
- 軸:design。重大度は範囲で示し、ドリフト率を推測で作りません。
- アプリで維持されている導出保存列(ドリフトのリスク):重大度 3、
warn、fixable: proposed。 - DB デフォルト値がない
created_at/updated_at:重大度 2~3、warn、fixable: auto(追加的なデフォルト値)。 - NULL の意味を隠す
DEFAULT ''/センチネル値:重大度 2、warn。 - M6 に重大度 5 の上限はありません。Tipos カテゴリの評価を形作ります。
Tier-0 静的チェック
scripts/parse-schema.mjs で DDL/スナップショットを解析します。DEFAULT のない *_at タイムスタンプ列にフラグを付けます。名前から導出列だと推測される列(full_name、total、*_count、search_vector)が、GENERATED ではなく通常の列として定義されていることを検出します。空文字列/センチネル値をデフォルトに設定しているものを一覧表示し、serial が IDENTITY のほうが望ましい場合に記録します。プログラムソースの解析結果は directional のままです。
Tier-1 検証クエリ
列のデフォルト値と生成列の状態を確認します。
-- $DATABASE_URL, read-only
SELECT table_name, column_name, column_default, is_generated, generation_expression
FROM information_schema.columns
WHERE table_schema NOT IN ('pg_catalog','information_schema')
AND (column_name ~* '(_at$|total|full_name|count|vector)');
「導出」列の値が入力値とずれていることを確認します。
SELECT count(*) AS drifted FROM order_items WHERE total <> qty * unit_price;
検出結果
schema/finding.schema.json に従って出力します。例:
M6.invoices.total_app_maintained—totalは通常の列であり、アプリケーションコードで同期されています。GENERATED ALWAYS AS ... STOREDではありません(重大度 3、warn、軸design、fixable: proposed)。M6.users.created_at_no_default—created_atにDEFAULT now()がありません(重大度 2、warn、fixable: auto、軸design)。M6.users.name_default_empty_string—DEFAULT ''が NULL の意味を隠しています(重大度 2、warn)。 各検出結果では、evidence.observedに列の DDL またはデフォルト値をそのまま引用します。verification.reproduceは上記の実行可能なクエリです(method: ddl_parse/schema_introspect/query_stat)。expected_impactは範囲と信頼度タグを付けて示します。
誠実性
- DB デフォルト値があるからといって、アプリの意図が不要になるわけではありません。DB 側での強制が明らかに安全な場合(タイムスタンプ、導出値)のみ指摘し、「すべてのデフォルト値を DB に移す」と一律には勧めません。
- 生成列には、エンジンやバージョンによるサポート上の制限があります(Postgres は STORED のみ、MySQL は VIRTUAL/STORED)。検出したエンジンに応じて推奨内容の対象範囲を定めます。
- Tier-1 の不一致件数がない限り、導出列の値がずれていると断定しません。静的な検出では
directionalとします。