markharness

0032: CLIリードモデルというseamを導入する

ステータス

Accepted(2026-09-16決定)。

背景

markharness v2は、Change ImpactとRelease Coverageのビューやダッシュボードを別リポジトリmarkharness-view(仮)に委ねる方針である。この方針を実現するため、docs/ja/design/cli-read-model-design.md(Draft)がCLIの外部向け読み取り契約(リードモデル)を、新設のrecord_kind/schema_versionエンベロープとCommandOutcomeへの新variant追加を前提に提案した。

grillingセッションで実装(src/)を調べたところ、この前提は誤りだった。実際には次の2つの独立した出力系統が既に存在する。

  1. CommandOutcome/Presenter系統(src/presentation.rs): canonical_imported・generated・changes_computed(markharness changes computeが.markharness/changes/へ書き込む処理結果)の3つの書込み系コマンドの結果を表す。JsonPresenterは{"schema_version": 1, "outcome": "<tag>", ...フィールド}というフラットな形式で、v0.6.1から出力している。
  2. 各コマンド専用モジュールの系統(src/impact.rs・src/coverage.rs): impact・coverageという読み取り系コマンドは、CommandOutcome/Presenterを一切経由しない。各モジュールが自前の構造体(ChangeImpact・ReleaseCoverage)を持ち、schema_version・record_kind(値はそれぞれ"change_impact"・"release_coverage")フィールドを既に備え、cli.rsからserde_json::to_string_prettyで直接シリアライズしている。--formatは現状Jsonしか値がなく、人間可読出力は未実装である。

つまり、ドラフトが提案しようとした「record_kind/schema_versionを持つリードモデルを、Application層で生成してJSON Presenterへ渡す」という設計は、impact/coverageについて既に実装済みである。またrecord_kindという名前自体も、0025とmarkharness-v2-design.md§9.1が.markharness/配下の永続レコード向けに確立し、impact/coverageのCLI出力もそれを踏襲している既存の命名規約であり、ドラフトが暗黙に想定していた新規の入れ子構造やフィールド名でもない。

新規に必要なのは、この既存パターンに従うtraceabilityコマンド(現状は未実装)を1つ追加することだけである。

さらに、src/traceability.rsというファイル自体は既に存在しており、TraceabilityIndex/build_index/serialize_indexを実装している。これはgenerateが生成時に組み立て、.markharness/generated/traceability-index.jsonへ書き込む生成アーティファクト(application.rs)であり、verifyが再生成の決定性を確認するために使う(verify.rs)。TestCase単位のフラットな一覧(case_id・requirement_ids・feature・behavior・scenario・axis)で、record_kind/schema_versionを持たず、markharness-viewが読む対象でもない。新設するTraceabilityReadModel(Requirement/Feature/Behavior/Scenario/TestCaseの各Node配列とRelationを持つ、--at指定時にオンデマンドで計算されCLI標準出力へ返す読み取り専用モデル)とは、生成物か問い合わせ結果かという点も含め責務が異なる。同じファイル名を異なる責務のために使い回すと、どちらのモジュールを指しているか読み手が混乱するため、本ADRで名前の衝突を解消する。

決定

1. traceabilityはimpact/coverageと同じ出力パターンに従う

新設するtraceabilityコマンドは、CommandOutcome/Presenterを経由しない。impact.rs・coverage.rsと同様、専用モジュールにTraceabilityReadModel構造体を定義し、schema_version: u32・record_kind: &'static str(値は"traceability")を持たせ、cli.rsからserde_jsonで直接シリアライズする。

CommandOutcomeへの新variant追加(ImpactComputed・CoverageComputed・TraceabilityComputed)は行わない。impact・coverageは元からCommandOutcomeを使っておらず、traceabilityもそれに合わせる。

2. 既存のsrc/traceability.rsはsrc/traceability_index.rsへリネームし、src/traceability.rsを新設CLIコマンド用にする

TraceabilityIndex/build_index/serialize_index(generateの生成アーティファクト用)は、名前をsrc/traceability_index.rsへ変更する。呼び出し元(application.rs・verify.rs)のuseと参照パスを更新する。型名・関数名・.markharness/generated/traceability-index.jsonというファイル名自体は変更しない(生成アーティファクトのファイル名はモジュール名と独立した既存の外部仕様であり、変更する理由がない)。

空いたsrc/traceability.rsを、新設CLIコマンドtraceability(TraceabilityReadModel)専用のモジュールとする。これにより、impact.rs↔impactコマンド、coverage.rs↔coverageコマンドと同じ「モジュール名がコマンド名と一致する」命名パターンをtraceabilityでも維持できる。

このリネームは、markharness::traceability::TraceabilityIndexという公開Rust APIパス(src/lib.rsはpub mod traceability;を含め全モジュールをpubにしている)をmarkharness::traceability_index::TraceabilityIndexへ破壊的に変更する。本クレートのpub mod群はtests/配下の統合テストからクレート内部へアクセスするためのものであり、外部のライブラリ利用者への安定APIとして提供・保証しているものではない(Cargo.tomlのdescriptionは”Git-native test knowledge management CLI”であり、ライブラリとしての利用は想定外)。したがって、再エクスポート(pub use)による旧パスの互換維持は行わない。CLAUDE.mdの「後方互換のための設計を持ち込まない」方針をRust公開APIにも適用する。

3. impact・coverageの出力契約は変更しない

ChangeImpact・ReleaseCoverageは、record_kind/schema_versionを含め、既に外部契約として妥当な形になっている。ドラフトが提案していたChangeImpactReadModel・ReleaseCoverageReadModelは、既存のChangeImpact・ReleaseCoverageを指すものとして読み替える。既存フィールドの破壊的変更は、本ADRの範囲では行わない。

4. CommandOutcome/Presenter系統(outcomeフィールド)はリードモデルの対象外とする

canonical_imported・generated・changes_computedは書込み系コマンドの実行結果であり、markharness-viewが読み取り対象とするtraceability/impact/coverageとは無関係である。これらのoutcomeフィールドをrecord_kindへ統一する変更は、具体的な必要性がないため本ADRのスコープに含めない(YAGNI)。将来、書込み系コマンドの出力を外部契約として整理する具体的な必要が生じた場合は、別のADRで扱う。

5. 本ADRのスコープは「traceabilityを既存の読み取り系パターンに合わせて追加する」という決定のみとする

TraceabilityReadModelの詳細なフィールド構成(Node種別ごとの配列、Relationの表現等)は、本ADRでは決定事項として扱わず、docs/ja/design/cli-read-model-design.md(設計doc)の責務として残す。

6. 本ADRは設計決定の記録であり、実装は別途行う

src/traceability.rsのリネームと新規実装、cli.rsへのtraceabilityコマンド追加は、本ADRの範囲に含めない。別タスク(実装フェーズ)として、TDD(Red-Green-Refactor)で行う。

影響範囲

未着手(実装フェーズで行う): 以下の既存の追跡済みドキュメントは、本ADRの時点ではsrc/traceability.rsへの言及を意図的にそのままにしてある。理由は、決定2のリネームがまだコードに反映されておらず(src/traceability.rsは現時点でもTraceabilityIndexのままである)、今ここでsrc/traceability_index.rsと書き換えると、まだ存在しないファイルを指す誤った記述になるためである。実際のRustリネーム(決定6)が実装された時点で、同じコミット内でこれらも更新する。

検討したが採用しない選択肢