Skip to content

ddl diff のリスク評価を独立 evaluator 化し、手修正後 migration SQL の事後評価を可能にする #648

Description

@mk3008

Summary

現在の ztd ddl diff では、riskNotes を structured risks に置き換え、summary と責務分離し、applyPlan / renderApplySql / buildRisks までの内部整理が入った。

これは reviewability 改善としては十分前進しているが、リスク評価はまだ diff.ts 内の内部関数に留まっており、独立した evaluator としては扱えていない。

そのため現状では、

  • ztd ddl diff が生成した migration に対する評価
  • 人間が手修正した migration SQL に対する再評価
  • 将来的な他コマンドや他入口からの再利用

がまだできない。

本課題では、migration 生成処理と risk 評価処理を明確に分離し、ddl diff からは統合利用しつつ、独立した risk evaluator として再利用可能な形に整理する。
あわせて、手修正後 migration SQL に対しても同じ risks contract で事後評価できる入口を用意する。

Background

今回の structured risks 導入で、少なくとも次は整った。

  • summary は logical diff
  • risks は apply-plan based structured risks
  • destructiveRisks / operationalRisks
  • guidance / avoidable
  • buildApplyPlan(...)
  • renderApplySql(...)
  • buildRisks(applyPlan, summary)

ただし、このままだと risk 判定が migration 生成の内部都合に閉じやすい。

review-first の信頼性をさらに高めるには、

  • 生成器が自分で作ったものを自分で「安全」と言う構造から一歩離れること
  • 生成結果そのものを別責務で評価できること
  • 人間が SQL を手修正したあとでも、同じ基準で再評価できること

が重要である。

とくに migration は、現実運用では自動生成後に人間が少し手直しすることがある。
その最終成果物に対して independent に risk を再評価できることは、隠ぺいしていないことの説明にもなり、review artifact としての信頼性も上がる。

Goal

  • risk evaluator を diff.ts の内部関数から切り出し、独立責務にする
  • ddl diff はその evaluator を利用して risks を出す
  • 手修正後 migration SQL に対しても、同じ risks contract で事後評価できる入口を追加する
  • 将来的に他入口から再利用しやすい API 境界を作る

Non-goals

今回の課題では、次は主目的にしない。

  • DB 方言ごとの実行計画レベルの高精度性能推定
  • migration 実行時間の正確な見積もり
  • すべての手書き SQL を完全に意味解析すること
  • CLI option の全面再設計
  • ddl diff 自体の migration 生成アルゴリズム変更

Desired Outcome

少なくとも次の形に整理されていること。

  • migration 生成
  • migration SQL render
  • risk 評価

が内部責務として分離されている。

イメージとしては次のような境界を目指す。

buildApplyPlan(...)
renderApplySql(plan)
analyzeMigrationPlanRisks(plan, summary?)
analyzeMigrationSqlRisks(sql)

ddl diff は従来どおり summary / SQL / risks をまとめて出してよいが、risk 判定自体は独立 evaluator 経由にする。

Scope

1. risk evaluator を diff.ts 外へ切り出す

現在の buildRisks(applyPlan, summary) 相当の責務を、diff.ts の内部実装ではなく、独立した evaluator module に移す。

最低限の要件:

  • DdlDiffRisks contract を維持する
  • destructiveRisks / operationalRisks を返す
  • guidance / avoidable を維持する
  • ddl diff は切り出した evaluator を使う

2. plan ベース evaluator を独立化する

まずは既存実装に最も近い、applyPlan を入力とする evaluator を独立化する。

例:

analyzeMigrationPlanRisks(plan, summary?): DdlDiffRisks

ここでは、現在 buildRisks(...) に入っている判定規則を移送すればよい。

3. SQL ベースの事後評価入口を追加する

次に、migration SQL 文字列を入力として risk を出す入口を追加する。

例:

analyzeMigrationSqlRisks(sql): DdlDiffRisks

これは「手修正後 migration SQL の再評価」のための入口である。

v1 では、完全な SQL 意味復元は不要とする。
まずは少なくとも次が拾える形を目指す。

  • DROP TABLE
  • DROP COLUMN
  • CASCADE
  • table recreate 相当のパターン
  • index rebuild 相当のパターン
  • alter type 相当のパターン

必要なら、plan-based evaluator より判定精度が落ちる項目は docs / contract 上で明示する。
とくに rename_candidate のような文脈依存 risk は、SQL 単体では省略または精度低下を許容する。

4. ddl diff は plan-based evaluator を利用する

ddl diff コマンド自体は引き続き

  • summary
  • generated SQL
  • risks

をまとめて返してよい。

ただし内部では、

  • buildApplyPlan(...)
  • renderApplySql(...)
  • analyzeMigrationPlanRisks(...)

の順に呼ぶ構造へ揃える。

5. 事後評価用の入口を CLI または内部 API として持てるようにする

最低限、内部 API として analyzeMigrationSqlRisks(sql) を使える状態にする。

CLI 入口はあると望ましいが、この課題の必須条件ではなく stretch goal とする。
候補:

  • ztd ddl risk --file migration.sql
  • ztd ddl diff --risk-from <file>
  • あるいは describe / agent interface から触れる内部 command

CLI 名称の最終確定はこの課題内で必須ではない。まずは API 境界を優先する。

Design Notes

独立性の意味

この課題の狙いは単に関数分割することではない。
重要なのは、risk 評価が migration 生成ロジックの自己説明で終わらないことにある。

  • generator は migration を作る
  • evaluator は migration plan または migration SQL を評価する

という構図を明確にすることで、

  • 隠ぺいしていないことの説明になる
  • 最終成果物に対する independent review ができる
  • 人手修正後の再評価が可能になる

plan と sql の両系統を持つ理由

plan-based evaluator は、rename_candidatesummary 文脈を使えるため、ddl diff の内部評価には向いている。

一方で sql-based evaluator は、生成器に依存せず、最終的な migration SQL に直接かけられるため、手修正後評価や将来の汎用 analyzer として有用である。

したがって、どちらか一方ではなく、次の 2 層にするのが望ましい。

  • analyzeMigrationPlanRisks(...)
  • analyzeMigrationSqlRisks(...)

Acceptance Criteria

  • diff.ts 内部に閉じていた risk 判定処理が独立 module に切り出されている
  • ddl diff がその独立 evaluator を使って risks を返す
  • applyPlan を入力とする evaluator API が存在する
  • migration SQL を入力とする evaluator API が存在する
  • 少なくとも代表的な destructive / operational risk を SQL から再検出できる
  • guidance / avoidable の contract が維持される
  • 既存の ddl diff text/json 契約が壊れていない
  • docs / help / agent interface に新しい責務分離が反映される
  • テストで「手修正後 SQL の再評価」が確認できる

Test Plan

Unit tests

  • plan-based evaluator が既存 ddl diff の risk 判定結果を維持する
  • sql-based evaluator が次を検出できる
    • drop_table
    • cascade_drop
    • drop_column
    • alter_type
    • table_rebuild 相当
  • guidance / avoidable が plan-based evaluator で維持される
  • text/json の contract が従来どおり通る

CLI / integration tests

  • ddl diff が独立 evaluator 経由で同じ risks を返す
  • 事後評価用入口を追加した場合、その output contract が固定される
  • docs examples が新構成に一致する

Regression tests

  • 既存の structured risks 契約が壊れていない
  • riskNotes が復活していない
  • summaryrisks の責務分離が維持されている

Open Questions

  • SQL ベース evaluator の CLI 入口は今回の課題で一緒に入れるか、API だけ先に切るか
  • rename_candidate のような文脈依存リスクを SQL ベース評価でどう扱うか
  • sql-based evaluator の精度差を contract / docs にどう表現するか

Suggested Implementation Order

  1. buildRisks(...) 相当を独立 module へ切り出す
  2. ddl diff が新 evaluator を使うように差し替える
  3. plan-based evaluator の unit tests を固定する
  4. sql-based evaluator を最小実装で追加する
  5. 手修正後 SQL 再評価の tests を追加する
  6. 必要なら CLI 入口を追加する
  7. docs / help / agent interface を更新する

Why this matters

今回の structured risks は reviewability を大きく改善した。
次は、その risk 評価自体を独立させることで、

  • migration generator の自己評価に見えにくくする
  • 人間が手修正した migration の再評価を可能にする
  • 将来の汎用 migration risk analyzer へ育てやすくする

という、信頼性と運用性の強化に進みたい。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions