作成日:2026-09-11(初版)。2026-09-11、既存の設計・概念に引っ張られない再検討(grillingセッション)により全面書き直し。同日、既存実装(src/)との突合結果を反映して§5.2.1・§6.1・§9.1等を訂正。さらに、StrictDoc→markharness→Playwrightの実運用後に完全モデルへ進めるための契約を§9.2とADR 0025へ追加した。
状態:MVP(M0〜M2)実装済み(2026-09-12、checklist-v2-core.md参照)。本書が定める型・判定規則は実装されている。CLI表面は0028がKnowledge authoringをknowledge reconcileへ統合したため本書の初版から変わっており、§7・§9.1に反映済みである。M3・M4は未着手であり、これらに関する記述は引き続き提案である。
開発者が機能・仕様(Requirement)・テストケースのいずれかを変更したとき、チームは次の4つの答えを手にする。
問い3についてmarkharnessが答えるのは、そのリリースのReleaseScope(選定リスト)が記録されていれば「何を検証対象に選んだか」まで、無ければ「その時点で登録されていたTestCaseと検証手段」までである。いずれの場合も実行された事実は扱わない(§6.2)。これがv2のNorth Starであり、以下すべての設計判断はこの4点に照らして評価する(用語集はmarkharness-v2-glossary.md、確定した用語の一次情報はCONTEXT.mdを参照)。
成功の判定基準は次の3点。
本書は2026-09-11の同日中に、既存の設計・概念(v2旧版のArtifact/Evidence/Execution Manifest等の重量級モデル、旧実装のidentity退役・復元機構)に引っ張られない前提で作り直したものである。旧版との主な差分は次の通り。
| 領域 | 旧版 | 本版 |
|---|---|---|
| 実行結果・証跡 | Evidence/EvidenceSelection/Execution Manifest/Implementation revision/Environment matrixの重量級モデル | automated/manualの1軸+任意の参照文字列のみ(0020) |
| 対応確認 | AlignmentObligation/AlignmentDecisionという独立Domain型 |
commit trailerによる軽量な記録(0019) |
| 同一性(退役・復元) | 退役・復元・ID予約解除の厳密な保証機構を維持 | 「退役=削除」まで単純化(0021) |
| 外部連携(StrictDoc/Playwright) | MVP必須(M0〜M4すべてに組込み) | MVP範囲外。データ構造だけ将来の連携を意識する |
| 構造プロファイル | 複数profileの切替機構(minimal-trace-v1/hierarchical-test-v1) | 単一構造(Feature→Behavior→Scenario→TestCase)のみ。profile切替は導入しない |
| GUI/dashboard | MVPから除外(Stage 3として後回し) | CLI/JSON出力のみで完結させ、ビューは別ツールに委ねる。ADR 0008 Stage 3で実装済みのserver.rs・ui/は削除する(0022) |
| Requirementの正本 | markharness nativeの実体のみ(label/description/axis) |
native/externalの二モード。externalではStrictDocが正本で固定参照のみ保持(0023、§5.2.1) |
一次資料は2026-09-11の再設計grillingセッション(この会話)。根拠となる回答は次の通り。
| 論点 | 確定内容 |
|---|---|
| 再設計の対象範囲 | 既存のknowledge/コア(Feature/Behavior/Scenario/Axis/決定的生成/ChangeEvent)を含め全面見直し可としたが、結果としてこのコアは維持する判断に至った |
| 「機能」の実体 | 仕様上の概念(現行Feature相当)。実装コードの差分検知はmarkharnessの責務外 |
| 仕様の正本 | StrictDoc(.sdoc、Git管理)。JSON export取込・自前パーサはロードマップ扱い |
| テストケースの正本 | 現行knowledge/資産を維持 |
| 修正漏れ検知 | 仕様⇄テストケース双方向。自動判定+commit trailerでの軽量な確認記録 |
| リリース単位 | PR base/head差分(日常)+リリース全体一覧(判断補助)の両方 |
| 実行結果 | 簡易ステータス(automated/manual)のみ保持。証跡管理は別ツール(現状Excel)の責務 |
| 環境(ブラウザ/OS等) | テストケースの外。仕様書/実行ツール側の責務 |
| identity | 単純化。退役後の厳密な復元・ID予約解除は保証しない |
| 後方互換 | 不要(実利用者はごく少数のプロトタイプ段階、0017背景と同じ前提) |
| ID | 原則 | 設計への帰結 |
|---|---|---|
| P1 | 外部の正本を尊重する | StrictDocの要件本文を複製・編集せず、固定参照(id・版)のみ保持する |
| P2 | 同一性と版を分ける | UIDを名前・パス・内容ハッシュから無条件に作らない(現行knowledge/の方針を維持) |
| P3 | 判定は再現可能にする | 同一Git snapshotから同一Change Impact/Release Coverageを作る |
| P4 | 合否と検証手段を分ける | pass/fail等の詳細判定は別ツールに委ね、markharnessは「自動/手動どちらの手段で検証するか」とその参照先だけを扱う(§5.2) |
| P5 | Coreは外部形式を知らない | StrictDoc固有フィールドと変換規則は将来のAdapterに置き、Coreへ持ち込まない |
| P6 | 拡張は命題から評価する | 汎用plugin基盤・独自業務管理を先行実装しない(CLAUDE.mdのYAGNI原則) |
| P7 | 判定は一箇所に集約する | CLI・CIは同じApplication結果を使う(現行0008のモジュラーモノリス方針を継承) |
| 領域 | 正本/担当 | markharnessが保持するもの |
|---|---|---|
| 仕様(Requirement)の本文・構造 | external: StrictDoc / native: markharness | externalは固定参照(id・版)のみ、nativeはlabel/description(0023) |
| テストケースの意図・手順・期待結果 | markharness native(knowledge/) |
Feature/Behavior/Scenario/TestCaseそのもの(既存資産を維持) |
| 実行、証跡本体、日時、実行者 | 別ツール(現状Excel、将来Playwright等) | automated/manualの1軸+任意の参照文字列のみ |
| 実行環境(ブラウザ/OS等) | 仕様書・実行ツール側 | 保持しない |
| 対応確認の記録 | Gitのcommit履歴(trailer) | 確認要否の自動判定のみ。記録本体はGit履歴に委ねる |
| Change Impact・Release Coverageの算出 | markharness Core | 決定的な差分・一覧算出 |
Feature・Behavior・Scenario・TestCase・Axis・Case revision・ChangeEventは現行knowledge/実装をそのまま維持する。決定的生成、Git tree SHAによる版比較、Axisによる横断検索は今回の再設計の対象外であり、変更しない。
なお現行実装はRequirementもknowledge/requirements/<id>/requirement.ymlとしてnativeな実体(独自UID・label・description・axis)で保持し、feature.requirement_uidsで多対多に関連付けている(0017§1・§3、src/knowledge.rs・src/identity/entity_kind.rs・src/traceability.rs)。Requirementはcase identityには含まれない(case_id = tc-{feature}-{behavior}-{scenario}、src/generate.rs)。したがって§5.2のRequirementは新規概念の追加ではなく、既存のnative Requirementに「正本を外部に置くモード」を足す変更である(0023、§5.2.1)。StrictDocを導入していない運用でもmarkharnessは単独で成立する必要があるため、正本を常に外部へ固定する設計は採らない。
Requirement {
id, // 表示ID(現行`requirement.yml`の`id`)。externalではStrictDoc側UIDと一致させる
uid, // 現行のRequirement UID(ADR 0013)を維持する
source: native | external, // 必須。省略時のdefaultは持たない(0026 §7)
axis, // 両モードで保持する。markharness自身の分類であり外部正本の複製ではない
// source = native のとき必須、externalでは書けない
label,
description, // optional
// source = external のとき必須、nativeでは書けない
source_locator, // 同一Gitリポジトリ内の`.sdoc`パス
source_revision, // 取込時に固定したGit blob OID
}
ExecutionBinding {
case_uid, // 表示IDではなくCase UIDで参照する(ADR 0013、rename耐性)
mode: automated | manual,
reference: string, // optional。テストコードへのパスやURL
}
ReleaseScope {
release_id, // リリースの表示名(Git tag名を推奨)。安全な単一パス構成要素に限る(下記)
case_uids: [case_uid], // そのリリースで検証対象に選んだTestCase
}
source: externalのRequirementはStrictDoc側の内容を複製しない。markharnessが保持するのは固定参照だけであり、本文・受け入れ条件等はStrictDoc側を都度参照する(P1)。source: nativeでは従来どおりmarkharnessがlabel/descriptionの正本を持つ。両方のフィールドを併せ持つ、あるいはどちらも欠くrequirement.ymlはvalidateで拒否する(0023)。
FeatureからRequirementへの多対多関連は、新しいContributesTo型・格納先を作らず、現行のfeature.requirement_uidsをそのまま用いる(正本はFeature側、逆方向一覧は派生。0017§1・§3)。「実現に寄与する」ことを示すのみで、検証済みの証明ではない。既存フィールドで足りるため新規型を作らないのはP6(YAGNI)に従う判断である。
ReleaseScopeは「そのリリースで何を検証対象に選んだか」だけを記録する(0024)。選定日時・担当者・承認状態・合否は持たず、内容は人がCLIで記録する。.markharness/releases/<release_id>.ymlとしてGit管理下に置くため、--at <ref>で過去時点の選定も再現できる。release_idはこのパスの単一の構成要素になるため、現行generate.rsのrequire_valid_slugがid:に課しているのと同じ理由で文字集合を制限する:ASCII小文字英数字・ハイフン・ドットのみを許し、空文字、.と..そのもの、先頭がドットの値、パス区切り(/・\)やドライブ指定を含む値は書き込み前に拒否する(v1.2.0のようなtag名は通り、../../etc/passwdは通らない)。書き込み自体もfs_safetyの原子的置換経路を通す。選定リストが無いリリースについては、Release Coverageは従来どおり登録状態の一覧だけを返す(§6.2)。
ExecutionBindingは§1.1・0020・0025の通りTestCase単位の最小限の記録である。これは「実行された事実」ではなく検証手段(自動/手動)とその参照先の対応宣言を表す。合否・日時・実行回数を持たないため、値の存在を「最新版で実行済み」と読んではならない。将来のExecution Factへ変換・読み替えず、別の型として追加する。
| 項目 | 現行 | 本版 |
|---|---|---|
source |
無し | 追加。必須とし、省略したrequirement.ymlはvalidateで拒否する(0026§7、AC09b) |
requirement.ymlのlabel/description |
markharnessが本文相当を保持 | nativeでは維持。externalでは書けない(P1。表示名が必要になった時点でM3のStrictDoc Adapterが都度取得する) |
source_locator/source_revision |
無し | externalで必須、nativeでは書けない。欠落・混在はvalidateで拒否する |
axis |
保持 | 両モードで保持(markharness自身の分類であり外部正本の複製ではない) |
uid・feature.requirement_uids |
ADR 0013のUID・多対多関連 | そのまま維持 |
| Requirement authoring | 対話フローでlabel/axisを入力 |
0028により対話フローは廃止。Knowledge Intentへsourceごとのfieldを書く(nativeはlabel、externalはsource_locatorとsource_revision: current。AC02と整合) |
traceability.rsのRequirement索引・GeneratedFrom.requirement_ids/requirement_uids |
実装済み | 維持 |
sourceは必須であり、省略時のdefaultは持たない。0023§1の「省略時はnative」は既存ファイルを無変更で通すための互換規定であったため、過去を無かったものとして扱う方針(0026§7)の下では適用しない。externalへ移す場合は人が書き直す(§2の後方互換不要方針により自動変換は作らない)。
Requirementの意味変更、またはTestCaseの実効内容変更を検知した際、関連する他方(TestCaseまたはRequirement)の状態を次の三値で出力する(0019)。独立した承認ワークフローは作らない。
| 状態 | 条件 |
|---|---|
| 追随変更あり | 同じbase/head区間内で関連する他方の実効内容も変更されている。意味の整合を人が確認した証拠ではない |
| 確認済み | 有効なSpec-Reviewedトレーラーが対象を特定して存在する |
| 未確認 | 上記いずれでもない |
「追随変更あり」と「確認済み」を同じ状態にまとめない。両方のファイルがたまたま同じPRで変わっただけでは意味の整合を確認したことにならない、という0019の前提をそのまま出力に反映する。
トレーラーの扱いは次の規則による。
Spec-Reviewed: no-change-required (req-login-01)のように対象を書く。対象のないトレーラーで複数のRequirement/TestCaseをまとめて確認済みにはしない(未確認のまま残す)。片側指定から相手を一意に解決できない場合は、Spec-Reviewed: no-change-required (req-login-01, <case-uid>)のように両側を明示する(規則2)。requirement.ymlまたは.sdoc blob)が変更された場合、その組の確認を無効化する。別の組への確認の流用や、後から追加されたケースへの拡張はしない。無効な記録は「確認済み」の根拠にせず、有効な別記録がなければ§5.3の規則に従い「追随変更あり」または「未確認」を出力する。Spec-Reviewed: <value>形式の行のみをトレーラーとして解釈する。引用行・インデントされた行・コードブロック内の同名文字列は対象外とし、本文中の言及を宣言と誤認しない。git log base..headの各コミット本文を走査する実装とし、末尾行だけを見る実装にしない。有効範囲(規則2)を解決できない記録は採用しない。.sdocのtreeに加えてbase..headのコミット履歴が含まれる(P3の再現性契約に含める)。shallow cloneやfilterで履歴が取得できない場合は診断付きで失敗させ、履歴不足を「確認済み」として扱わない。base/head間のFeature版比較(現行changes.rsのChangeEvent計算を流用)に加え、次を行う。
contributes_toするRequirement)と、Requirementの変更起点(変更されたRequirement→関連するFeature・TestCase)の両方を辿る。Featureが変更されていないPRでもRequirementの変更を見落とさないため、探索をFeature変更の有無に依存させない。source: native:requirement.yml自体のbase/head差分。粒度はRequirement単位で、外部ツールを必要としない。source: external:source_locatorが指す.sdoc blobのbase/head差分。.sdocがmarkharnessと同一のGitリポジトリで管理されていることを前提とし、.sdocの構文解析を必要としない。粒度はファイル単位であり、同一ファイル内の別Requirementの変更でも「変更あり」と判定される(偽陽性を許容する。Requirement単位の粒度が必要になった時点でM3の.sdoc解析へ引き上げる)。source_revisionがhead時点のblob OIDと一致しない場合、「固定参照が古い」として出力する。これは2の変更検知とは独立した項目であり、source_revision: currentによる参照更新が仕様変更の検知を打ち消してはならない(同一PR内で.sdocを変更しrepinしても、2の差分は成立する)。この方式により、Change Impact(M1)は.sdocパーサ(M3)にも、StrictDocの導入有無にも依存しない。repin(source_revision: current)は固定参照を現在値へ進める操作にすぎず、対応確認の代替ではない(確認の記録は§5.3のトレーラーだけが担う)。repin後の無変更PRでは、base/head間に差分がないため新たな仕様変更としては報告されない。
指定したRequirement/Feature集合全体について、次を一覧化する。
ExecutionBindingが存在するか、modeは何か。contributes_toするFeatureが存在するか(coverage gap)。Change Impactが「今回の差分で何が変わったか」を示すのに対し、Release Coverageは「リリース対象全体を取りこぼしなく見渡せるか」を示す補助情報であり、リリース判断時にChange Impactと併用する。
Release Coverageは指定したGit ref(既定はHEAD)の内容で評価する。--releaseを指定しない場合、出力の意味は「その時点でKnowledgeに登録されていたTestCaseと検証手段の一覧」であり、実行された事実ではない。modeの存在を「実行済み」と表示しない(§5.2)。
--release <release-id>を指定した場合は、当該ReleaseScope(§5.2、0024)を読み、次を追加で示す。
ExecutionBindingがあるか、modeは何か。§1の問い3(前回リリースでどのテストが検証スコープに入っていたか)は、リリースtagを--atに、そのリリースのrelease_idを--releaseに渡して答える。ReleaseScopeが記録されていないリリースについては、答えられるのは登録状態の再現までである。ExecutionBindingもReleaseScopeも日時を持たないため、時点の指定はGit refに委ねる(P3)。選定リストは人が記録した「選んだ」という宣言であり、実行された証跡ではない。
markharness knowledge reconcile <intent-file> # Requirement関連の追加・削除はUID付きFeatureのcontributes_toを全置換
# repinはUID付きRequirementのsource_revision: current
markharness binding set --case-uid <case-uid> --mode automated --reference src/tests/login.spec.ts
markharness binding set --case-uid <case-uid> --mode manual
markharness release scope set --release <release-id> --case-uid <case-uid> [--case-uid ...] # 選定リストを置換
markharness release scope show --release <release-id> [--at <ref>] --format json
markharness impact --base <ref> --head <ref> --format json
markharness coverage --requirements <requirement-ids-or-all> [--release <release-id>] --at <ref> --format json
FeatureとRequirementの関連はfeature.ymlのrequirement_uidsが正本であり、新しい格納先は作らない(§5.2)。その編集は0028によりknowledge reconcileへ統合されている。出力はCLI/JSONのみとし、ローカルサーバーやダッシュボードはMVPに含めない(§8)。終了コード・JSON schemaのversioning方針は実装時に確定する。廃止するCLIは§9.1で扱う。
knowledge/編集フローを維持するのみ)。ReleaseScopeは「選んだ」という宣言のみを記録し、実行結果は扱わない(0024)。.sdocの自前パーサ・JSON export取込の自動化(ロードマップ扱い、§2)。| 現行資産 | 判断 | 理由 |
|---|---|---|
knowledge/一式(Feature/Behavior/Scenario/Axis、決定的生成) |
維持 | North Starの前提資産。§5.1 |
changes.rs(ChangeEvent計算) |
維持・拡張 | Change Impactの基盤としてそのまま使う。§6.1 |
case_definition.rs(Case revision固定保存) |
維持 | 既に0017§1〜4相当を実装済み |
execution.rs(target_revision/environment等) |
縮小 | 0020・0025のExecutionBindingへ置き換え |
plan.rs(Evidence適用可能性判定)・markharness plan |
廃止 | 厳密な突合ロジックは0020で不要になり、残る「ExecutionBindingの有無を返す」機能はcoverageと重複する(0026)。application.rs・presentation.rsのplan経路も同時に削除する |
src/identity/feature_ops.rsのretire_entity/restore_entity/release_id/reissue_entityとそのエラー型(約524行)、event.rsのIdentityMutation::{Retired, Restored, Released, Reissued}、engine.rsの該当status遷移とStatus::Retired、migration_manifest.rsのreissue依存部 |
縮小 | 0021。2026-09-11の実測により対象ファイルを特定した(recovery.rs・lock.rsに現れるreleaseはIdentityLockのファイルロック解放であり本件と無関係、audit.rsには該当語の出現が無い)。0026 |
src/identity/(UID発行/rename部分) |
維持 | 0021の対象外 |
src/git.rs・fs_safety.rs |
維持 | 不変ref読出し・原子的操作は今回の変更と独立 |
src/canonical.rs(ImportSourceArg等) |
縮小 | markharness import(native/junit)専用に縮小する。plan廃止に伴いCanonicalEvidence/EvidenceResult等のplan専用型を削除。StrictDoc取込は将来別Adapterとして再設計(0026) |
knowledge/requirements/(native Requirement実体) |
維持・拡張 | nativeはlabel/descriptionを含めそのまま維持する。source: externalを選んだRequirementでのみ本文相当を持たず固定参照になる(0023、§5.2.1) |
src/traceability.rs(Requirement索引) |
維持 | Requirement⇄TestCaseの逆引きは既存実装をそのまま使う |
src/server.rs・ui/・markharness serve(ADR 0008 Stage 3のdashboard) |
廃止 | 現行UIはplan/evidence出力に依存し、plan縮小と同時に壊れる(0022)。§9.1 |
src/milestone.rs・src/lineage.rs |
維持 | src/changes.rsがmilestone::verify_audit_matches_tag(fail-closedゲート)とlineage::classify(merge分類)を内部利用しており、削除するとchanges computeがコンパイル不能になる(0026) |
src/backfill.rs・src/verify.rs |
維持 | 逆依存ゼロだが0020〜0025のいずれとも衝突せず、廃止する積極的な理由が無い(0026) |
src/derived_index.rs・markharness cache index |
廃止 | 入力であるplan::BoundVersionsとexecution::read_all_resultsが廃止・置換される。派生キャッシュはChange Impact/Release Coverageの設計に登場せず、CLI統合テストも無い(0026) |
src/audit_scope.rs |
維持 | identity migrate --json・identity audit --json・changes compute --jsonの出力契約(0013検証規則)に含まれる |
identity CLIのretire/restore/release/reissue |
廃止 | 0021。既存イベントログの扱いは§9.1 |
identity retire/restore/release/reissue(0021)、plan(0026)、execution record(binding setへ置換、0020・0025)、serve(0022)、cache index(0026)、knowledge add/scaffold/validate/apply・feature rename-id・requirement link/unlink/repin(いずれもknowledge reconcileへ統合、0028)。削除範囲は実装時のチェックリストで確定する。ExecutionBindingは新しい保存先.markharness/bindings/のみを読み、旧.markharness/executions/配下の実行記録は参照しない。廃止したevent種別はIdentityMutationから削除されるため、それを含むログは読み取り経路に存在しない。自動変換も、互換replayも、旧データを名指しする診断も実装しない——いずれも互換コードであり、本方針の排除対象である。旧ディレクトリがworktreeに残っていても新コードのどの経路も読まないため、動作には影響しない。同じ理由でrequirement.ymlのsourceは必須とし、省略時のdefaultを持たない(§5.2.1、AC09b)。src/server.rs・ui/・markharness serve・frontendのbinary同梱を削除する(0022)。削除はplan縮小と同じタイミングで行い、tests/server.rs等の関連テストも同時に削除する。リポジトリ外のviewerがplan出力を参照している場合は、Change Impact/Release Coverage出力への切替が必要になる。V2は将来の完全モデルを部分実装するものではない。V2単体でNorth Starの4問へ答えられる小さな製品として完成させ、その後にStrictDoc→markharness→Playwrightの流れを実運用して、必要性が確認された概念だけを追加する。詳細な決定理由は0025を正とする。
V2の時点で、次の契約を安定させる。
referenceは移動可能な案内であり、照合のIdentityにはしない。schema_versionを持ち、解決済みの完全なGit commit ID、入力schema version、判定に影響する規則versionを含める。同じ入力を別のAI・CLI・CIが読んでも判定根拠を再現できる形にする。これらは将来機能の先行実装ではなく、後から変更すると既存Knowledge・関連・履歴の移行が必要になる最小の永続契約である。
V2と将来モデルの関係を次のように固定する。
| V2の記録 | V2が保証する事実 | 将来追加し得る別の記録 | 禁止する読み替え |
|---|---|---|---|
ExecutionBinding |
Case UIDに自動または手動の検証手段と参照先がある | ExecutionFact |
bindingがあるため実行済み・合格とみなす |
ReleaseScope |
そのreleaseでCase UIDを選定した | ReleasePlan |
選定一覧を版・理由・build・環境まで確定した計画とみなす |
Spec-Reviewed trailer |
commit時点で対象の対応確認を記録した | ImpactDecision、HumanAttestation |
欠落しているLink・policy digestや承認を補完する |
| Git上の削除・再登場 | その時点でファイルが無い、または再び存在する | retire、restore event |
削除意図や同一Identityとしての復元を推測する |
永続レコードにはschema_versionを持たせる。複数種類のレコードを同じ保存領域または出力に載せる場合はrecord_kind等で種類を明示する。ただしschema_versionは全種別で1に固定し、今後も上げない。これは過去のレコードを読むための互換機構ではなく、将来別種のレコードを追加したときに種類を取り違えないための前方向の契約だからである。旧版を読む必要が生じた場合も版で分岐せず、新しい型として追加する(§9.1の既存データ方針)。record_kindの値はexecution_binding・release_scope・requirement・change_impact・release_coverageとする。将来の型に必要そうなフィールドをすべてoptionalとしてV2へ足さない。完全モデルは別の型・保存契約として追加し、V2に存在しない情報はunknownまたはlegacyとする。
StrictDoc固有の構文解析とPlaywright固有のreporter形式をDomainへ入れない。ただし、実在する形式が一つしかない段階で汎用plugin interfaceを作らない。最初の実装はApplication境界で正規化し、二つ目の実在Adapterまたは交換要求が現れた時点で共通seamを抽出する。
将来形式を追加するときは、旧レコードを破壊的に変換するのではなく、必要に応じて複数readerから同じ読み取りモデルへ正規化する。
ExecutionBinding reader ─┐
ExecutionFact reader ────┴→ release verification read model
Trailer decision reader ─┐
Structured decision reader┴→ alignment resolution read model
上図は将来の発展方向であり、V2で空のreaderやseamを実装する要求ではない。二つ目の入力が存在するまで、型の区別と保存場所の衝突回避だけを維持する。
M3・M4では機能実装だけでなく、次の事実を記録して次段階の設計入力にする。
これらの観測で具体的な不足が確認されたときだけ、Release Plan、Execution Fact、構造化Decision、dashboard等を別ADRで昇格させる。
V2期間中に保存しなかった情報を、Git履歴や自然言語から完全な事実として推測しない。将来、Case revision・build・環境まで照合するExecution Fact、またはretire・restore・ID予約を含む完全なIdentity lifecycleを導入する場合は、保証開始commitを明示する。
cutover前の記録は次のように扱う。
ExecutionBindingはそのままbindingとして有効だが、過去に実行されたFactへ変換しない。ReleaseScopeは選定事実として有効だが、理由・対象版・実行条件はunknownとする。retire・restoreへ変換しない。このcutoverは、過去データを捨てるためではなく、V2が実際に記録した弱い事実と、将来記録する強い事実を混同しないための境界である。
将来性を残す目的で、次をV2へ追加しない。
ExecutionBinding。ImpactDecisionまたはHumanAttestation。retire・restore・ID予約状態遷移。ReleaseScope。V2の拡張容易性は、未来のフィールドを予約することではなく、現在の型の意味を狭く保ち、別の事実を別の型として後から追加できることによって確保する。
| 段階 | 作るもの | 完了条件 |
|---|---|---|
| M0 ✅ | Requirementの新schema(native/externalの二モード)・ExecutionBindingのschema、feature.requirement_uidsによる関連付け、CLI(§7)、Alignment check(§5.3)の自動判定、対話作成フローの更新(§5.2.1) |
native運用(StrictDocなし)とexternal運用の双方でFeature⇄Requirementの対応とTestCaseのExecutionBinding記録がGit/CLI経路で完結し、モードの混在したrequirement.ymlが拒否される |
| M1 ✅ | Change Impact(§6.1) | PR base/head間で影響Feature・Requirement・未確認Alignment checkを一覧できる(.sdoc解析=M3に依存しない) |
| M2 ✅ | Release Coverage(§6.2)とReleaseScope(§5.2) |
指定Requirement集合全体のcoverage gapを一覧でき、選定リストを記録したリリースでは選定・選定漏れ・不在Case UIDを併せて一覧できる |
| M3(将来) | StrictDoc .sdoc取込(Git管理された要件の実体反映) |
需要確認後に着手。自前パーサの要否を含め別途設計する |
| M4(将来) | Playwright連携の実運用検証 | 要望が出た時点で着手。まずCase UIDとExecutionBindingによる接続・外部reportの観測を行い、結果を永続的なExecution Factとして取り込むかは§9.2の観測後に別ADRで決める |
MVPはM0〜M2とする。M0〜M2は2026-09-12に実装完了した(✅)。M3・M4は本書の時点では着手を約束しない。
| ID | シナリオ | 期待結果 |
|---|---|---|
| AC01 | FeatureをRequirementへcontributes_toで関連付ける |
関連はFeature側が正本を持ち、逆引き一覧は派生する |
| AC02 | source: externalのRequirementの本文(label/description)をmarkharnessから編集しようとする |
拒否する。externalではmarkharnessは固定参照のみ保持する(0023) |
| AC02b | source: nativeのRequirementのlabel/descriptionを編集する |
成功する。nativeではmarkharnessが本文の正本を持つ |
| AC03 | Requirementが変更されたのに関連TestCaseが更新されていない | Change Impactの出力で「未確認」として明示する |
| AC04 | TestCase変更コミットに、対象を特定したSpec-Reviewed: no-change-required (req-xxx)が付与され、相手側のCase UIDが一意に解決できる |
Alignment checkは当該の組について「確認済み」と判定する(§5.3) |
| AC05 | TestCaseにExecutionBinding(mode=manual)を記録し、日時や実行者は渡さない |
記録が成立する。日時・実行者フィールドは存在しない |
| AC06 | 同一入力から複数回Change Impact/Release Coverageを計算する | 同じ出力を再現する(P3) |
| AC07 | 削除したTestCaseと同じ内容のScenarioをCLIで新規作成する | 新しいScenario UIDが発行され、そこから導出されるCase UIDも別値になる。内容の一致を理由に旧UIDを推定しない(0021) |
| AC07b | 削除したScenarioのファイルをGit履歴から復元する(git checkout <ref> -- <path>等) |
ファイル内のuid:が戻るため、当時のScenario UID・Case UIDが復活する。これはmarkharnessのrestore機能ではなくGit履歴操作であり、markharnessはこれを禁止も検出もしない(0021§2) |
| AC08 | Requirementにcontributes_toするFeatureが一つもない |
Release Coverageでcoverage gapとして一覧される |
| AC09 | source: externalなのにsource_locator/source_revisionを持たないrequirement.ymlを置く |
validateが拒否する(§5.2.1) |
| AC09b | sourceを省略したrequirement.yml(labelあり)を置く |
validateが拒否する。モード判定を暗黙のdefaultに委ねない(§9.1) |
| AC09c | labelとsource_locatorを両方持つrequirement.ymlを置く |
validateが拒否する(モード混在) |
| AC10 | source: externalのRequirementで、source_locatorが指す.sdoc blobがbaseとheadで異なる |
Change Impactが仕様側変更として検出する。.sdocの構文解析は行わない(§6.1手順2) |
| AC10b | source: nativeのRequirementのlabel/descriptionをbase/head間で変更する |
Change Impactが仕様側変更として検出する(§6.1) |
| AC10c | .sdocはbase/head間で変更されていないが、source_revisionがhead時点のblob OIDと一致しない |
stale pinとしてのみ出力する。仕様側変更としては報告しない(§6.1手順3) |
| AC11 | 過去のリリースtagを--atに指定してRelease Coverageを算出する |
当時のKnowledge・ExecutionBindingに基づく一覧を再現する(§6.2) |
| AC12 | 1コミットで複数のRequirementに触れ、対象を書かないtrailerを付与する | どの対応確認が済んだか判定できないため「未確認」のまま残る(§5.3) |
| AC13 | Scenarioの表示idをrenameする | ExecutionBindingはCase UID参照のため維持される(§5.2) |
| AC14 | C1でRequirement Rを変更しSpec-Reviewedを付与、同一PRのC2でRをさらに変更する |
C1の確認は無効になり、Rは「未確認」として出力される(§5.3規則2) |
| AC15 | RequirementとTestCaseが同一PRで変更されているが、Spec-Reviewedが無い |
「追随変更あり」として出力し、「確認済み」とはしない(§5.3) |
| AC16 | 対象を書かないSpec-Reviewedトレーラーを、複数Requirementに触れるコミットに付与する |
どのRequirementも確認済みにならない(§5.3規則1) |
| AC17 | shallow cloneなどでbase..headのコミット履歴を取得できない |
診断付きで失敗する。履歴不足を「確認済み」として出力しない(§5.3規則5) |
| AC18 | 同一PRで.sdocを変更し、同じPR内でrepin(source_revision: current)も実行する |
仕様変更として検出される。repinは検知を打ち消さない(§6.1手順3) |
| AC19 | repin後、内容を変更しない次のPRを評価する | 新たな仕様変更としては報告されない。固定参照が古い場合のみstale pinとして出力する(§6.1手順3) |
| AC20 | Requirementのみが変更され、関連Featureは変更されていない | 関連Feature・TestCaseを逆引きし、影響とAlignment checkを出力する(§6.1手順1) |
| AC21 | RequirementにFeatureは関連付いているが、そのFeature配下にScenarioが一つもない | Release Coverageが当該Featureをcoverage gapとして明示する(§6.2) |
| AC23 | 発行(issued)とrenameのみで構成されたidentity-eventsを読み込む |
決定的にreplayでき、UIDとidの対応を再現する(§9.1) |
| AC24 | ReleaseScopeを記録し、過去のリリースtagを--at、release_idを--releaseに渡してRelease Coverageを算出する |
当時選定されたTestCaseと、その検証手段の有無を再現する(§6.2) |
| AC25 | 対象Requirement配下にあるが選定リストに入っていないTestCaseがある | 選定漏れ候補として一覧される(§6.2) |
| AC26 | 選定リストに、その時点のKnowledgeに存在しないCase UIDが含まれる | 不在のCase UIDとして明示する。選定リストを自動的に書き換えない(§6.2) |
| AC27 | ReleaseScopeに選定日時・担当者・合否を渡そうとする |
フィールドが存在せず記録できない(0024) |
| AC28 | release_idに../../etc/passwd、..、/abs/path、先頭ドットなどを渡す |
書き込み前に拒否し、.markharness/releases/の外にも中にもファイルを作らない(§5.2) |
| AC29 | C1でケースAを変更し要件Rの変更不要を確認、C2でAだけを再変更する | Rが不変でも組(R,A)の確認は無効。確認済みとはせず、この例では未確認を出力する |
| AC30 | 片側指定のトレーラーから複数の相手ケースが候補になる | 一括確認しない。両側を明示して組を一意に解決できる記録だけ採用する |
| AC31 | 組(R,A)の確認後、別ケースBが追加される | Bへ確認を流用しない。元の組の内容が不変ならその確認は維持する |
| AC32 | ExecutionBindingへresult、executed_at、build、environmentを渡す |
V2のbinding schemaに存在しないフィールドとして拒否し、実行事実として保存しない(§9.2.2) |
| AC33 | 将来のreaderがV2のReleaseScopeを読む |
選定されたCase UIDだけを既知とし、理由・Case revision・build・環境はunknownとして扱う(§9.2.2) |
| AC34 | Playwrightのtest titleまたはファイルパスを変更し、Case UIDのannotationは維持する | 同じTestCaseへのbindingとして解決し、titleやpathをIdentityとして扱わない(§9.2.1) |
| AC35 | Playwright report内で一つのCase UIDが0件または複数件へ解決される | 実運用観測へ明示的に記録し、自動的に任意の1件を選ばない(§9.2.4) |
| AC36 | 将来の完全なIdentity lifecycle導入前に、V2で削除・再登場した要素がある | migration manifestで明示されない限りretire/restoreを推定せず、cutover前のlifecycleをlegacyまたはunknownとして扱う(§9.2.5) |
| AC37 | 同じbase/headと規則versionでChange Impactを再計算する | JSONのschema_version、解決済みcommit ID、規則versionを含めて同じ判定を再現できる(§9.2.1) |