Accepted(Phase 1〜5は2026-08-18に実行済み。Phase 5ではKnowledgeSource、Git tree直読、再構築可能索引、Backfill処理量制限を導入した)。
現在の実装(単一Rust crate)は機能別のフラットな.rsファイル群で構成されており、コード量が増えるにつれて以下の問題が具体的に確認されている。
src/cli.rsが2248行あり、引数解析・Use Case実行・人間向け/JSON出力・終了コード決定を一括で担当している(process::exit呼び出しが32箇所、println!/eprintln!が92箇所)。src/changes.rsのcompute_changes(root, from_milestone, to_milestone, use_cache: bool, use_current_tree: bool)は意味の薄いbool引数を2つ取り、呼び出し側が意図を読み取りにくい。changes.rs内にCommand::new("git")の直接呼び出しが5箇所分散しており、src/git.rsに集約されていない。src/verify.rsのtrace/pending関数はfs::read_to_stringを直接呼んでおり、判定ロジック(Current/Pending/Stale/Unknown相当の分岐)とファイルI/Oが分離されていない。src/knowledge.rsはYAMLのparse/serializeのみを提供し、正規化されたSnapshotの抽象がない。そのためsrc/generate.rsとsrc/validate.rsがそれぞれ独自にfs::read_dirでknowledge/を走査しており、走査ロジックが重複している。changes.rsのhistorical_testcases_by_featureは、マイルストーンごとにgit worktree add→generate_testcases→git worktree removeを実行する。markharness backfill run(UC6、大規模既存リポジトリ向けの優先度付きバックフィル、PROJECT.md)は多数のマイルストーンペアを処理する設計であり、このworktree生成コストはbackfillのスケールに直結する。ユーザーから提供された設計提案「markharness アーキテクチャ設計提案」(2026-08-18)は、これらをDomain/Application/Infrastructureへ分離するレイヤー構成を示した。レビューの結果、現状分析は実装と一致しており(上記の各行はコード確認済み)、13章「採用しない設計」の判断もCLAUDE.mdの「後方互換性のための設計を排除し常に最善を目指す」「デメリットに工数を含めない」という運用ルールと整合していた。一方で、提案のChangeAnalyzerインターフェースがdecisions/0008のロードマップと1点衝突していたため、本ADRで修正の上、採否を決定する。
KnowledgeWorkspace・TestcaseCompiler・ChangeAnalyzer・VerificationEngine・BackfillCoordinatorをDomain層の中核とする。各Moduleが呼び出し側に見せるInterfaceと内部へ隠す処理の詳細は設計文書を正とする。
CommandOutcome型とPresenter traitを導入し、Domain層・Application層からprintln!/eprintln!/std::process::exitを排除する。人間向け出力とJSON出力は同じCommandOutcomeから生成する。
ChangeAnalyzerの版参照はMilestoneRef固定ではなくCommitRefベースに一般化する(元提案からの修正)元提案はChangeAnalyzer::compute(from: MilestoneRef, to: MilestoneRef, options: ChangeOptions)としていたが、decisions/0008 Stage 2は「milestone-only UXを、PR base/headをfirst-classに追加した共通version rangeへ一般化する」ことを既に決定済みである。MilestoneRefに型を固定したままPhase4でChangeAnalyzerを確定させると、Stage 2着手時に中核Interfaceの再設計が必要になり手戻りが生じる。そのため本ADRでは以下を採用する。
enum CommitRef {
Milestone(MilestoneId), // タグ名。内部でgit tagをcommitへ解決する
Commit(CommitId), // 任意のcommit(PRのbase/head SHA等)
}
impl ChangeAnalyzer {
fn compute(
&self,
from: CommitRef,
to: CommitRef,
options: ChangeOptions,
) -> Result<ChangeSet>;
}
既存のmarkharness changes computeとbackfill runはCommitRef::Milestoneを使い続ける(挙動は変わらない)。decisions/0008 Stage 2で追加するPR Verification Plan機能は、同じChangeAnalyzerに対してCommitRef::Commitを渡すだけで済み、Interfaceの再設計を要しない。
GitRepository traitは今は導入せず、まずgit.rsへの集約を先行する(元提案からの修正)元提案7.1はGitRepository trait定義を完全な形で先出ししていたが、これは提案自身の13章が掲げる「一つしか実装がない依存まで抽象化しない」という原則と整合しない。本ADRでは、Phase1でchanges.rs内の直接git呼び出しをgit.rsへ集約するところまでを決定する。trait化は、テスト用のfake実装が具体的に必要になった、または複数Adapterが要件化した、など明確な必要性が生じた段階の判断に委ね、現時点でtraitの型は確定しない。
KnowledgeSource traitを採用するWorkingTreeKnowledgeSource/GitTreeKnowledgeSourceの2 Adapterが最初から明確なため、上記4とは異なりtrait化の妥当性がある。GitTreeKnowledgeSourceにより、historical_testcases_by_featureのgit worktree add/removeをcommit配下のtree/blob直接読込に置き換え、backfillのスケールコストを下げる。
generateによるTestCaseとtraceability indexの更新を、ディレクトリ全体でトランザクション化する(一時ディレクトリへ全生成→検証→generated/への切り替え)。途中失敗時は既存生成物を保持する。
初期段階から増分生成のみで運用することは採用しない。増分生成を追加する場合も、CIでの定期的な全生成による検証を前提とする(13章の判断を維持)。
| Phase | 内容 |
|---|---|
| Phase 1 | compute_changesのbool引数をChangeOptionsへ、changes.rs内の直接git呼び出しをgit.rsへ集約。既存動作とCLI契約をCharacterization Testで固定。ディレクトリ構成は変更しない。 |
| Phase 2 | CommandOutcome導入。CLIからstd::process::exitをPresenterへ移動。人間向け/JSON Presenterを分離。generate・changes compute・verify pendingからApplication Use Caseを抽出。 |
| Phase 3 | TestCaseとtraceability indexの生成を一時領域で行い、成功後にgenerated/へ反映する原子性を追加。 |
| Phase 4 | KnowledgeSnapshot導入。TestcaseCompilerをファイルシステムから分離。VerificationのData LoaderとEngineを分離。ChangeAnalyzerは決定3のCommitRefベースで確定させる。 |
| Phase 5 | KnowledgeSource導入。GitTreeKnowledgeSourceでworktreeを置き換え。Feature/ChangeEvent/Executionの再構築可能な索引を追加。Backfillに--max-pairs/--time-budget等の処理量制限を追加。 |
詳細なInterface定義、Mermaid図、コード構成、テスト戦略はdomain-application-infrastructure-layering-design.mdを参照。
cli.rsへの変更集中が解消され、機能追加時の変更範囲が予測しやすくなる。ChangeAnalyzerがdecisions/0008 Stage 2のPR Verification Plan機能を、後方非互換な再設計なしに受け入れられる。GitRepository traitの導入を先送りすることで、単一実装しかない依存を抽象化する無駄なInterfaceを避けられる。GitRepositoryを含む):一つしか実装がない依存まで抽象化するとInterfaceが増え保守性を下げる。KnowledgeSourceのように複数Adapterが具体的に必要なseamだけを抽象化する(決定4・5)。ChangeAnalyzerをMilestoneRef固定のまま採用する(元提案どおり):decisions/0008 Stage 2との衝突により、PR Verification Plan着手時に中核Interfaceの再設計という手戻りが生じるため不採用とし、CommitRefへ一般化する(決定3)。