phasegate 0.68.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,205 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.70.0] - 2026-04-22
11
+
12
+ ### Added
13
+
14
+ - ISSUE-007 Wave 5 — `docs/guide/retrofit-adoption.md` を追加。既存プロジェクトへの phasegate 後付け導入チュートリアル(`init` → `baseline` → `scaffold-design` の 4 ステップ、phase-gate エラーの読み方、baseline 卒業手順、よくある詰まり方の QA)。
15
+
16
+ ## [0.69.0] - 2026-04-22
17
+
18
+ ### Added
19
+
20
+ - ISSUE-007 Wave 4 / Phase C — `npx phasegate scaffold-design --unit <id> --phase <logical|domain|uiux|unit-test|it-test> [--force] [--json]` CLI を追加。`templates/*.template.md` を読み取り `{{unit}}` プレースホルダを置換して `docs/product/construction/{unit}/*.md` に書き込む。既存ファイルは `--force` なしでは保護。Wave 3 の pre-tool-use hook エラーで emit される `scaffold:` 行が実動作するようになった。
21
+ - `templates/{domain_model,uiux_design,unit_test_design,it_test_design}.template.md` を追加(5 phase すべてに minimum viable template)。
22
+
23
+ ### Changed
24
+
25
+ - Wave 3 の L2-001 `defaultTemplatePath` を `docs/templates/logical_design.template.md` → `templates/logical_design.template.md` に修正(配布物と整合)。
26
+
27
+ ## [0.68.0] - 2026-04-22
28
+
29
+ ### Changed
30
+
31
+ - `skills/` 同梱物のクリーンアップ — skill-creator の `scripts/__pycache__/` Python バイトコンパイルキャッシュが npm 配布物に混入していたため除去。`.gitignore` / `.npmignore` に `__pycache__/` と `*.pyc` を追加。skill-creator の使用例パスを Anthropic 原本の `skills/public` / `skills/private` から PhaseGate レイアウトに合わせた `skills` に統一。
32
+
33
+ ## [0.67.0] - 2026-04-22
34
+
35
+ ### Changed
36
+
37
+ - ISSUE-007 Wave 3 / Phase B — `phase-gate` の HarnessError をアクショナブル化(足りない設計文書のパスと推奨アクションを `fix_example` に明示)。
38
+
39
+ ## [0.66.0] - 2026-04-22
40
+
41
+ ### Added
42
+
43
+ - ISSUE-007 Wave 2 / Phase A-2 — `.phasegate/baseline.json` に登録済みかつ sha1 が一致するファイルを `phase-gate` 対象から除外する **baseline grandfather** を pre-tool-use hook に統合。レガシーリポジトリへの後付け導入時の摩擦を解消する。
44
+
45
+ ## [0.65.0] - 2026-04-21
46
+
47
+ ### Added
48
+
49
+ - ISSUE-007 Wave 1 / Phase A-1 — `npx phasegate baseline [--dry-run|--force|--paths|--json]` CLI を追加。`.phasegate/baseline.json` スナップショットを生成し、phasegate.config.json に `baseline.{enabled, path}` スキーマを追加。
50
+
51
+ ## [0.64.0] - 2026-04-21
52
+
53
+ ### Added
54
+
55
+ - ISSUE-006 Story B — `quickMode.fullModeRequiredWhen` の判定を pre-tool-use hook に統合。`mixedCategories` / `newDomainFile` / `apiContractChange` のいずれかが立つと書き込み時点で同期的に Full Mode へエスカレートしブロックする(block reason: `FULL_MODE_REQUIRED`)。
56
+
57
+ ## [0.63.0] - 2026-04-21
58
+
59
+ ### Added
60
+
61
+ - ISSUE-006 Story A — `quickMode.fullModeRequiredWhen` 設定キー(`mixedCategories` / `newDomainFile` / `apiContractChange`、いずれもデフォルト `true`)を導入し、Quick Mode → Full Mode のエスカレート条件を設定駆動化。
62
+ - `npx phasegate check-change-category --paths <csv> [--format json] [--fail-on-full-required]` CLI — 任意のファイルリストを Quick Mode カテゴリに分類し、Full Mode が必要かを返す。CI gate での使用を想定。
63
+
64
+ ## [0.62.0] - 2026-04-21
65
+
66
+ ### Added
67
+
68
+ - ISSUE-013 C-6(軽量版)— UserPromptSubmit hook に violation detection を追加。
69
+
70
+ ## [0.61.0] - 2026-04-21
71
+
72
+ ### Added
73
+
74
+ - ISSUE-013 C-5 — UserPromptSubmit hook で動的状態(現在の Quick/Full モード等)をプロンプトに注入。
75
+
76
+ ## [0.60.0] - 2026-04-21
77
+
78
+ ### Added
79
+
80
+ - ISSUE-013 C-4 — SessionStart hook を追加し、セッション開始時に静的ルール(CLAUDE.md 等)を注入する仕組みを実装。
81
+
82
+ ## [0.59.0] - 2026-04-21
83
+
84
+ ### Added
85
+
86
+ - ISSUE-013 A-1 / A-2 / B-3 — `phasegate init --agent <claude|codex|both>` オプションで Codex CLI 向けの `.codex/hooks.json` を自動配置。Codex dogfood セットアップを README に追記。
87
+
88
+ ## [0.58.0] - 2026-04-21
89
+
90
+ ### Added
91
+
92
+ - ISSUE-013 Wave 2 — Codex CLI 統合の本体実装。`PreToolUse(Bash)` / `PostToolUse(Bash)` / `Stop` フックを Codex 向けに配線。
93
+
94
+ ## [0.57.0] - 2026-04-20
95
+
96
+ ### Added
97
+
98
+ - ISSUE-013 Wave 1 — `BashWriteTargetExtractor` が Bash 経由 `apply_patch <<'PATCH'` heredoc の書き込み先パスを抽出するよう拡張。Codex の Bash ルートを pre-tool-use hook で押さえられるようになる。
99
+
100
+ ## [0.56.0] - 2026-04-20
101
+
102
+ ### Fixed
103
+
104
+ - ISSUE-011 Wave 3 / P3-4 / HF2-04 — `initial-creation-expiration-checker` バリデータを修正。
105
+
106
+ ## [0.55.0] - 2026-04-20
107
+
108
+ ### Fixed
109
+
110
+ - ISSUE-011 Wave 2 — Markdown parser の code-span / code-fence 内に書かれた `@unit` / `@layer` 等のメタタグを誤検出していたバグを修正(コードフェンス内をスキップするよう変更)。
111
+
112
+ ## [0.54.0] - 2026-04-20
113
+
114
+ ### Fixed
115
+
116
+ - ISSUE-011 Wave 1 / P2-2 — CLI のエラー伝播を修正(内部エラーが exit code 0 で握り潰されていた問題)。
117
+ - ISSUE-011 Wave 1 / P2-3 — `.mdx` / `.markdown` 拡張子を Markdown ドキュメント検証の対象に追加。
118
+
119
+ ## [0.53.0] - 2026-04-19
120
+
121
+ ### Added
122
+
123
+ - ISSUE-008 Phase C-1〜C-3 + D — テストファイルへの `@story` メタデータ end-to-end 検証を完成。`templates/` 配下のサンプルファイルを実体化し、生成コードへのメタデータ付与を保証する経路を確立。
124
+
125
+ ## [0.52.0] - 2026-04-19
126
+
127
+ ### Changed
128
+
129
+ - ISSUE-008 Phase B-3 — pre-commit フローに `.md` 設計文書の検証を接続。`logical_design.md` 等の frontmatter / メタデータが欠けたままコミットされるのを防ぐ。
130
+
131
+ ## [0.51.0] - 2026-04-19
132
+
133
+ ### Added
134
+
135
+ - ISSUE-011 起票(`validate-metadata` UX / parser / drift 検出に関する改善集)。
136
+
137
+ ## [0.50.0] - 2026-04-19
138
+
139
+ ### Added
140
+
141
+ - ISSUE-008 Phase B-2 — `validate-metadata` CLI に `.md` 分岐を追加。Markdown 設計文書のメタデータ(frontmatter)も検証対象になる。
142
+
143
+ ## [0.49.0] - 2026-04-19
144
+
145
+ ### Changed
146
+
147
+ - ISSUE-008 Phase B-1 撤回 + P1-2 前提更新 — 設計文書 frontmatter 必須化(v0.48.0)の方針を再検討し前提を更新。
148
+
149
+ ## [0.48.0] - 2026-04-19
150
+
151
+ ### Added
152
+
153
+ - ISSUE-008 Phase B-1 / P1-2 — 設計文書(`logical_design.md` / `domain_model.md` 等)の frontmatter を必須化。
154
+
155
+ ## [0.47.0] - 2026-04-18
156
+
157
+ ### Added
158
+
159
+ - ISSUE-008 Phase A / P1-1 — 生成コードに `@unit` / `@layer` メタデータを必ず付与するよう、各実装スキル(`story-implementor` / `quick-implementor`)に指示を追加。
160
+
161
+ ## [0.46.0] - 2026-04-18
162
+
163
+ ### Added
164
+
165
+ - ISSUE-007 起票(リトロフィット導入障壁 — レガシーリポジトリでの初回 phase-gate ブロック問題)。
166
+ - ISSUE-008 起票(メタデータ emit 欠落 — 生成コードに `@unit` / `@layer` が付かないケース)。
167
+
168
+ ## [0.45.0] - 2026-04-18
169
+
170
+ ### Added
171
+
172
+ - ISSUE-006 起票 + Phase P2-3 — `docs/guide/quick-vs-full-mode.md`(Quick Mode と Full Mode の選択ガイド)を新設。
173
+
174
+ ## [0.44.0] - 2026-04-18
175
+
176
+ ### Fixed
177
+
178
+ - ISSUE-005 Phase D / P3-8 — Markdown のメタ見出し(`---` で囲まれた frontmatter 等)をパース時に正しくスキップするよう修正。
179
+ - ISSUE-005 Phase D / P3-9 — ファイルパスから `@unit` を推定するロジックを改善。
180
+ - ISSUE-005 Phase D / P3-10 — `list-errors` と `render-errors` の境界をドキュメント化(`list-errors` は定義駆動 / `render-errors` はランタイム駆動)。
181
+
182
+ ## [0.43.0] - 2026-04-18
183
+
184
+ ### Fixed
185
+
186
+ - ISSUE-005 Phase C / P2-6 — `phasegate:check-phase` の `--help` / `--json` フラグが positional 引数として食われ unit 名扱いされていたバグを修正。
187
+ - ISSUE-005 Phase C / P2-7 — `regression:*` 系コマンドの出力先を整理。
188
+
189
+ ## [0.42.0] - 2026-04-18
190
+
191
+ ### Fixed
192
+
193
+ - ISSUE-005 Phase B-2 / P1-5 — `detect-drift` と L4-001 バリデータを統合し、設計-コード乖離検出の経路を一本化。
194
+
195
+ ## [0.41.0] - 2026-04-18
196
+
197
+ ### Fixed
198
+
199
+ - ISSUE-005 Phase B-1 / P1-3 — fresh repo(履歴がない初期化直後のリポジトリ)での git 解析が失敗するバグを fallback 経路で修正。
200
+ - ISSUE-005 Phase B-1 / P1-4 — `validate --layer` フィルタが効かないケースを修正。
201
+
202
+ ## [0.40.0] - 2026-04-18
203
+
204
+ ### Fixed
205
+
206
+ - ISSUE-005 Phase A / P0-1 — pre-commit 経路の復旧(一部バリデータが pre-commit から呼ばれていなかった問題)。
207
+ - ISSUE-005 Phase A / P0-2 — `ci:generate-template` の UX 改善(`--preset` 省略時のエラーメッセージを実用的に)。
208
+
10
209
  ## [0.39.0] - 2026-04-18
11
210
 
12
211
  ### Fixed
@@ -176,7 +375,36 @@ Pre-reset era (formerly v1.0.0 - v1.1.1). Initial release and early bug fixes:
176
375
  - ajv v8互換対応
177
376
  - 3件のバグ修正
178
377
 
179
- [Unreleased]: https://github.com/junpei-9898/phasegate/compare/v0.38.0...HEAD
378
+ [Unreleased]: https://github.com/junpei-9898/phasegate/compare/v0.67.0...HEAD
379
+ [0.67.0]: https://github.com/junpei-9898/phasegate/compare/v0.66.0...v0.67.0
380
+ [0.66.0]: https://github.com/junpei-9898/phasegate/compare/v0.65.0...v0.66.0
381
+ [0.65.0]: https://github.com/junpei-9898/phasegate/compare/v0.64.0...v0.65.0
382
+ [0.64.0]: https://github.com/junpei-9898/phasegate/compare/v0.63.0...v0.64.0
383
+ [0.63.0]: https://github.com/junpei-9898/phasegate/compare/v0.62.0...v0.63.0
384
+ [0.62.0]: https://github.com/junpei-9898/phasegate/compare/v0.61.0...v0.62.0
385
+ [0.61.0]: https://github.com/junpei-9898/phasegate/compare/v0.60.0...v0.61.0
386
+ [0.60.0]: https://github.com/junpei-9898/phasegate/compare/v0.59.0...v0.60.0
387
+ [0.59.0]: https://github.com/junpei-9898/phasegate/compare/v0.58.0...v0.59.0
388
+ [0.58.0]: https://github.com/junpei-9898/phasegate/compare/v0.57.0...v0.58.0
389
+ [0.57.0]: https://github.com/junpei-9898/phasegate/compare/v0.56.0...v0.57.0
390
+ [0.56.0]: https://github.com/junpei-9898/phasegate/compare/v0.55.0...v0.56.0
391
+ [0.55.0]: https://github.com/junpei-9898/phasegate/compare/v0.54.0...v0.55.0
392
+ [0.54.0]: https://github.com/junpei-9898/phasegate/compare/v0.53.0...v0.54.0
393
+ [0.53.0]: https://github.com/junpei-9898/phasegate/compare/v0.52.0...v0.53.0
394
+ [0.52.0]: https://github.com/junpei-9898/phasegate/compare/v0.51.0...v0.52.0
395
+ [0.51.0]: https://github.com/junpei-9898/phasegate/compare/v0.50.0...v0.51.0
396
+ [0.50.0]: https://github.com/junpei-9898/phasegate/compare/v0.49.0...v0.50.0
397
+ [0.49.0]: https://github.com/junpei-9898/phasegate/compare/v0.48.0...v0.49.0
398
+ [0.48.0]: https://github.com/junpei-9898/phasegate/compare/v0.47.0...v0.48.0
399
+ [0.47.0]: https://github.com/junpei-9898/phasegate/compare/v0.46.0...v0.47.0
400
+ [0.46.0]: https://github.com/junpei-9898/phasegate/compare/v0.45.0...v0.46.0
401
+ [0.45.0]: https://github.com/junpei-9898/phasegate/compare/v0.44.0...v0.45.0
402
+ [0.44.0]: https://github.com/junpei-9898/phasegate/compare/v0.43.0...v0.44.0
403
+ [0.43.0]: https://github.com/junpei-9898/phasegate/compare/v0.42.0...v0.43.0
404
+ [0.42.0]: https://github.com/junpei-9898/phasegate/compare/v0.41.0...v0.42.0
405
+ [0.41.0]: https://github.com/junpei-9898/phasegate/compare/v0.40.0...v0.41.0
406
+ [0.40.0]: https://github.com/junpei-9898/phasegate/compare/v0.39.0...v0.40.0
407
+ [0.39.0]: https://github.com/junpei-9898/phasegate/compare/v0.38.0...v0.39.0
180
408
  [0.38.0]: https://github.com/junpei-9898/phasegate/compare/v0.37.0...v0.38.0
181
409
  [0.37.0]: https://github.com/junpei-9898/phasegate/compare/v0.36.0...v0.37.0
182
410
  [0.36.0]: https://github.com/junpei-9898/phasegate/compare/v0.35.0...v0.36.0
package/README.ja.md CHANGED
@@ -588,7 +588,7 @@ export class ConfigSchema { ... }
588
588
 
589
589
  | Hook | タイミング | 動作 |
590
590
  |---|---|---|
591
- | **PreToolUse** | Write/Edit/Bash 実行前 | フェーズゲート違反・保護ファイルへの書き込み・Bash 経由の書き込み(`sed -i`, `tee` 等)をブロック |
591
+ | **PreToolUse** | Write/Edit/Bash 実行前 | フェーズゲート違反・保護ファイルへの書き込み・Bash 経由の書き込み(`sed -i`, `tee` 等)をブロック。`quickMode.fullModeRequiredWhen` トリガー時は Quick Mode → Full Mode へエスカレート(v0.64.0)。`.phasegate/baseline.json` 登録済みかつ未編集のファイルは grandfather として `phase-gate` をスキップ(v0.66.0) |
592
592
  | **PostToolUse** | Write/Edit 実行後 | Biome AST ルールを自動実行、違反を即時フィードバック |
593
593
  | **Stop** | セッション終了前 | L2-L4 全チェックを実行、全グリーンでないと終了を保留 |
594
594
 
@@ -807,4 +807,4 @@ phasegate 自体の開発(内部アーキテクチャ、回帰テスト、リ
807
807
 
808
808
  ---
809
809
 
810
- *Last updated: 2026-04-07 -- v0.33.0*
810
+ *Last updated: 2026-04-22 -- v0.66.0*
@@ -50,6 +50,37 @@ Both modes keep **L1 in full strength** and **L2 metadata / test-quality** — `
50
50
 
51
51
  ---
52
52
 
53
+ ## Automatic Escalation: `fullModeRequiredWhen`
54
+
55
+ Even when you launch `/quick-implementor`, the harness re-checks whether the in-flight change set actually qualifies as Quick. Three triggers force escalation back to Full Mode at the **pre-tool-use hook** (synchronous block, not just a post-hoc warning):
56
+
57
+ | Trigger | `quickMode.fullModeRequiredWhen.*` flag | Default | Block reason on hook |
58
+ |---|---|---|---|
59
+ | Change set spans multiple categories (e.g. `bugfix` + `api`) | `mixedCategories` | `true` | `FULL_MODE_REQUIRED` |
60
+ | New file added under any `domain/` directory | `newDomainFile` | `true` | `FULL_MODE_REQUIRED` |
61
+ | Modification to a Port (`*port.ts`) or Adapter (`*adapter.ts`) | `apiContractChange` | `true` | `FULL_MODE_REQUIRED` |
62
+
63
+ Introduced in v0.63.0 (ISSUE-006 Story A — config-driven flags + `check-change-category` CLI) and wired into the hook in v0.64.0 (Story B). Each flag can be flipped to `false` only when a project intentionally accepts the risk of merging that category of change without the design ceremony — e.g. early-stage prototypes where new domain files churn freely.
64
+
65
+ ### Dry-running the classifier
66
+
67
+ Use `check-change-category` to evaluate an arbitrary file list without actually starting an implementation:
68
+
69
+ ```bash
70
+ # Inspect what category each file lands in
71
+ npx phasegate check-change-category --paths src/foo.ts,src/bar.ts
72
+
73
+ # CI gate: hard-fail the build if Quick Mode would have to escalate
74
+ npx phasegate check-change-category \
75
+ --paths "$(git diff --name-only origin/main...HEAD | paste -sd, -)" \
76
+ --fail-on-full-required \
77
+ --format json
78
+ ```
79
+
80
+ `--fail-on-full-required` is opt-in; without it the command is purely informational (always exit 0).
81
+
82
+ ---
83
+
53
84
  ## Worked Examples
54
85
 
55
86
  ### Full Mode candidates
@@ -125,7 +156,7 @@ Not mechanically — Quick Mode does not inspect paths. A one-line bugfix inside
125
156
  Stop, commit nothing, and re-launch `/story-implementor`. Don't try to "finish in Quick" — you'll skip the design gate that would otherwise catch the scope creep.
126
157
 
127
158
  **Q. Can I disable Quick Mode entirely?**
128
- Yes — remove all entries from `quickMode.allowedCategories` in `phasegate.config.json`. All changes will route through Full Mode. This is reasonable for high-compliance projects.
159
+ Yes — remove all entries from `quickMode.allowedCategories` in `phasegate.config.json`. All changes will route through Full Mode. This is reasonable for high-compliance projects. Alternatively, leave the categories as-is and set every `quickMode.fullModeRequiredWhen.*` flag to `true` (the default) so any non-trivial scope automatically escalates.
129
160
 
130
161
  **Q. Can I add custom categories?**
131
162
  No. `allowedCategories` is a fixed enum (`bugfix`, `docs`, `test`, `config`). If your workflow needs a fifth category, that is evidence the change is probably Full Mode material.
@@ -0,0 +1,241 @@
1
+ # Retrofit Adoption Guide
2
+
3
+ 既に動いているプロジェクトに phasegate を後付け導入するためのチュートリアル。
4
+
5
+ ## このガイドの対象
6
+
7
+ - 既存コードベースに phasegate を導入したいメンテナ
8
+ - 設計文書(logical_design.md / domain_model.md 等)が未整備のまま保守と新規開発を並行したい状態
9
+ - 「phase-gate が既存コード編集で発火して保守が詰む」ことを避けたい
10
+
11
+ phasegate は本来「新規プロジェクトをゼロから AIDLC で組む」前提で設計されている。
12
+ 既存コードに後付けすると、設計文書の無いファイルを触るたびに pre-tool-use hook が発火し、
13
+ 通常の保守作業が block される。このガイドは ISSUE-007 で導入した **baseline grandfather** と
14
+ **scaffold-design CLI** を組み合わせて、段階的に phasegate 管理下に取り込む手順を示す。
15
+
16
+ ---
17
+
18
+ ## 前提
19
+
20
+ - Node.js >= 18.0.0
21
+ - 既存プロジェクトのソースコードが git で管理されている
22
+ - phasegate >= v0.69.0(scaffold-design CLI 含む)
23
+
24
+ ```bash
25
+ npm install --save-dev phasegate
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 4 ステップ後付け導入
31
+
32
+ ```
33
+ Step 1: npx phasegate init # 雛形・スキル配布
34
+ Step 2: npx phasegate baseline # 既存コードを grandfather 登録
35
+ Step 3: 既存ファイルの保守は gate をスキップ
36
+ Step 4: 新規 Unit / 構造変更は scaffold-design で設計文書を起こしてから実装
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Step 1: 初期化
42
+
43
+ ```bash
44
+ npx phasegate init --name <project-name>
45
+ ```
46
+
47
+ - `.claude/skills/` に 28 スキルを配置
48
+ - `phasegate.config.json` を生成
49
+ - `phasegate.config.json` の `baseline` セクションは既定で `enabled: true`
50
+
51
+ `phasegate.config.json` の該当部分(デフォルト):
52
+
53
+ ```json
54
+ {
55
+ "baseline": {
56
+ "enabled": true,
57
+ "path": ".phasegate/baseline.json"
58
+ }
59
+ }
60
+ ```
61
+
62
+ `baseline.enabled` を `false` にすると grandfather が無効化され、既存ファイルも全て
63
+ gate 対象になる(後付け導入では推奨しない)。
64
+
65
+ ---
66
+
67
+ ## Step 2: 既存コードを baseline に登録
68
+
69
+ ```bash
70
+ npx phasegate baseline
71
+ ```
72
+
73
+ 実行すると、現時点の全 TS/JS ソースファイルの相対パスと sha1 ハッシュを
74
+ `.phasegate/baseline.json` に保存する。
75
+
76
+ ```jsonc
77
+ {
78
+ "version": 1,
79
+ "createdAt": "2026-04-22T10:00:00Z",
80
+ "entries": [
81
+ { "path": "src/foo.ts", "sha1": "abc123..." },
82
+ { "path": "src/bar.ts", "sha1": "def456..." }
83
+ ]
84
+ }
85
+ ```
86
+
87
+ ### 確認だけしたい場合
88
+
89
+ ```bash
90
+ npx phasegate baseline --dry-run --json
91
+ ```
92
+
93
+ ### 特定ディレクトリだけ登録
94
+
95
+ ```bash
96
+ npx phasegate baseline --paths "src/**/*.ts,scripts/**/*.ts"
97
+ ```
98
+
99
+ ### `.phasegate/baseline.json` は commit する
100
+
101
+ grandfather 対象はチーム全員で共有するため、`.phasegate/baseline.json` は
102
+ `.gitignore` に入れず commit する。
103
+
104
+ ---
105
+
106
+ ## Step 3: 既存ファイルの保守
107
+
108
+ baseline に登録されたファイルは pre-tool-use hook で gate をスキップする。
109
+
110
+ - ファイル内容を編集しても sha1 が一致していれば許可(タイポ修正・コメント追加等)
111
+ - 構造的変更(新規 export 追加・レイヤー変更等)で sha1 がズレた瞬間、grandfather
112
+ が外れて通常の gate 対象に戻る。その時は Step 4 に進む
113
+
114
+ この段階では `logical_design.md` 等の設計文書が存在しなくても、既存ファイルの
115
+ 保守は通常通り行える。
116
+
117
+ ---
118
+
119
+ ## Step 4: 新規 Unit / 構造変更は scaffold-design
120
+
121
+ 新しい Unit を作る、あるいは baseline を外して既存 Unit を phasegate 管理下に
122
+ 取り込む場合、設計文書を先に起こす。
123
+
124
+ ### 4-1: phase-gate 発火時のエラーを読む
125
+
126
+ 設計文書が存在しない Unit に新規ファイルを作ろうとすると、pre-tool-use hook が
127
+ 以下の形式で block する(v0.67.0 以降):
128
+
129
+ ```
130
+ 成果物が不足しています: docs/product/construction/harness-api/logical_design.md
131
+ → phase gate prerequisites are not met
132
+
133
+ 次のアクション: /story-implementor スキルを使用して設計フェーズから開始してください。
134
+ scaffold: npx phasegate scaffold-design --unit harness-api --phase logical
135
+ テンプレ: templates/logical_design.template.md
136
+ ```
137
+
138
+ - **次のアクション**: `suggestedSkill` — 本格的に設計するなら Claude Code でこのスキルを呼ぶ
139
+ - **scaffold**: `scaffoldCommand` — テンプレだけ先に生成して placeholder で埋めたい時はこちら
140
+ - **テンプレ**: `templatePath` — 手書きしたい場合の参照元
141
+
142
+ ### 4-2: scaffold-design で雛形を生成
143
+
144
+ ```bash
145
+ npx phasegate scaffold-design --unit harness-api --phase logical
146
+ ```
147
+
148
+ 出力例:
149
+
150
+ ```
151
+ 設計文書を生成しました: docs/product/construction/harness-api/logical_design.md
152
+ テンプレ: /path/to/project/templates/logical_design.template.md
153
+ Unit: harness-api / phase: logical
154
+ TODO プレースホルダを実体で埋めてください。
155
+ ```
156
+
157
+ 生成されるファイルは `{{unit}}` が Unit ID に置換済みで、`TODO:` コメントが
158
+ 各セクションに残る。人間 / AI エージェントがこの TODO を埋めて設計を実体化する。
159
+
160
+ ### 対応する phase
161
+
162
+ | `--phase` | 生成先 |
163
+ |---|---|
164
+ | `logical` | `docs/product/construction/{unit}/logical_design.md` |
165
+ | `domain` | `docs/product/construction/{unit}/domain_model.md` |
166
+ | `uiux` | `docs/product/construction/{unit}/uiux_design.md` |
167
+ | `unit-test` | `docs/product/construction/{unit}/unit_test_design.md` |
168
+ | `it-test` | `docs/product/construction/{unit}/it_test_design.md` |
169
+
170
+ ### 4-3: 既存ファイルがある場合
171
+
172
+ 既定では scaffold は既存ファイルを上書きしない:
173
+
174
+ ```
175
+ 既に存在します: docs/product/construction/harness-api/logical_design.md
176
+ 上書きするには --force を指定してください。
177
+ ```
178
+
179
+ 意図的に再生成したい場合のみ `--force` を付ける:
180
+
181
+ ```bash
182
+ npx phasegate scaffold-design --unit harness-api --phase logical --force
183
+ ```
184
+
185
+ ### 4-4: JSON 出力(CI / スクリプト向け)
186
+
187
+ ```bash
188
+ npx phasegate scaffold-design --unit harness-api --phase logical --json
189
+ ```
190
+
191
+ exit code:
192
+
193
+ | 状況 | code |
194
+ |---|---|
195
+ | 生成成功 / 上書き成功 | 0 |
196
+ | 既存ファイルあり(--force なし) | 2 |
197
+ | 引数不正 / テンプレ不在 | 2 |
198
+
199
+ ---
200
+
201
+ ## baseline から外して phasegate 管理下に取り込む
202
+
203
+ Unit の設計文書が揃い、phasegate フル管理に昇格させたい場合の手順:
204
+
205
+ 1. `scaffold-design` で logical_design.md / domain_model.md を生成 → TODO を埋める
206
+ 2. 対象ファイルを `.phasegate/baseline.json` から削除(手動編集 or `--paths` で対象外にして再生成)
207
+ 3. 以降、構造変更のたびに phase-gate が走る通常の運用に移行
208
+
209
+ ---
210
+
211
+ ## よくある詰まり方
212
+
213
+ ### Q. `baseline` 作成後も gate が発火する
214
+
215
+ **確認**: `phasegate.config.json` の `baseline.enabled` が `true` か。
216
+ `baseline.path` と実ファイルの配置が一致しているか。
217
+
218
+ ### Q. scaffold した直後に L1 lint が失敗する
219
+
220
+ scaffold は markdown テンプレのみ生成する。**TS/JS ソースファイルは生成しない**。
221
+ ソースコードの雛形が必要な場合は `/story-implementor` スキルを使う。
222
+
223
+ ### Q. チームメイトの環境で baseline がズレる
224
+
225
+ `.phasegate/baseline.json` は commit する必要がある。`.gitignore` に
226
+ 入れていないか確認。
227
+
228
+ ### Q. 既存ファイルを少し触っただけで grandfather が外れた
229
+
230
+ sha1 一致で判定しているため、**フォーマット変更・インポート順序変更でも外れる**。
231
+ 意図的な編集であればそのまま設計文書を起こすフローに移る。自動フォーマッタが
232
+ 大量変更を起こす場合は、`baseline` を `--force` で取り直す運用も可。
233
+
234
+ ---
235
+
236
+ ## 関連
237
+
238
+ - `docs/guide/cli-reference.md` — `baseline` / `scaffold-design` のフラグ一覧
239
+ - `docs/guide/layer-model.md` — L0-L4 防御モデルと phase-gate の位置付け
240
+ - `docs/ADR/ADR-013-story-reflection-gate.md` — phase-gate の思想的背景
241
+ - ISSUE-007 — 本ガイドが対応する起票 issue(`docs/inception/issues/ISSUE-007/`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phasegate",
3
- "version": "0.68.0",
3
+ "version": "0.70.0",
4
4
  "packageManager": "pnpm@10.30.1",
5
5
  "description": "Phasegate — AI-agnostic quality defense toolkit. Enforces structural integrity between design intent and code.",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,8 @@
1
+ // @unit ci-governance
2
+ // @layer application
3
+
4
+ export interface ScaffoldDesignInput {
5
+ readonly unit: string;
6
+ readonly phase: string;
7
+ readonly force?: boolean;
8
+ }
@@ -0,0 +1,12 @@
1
+ // @unit ci-governance
2
+ // @layer application
3
+
4
+ export interface ScaffoldDesignOutput {
5
+ readonly targetPath: string;
6
+ readonly templatePath: string;
7
+ readonly unit: string;
8
+ readonly phase: string;
9
+ readonly written: boolean;
10
+ readonly alreadyExists: boolean;
11
+ readonly overwritten: boolean;
12
+ }
@@ -0,0 +1,56 @@
1
+ // @unit ci-governance
2
+ // @layer application
3
+
4
+ import { DesignPhase } from '../../domain/value-objects/design-phase.js';
5
+ import type { TemplateRepositoryPort } from '../../domain/ports/template-repository-port.js';
6
+ import type { DesignDocWriterPort } from '../../domain/ports/design-doc-writer-port.js';
7
+ import type { ScaffoldDesignInput } from '../dto/scaffold-design-input.js';
8
+ import type { ScaffoldDesignOutput } from '../dto/scaffold-design-output.js';
9
+
10
+ const UNIT_PLACEHOLDER = /\{\{\s*unit\s*\}\}/g;
11
+
12
+ export class ScaffoldDesignUseCase {
13
+ constructor(
14
+ private readonly templates: TemplateRepositoryPort,
15
+ private readonly writer: DesignDocWriterPort,
16
+ ) {}
17
+
18
+ async execute(input: ScaffoldDesignInput): Promise<ScaffoldDesignOutput> {
19
+ if (!input.unit || input.unit.trim().length === 0) {
20
+ throw new Error('--unit は必須です');
21
+ }
22
+ const phase = DesignPhase.create(input.phase);
23
+ const unit = input.unit.trim();
24
+ const force = input.force === true;
25
+
26
+ const templatePath = this.templates.resolvePath(phase);
27
+ const targetPath = this.writer.resolvePath(unit, phase);
28
+ const alreadyExists = await this.writer.exists(unit, phase);
29
+
30
+ if (alreadyExists && !force) {
31
+ return {
32
+ targetPath,
33
+ templatePath,
34
+ unit,
35
+ phase: phase.value,
36
+ written: false,
37
+ alreadyExists: true,
38
+ overwritten: false,
39
+ };
40
+ }
41
+
42
+ const raw = await this.templates.read(phase);
43
+ const rendered = raw.replace(UNIT_PLACEHOLDER, unit);
44
+ await this.writer.write(unit, phase, rendered);
45
+
46
+ return {
47
+ targetPath,
48
+ templatePath,
49
+ unit,
50
+ phase: phase.value,
51
+ written: true,
52
+ alreadyExists,
53
+ overwritten: alreadyExists && force,
54
+ };
55
+ }
56
+ }
@@ -40,11 +40,17 @@ import { GlobFileScannerAdapter } from './infrastructure/adapters/glob-file-scan
40
40
  import { FileSystemSha1HasherAdapter } from './infrastructure/adapters/file-system-sha1-hasher-adapter.js';
41
41
  import { BaselineJsonRepositoryAdapter } from './infrastructure/adapters/baseline-json-repository-adapter.js';
42
42
 
43
+ import { ScaffoldDesignUseCase } from './application/usecases/scaffold-design-usecase.js';
44
+ import { FileSystemTemplateRepositoryAdapter } from './infrastructure/adapters/file-system-template-repository-adapter.js';
45
+ import { FileSystemDesignDocWriterAdapter } from './infrastructure/adapters/file-system-design-doc-writer-adapter.js';
46
+ import { ScaffoldDesignHandler } from './presentation/handlers/scaffold-design-handler.js';
47
+
43
48
  export interface CiGovernanceCompositionRoot {
44
49
  generateCiTemplateHandler: GenerateCiTemplateHandler;
45
50
  migrateAgentsMdHandler: MigrateAgentsMdHandler;
46
51
  checkRepetitionHandler: CheckRepetitionHandler;
47
52
  createBaselineHandler: CreateBaselineHandler;
53
+ scaffoldDesignHandler: ScaffoldDesignHandler;
48
54
  // Use cases exposed for direct access
49
55
  recordErrorOccurrenceUseCase: RecordErrorOccurrenceUseCase;
50
56
  checkEscalationUseCase: CheckEscalationUseCase;
@@ -52,9 +58,13 @@ export interface CiGovernanceCompositionRoot {
52
58
  aggregateLessonsUseCase: AggregateLessonsUseCase;
53
59
  validatePointersUseCase: ValidatePointersUseCase;
54
60
  createBaselineUseCase: CreateBaselineUseCase;
61
+ scaffoldDesignUseCase: ScaffoldDesignUseCase;
55
62
  }
56
63
 
57
- export function buildCiGovernance(baseDir: string): CiGovernanceCompositionRoot {
64
+ export function buildCiGovernance(
65
+ baseDir: string,
66
+ harnessRoot: string = baseDir,
67
+ ): CiGovernanceCompositionRoot {
58
68
  // Infrastructure adapters
59
69
  const validatorIdRegistryAdapter = new ValidatorIdRegistryAdapter();
60
70
  const presetConfigAdapter = new PresetConfigAdapter();
@@ -98,6 +108,14 @@ export function buildCiGovernance(baseDir: string): CiGovernanceCompositionRoot
98
108
  baselineRepository,
99
109
  );
100
110
 
111
+ // Scaffold design adapters & use case (ISSUE-007 Wave 4)
112
+ const templateRepository = new FileSystemTemplateRepositoryAdapter(harnessRoot);
113
+ const designDocWriter = new FileSystemDesignDocWriterAdapter(baseDir);
114
+ const scaffoldDesignUseCase = new ScaffoldDesignUseCase(
115
+ templateRepository,
116
+ designDocWriter,
117
+ );
118
+
101
119
  // Handlers
102
120
  const generateCiTemplateHandler = new GenerateCiTemplateHandler(
103
121
  generateCiTemplateUseCase,
@@ -106,17 +124,20 @@ export function buildCiGovernance(baseDir: string): CiGovernanceCompositionRoot
106
124
  const migrateAgentsMdHandler = new MigrateAgentsMdHandler(migrateAgentsMdUseCase);
107
125
  const checkRepetitionHandler = new CheckRepetitionHandler(checkEscalationUseCase);
108
126
  const createBaselineHandler = new CreateBaselineHandler(createBaselineUseCase);
127
+ const scaffoldDesignHandler = new ScaffoldDesignHandler(scaffoldDesignUseCase);
109
128
 
110
129
  return {
111
130
  generateCiTemplateHandler,
112
131
  migrateAgentsMdHandler,
113
132
  checkRepetitionHandler,
114
133
  createBaselineHandler,
134
+ scaffoldDesignHandler,
115
135
  recordErrorOccurrenceUseCase,
116
136
  checkEscalationUseCase,
117
137
  resetRepetitionUseCase,
118
138
  aggregateLessonsUseCase,
119
139
  validatePointersUseCase,
120
140
  createBaselineUseCase,
141
+ scaffoldDesignUseCase,
121
142
  };
122
143
  }
@@ -0,0 +1,18 @@
1
+ // @unit ci-governance
2
+ // @layer domain
3
+
4
+ import type { DesignPhase } from '../value-objects/design-phase.js';
5
+
6
+ export interface DesignDocWriterPort {
7
+ /** 書き込み先の絶対パスを返す(副作用なし) */
8
+ resolvePath(unit: string, phase: DesignPhase): string;
9
+
10
+ /** 書き込み先が既に存在するか */
11
+ exists(unit: string, phase: DesignPhase): Promise<boolean>;
12
+
13
+ /**
14
+ * 設計文書を書き込む(親ディレクトリが無ければ作成)。
15
+ * 書き込んだ絶対パスを返す。
16
+ */
17
+ write(unit: string, phase: DesignPhase, content: string): Promise<string>;
18
+ }
@@ -0,0 +1,15 @@
1
+ // @unit ci-governance
2
+ // @layer domain
3
+
4
+ import type { DesignPhase } from '../value-objects/design-phase.js';
5
+
6
+ export interface TemplateRepositoryPort {
7
+ /**
8
+ * 指定した phase に対応するテンプレートファイルを読み込む。
9
+ * 存在しない場合は例外を投げる。
10
+ */
11
+ read(phase: DesignPhase): Promise<string>;
12
+
13
+ /** テンプレートの絶対パスを返す(UI 出力用) */
14
+ resolvePath(phase: DesignPhase): string;
15
+ }
@@ -0,0 +1,65 @@
1
+ // @unit ci-governance
2
+ // @layer domain
3
+
4
+ export const DESIGN_PHASES = [
5
+ 'logical',
6
+ 'domain',
7
+ 'uiux',
8
+ 'unit-test',
9
+ 'it-test',
10
+ ] as const;
11
+
12
+ export type DesignPhaseValue = (typeof DESIGN_PHASES)[number];
13
+
14
+ export class DesignPhase {
15
+ private constructor(readonly value: DesignPhaseValue) {}
16
+
17
+ static create(input: string): DesignPhase {
18
+ if (!DESIGN_PHASES.includes(input as DesignPhaseValue)) {
19
+ throw new Error(
20
+ `未知の設計 phase: "${input}"。許容値: ${DESIGN_PHASES.join(', ')}`,
21
+ );
22
+ }
23
+ return new DesignPhase(input as DesignPhaseValue);
24
+ }
25
+
26
+ static isValid(input: string): input is DesignPhaseValue {
27
+ return (DESIGN_PHASES as readonly string[]).includes(input);
28
+ }
29
+
30
+ equals(other: DesignPhase): boolean {
31
+ return this.value === other.value;
32
+ }
33
+
34
+ /** このフェーズに対応するテンプレートファイル名(`docs/templates/` 配下) */
35
+ get templateFileName(): string {
36
+ switch (this.value) {
37
+ case 'logical':
38
+ return 'logical_design.template.md';
39
+ case 'domain':
40
+ return 'domain_model.template.md';
41
+ case 'uiux':
42
+ return 'uiux_design.template.md';
43
+ case 'unit-test':
44
+ return 'unit_test_design.template.md';
45
+ case 'it-test':
46
+ return 'it_test_design.template.md';
47
+ }
48
+ }
49
+
50
+ /** このフェーズで書き込む設計文書のファイル名(`docs/product/construction/{unit}/` 配下) */
51
+ get designDocFileName(): string {
52
+ switch (this.value) {
53
+ case 'logical':
54
+ return 'logical_design.md';
55
+ case 'domain':
56
+ return 'domain_model.md';
57
+ case 'uiux':
58
+ return 'uiux_design.md';
59
+ case 'unit-test':
60
+ return 'unit_test_design.md';
61
+ case 'it-test':
62
+ return 'it_test_design.md';
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,42 @@
1
+ // @unit ci-governance
2
+ // @layer infrastructure
3
+
4
+ import * as fs from 'node:fs/promises';
5
+ import * as path from 'node:path';
6
+ import type { DesignDocWriterPort } from '../../domain/ports/design-doc-writer-port.js';
7
+ import type { DesignPhase } from '../../domain/value-objects/design-phase.js';
8
+
9
+ export class FileSystemDesignDocWriterAdapter implements DesignDocWriterPort {
10
+ private readonly baseDir: string;
11
+ private readonly constructionDir: string;
12
+
13
+ constructor(
14
+ baseDir: string,
15
+ constructionSubDir: string = path.join('docs', 'product', 'construction'),
16
+ ) {
17
+ this.baseDir = baseDir;
18
+ this.constructionDir = path.isAbsolute(constructionSubDir)
19
+ ? constructionSubDir
20
+ : path.join(baseDir, constructionSubDir);
21
+ }
22
+
23
+ resolvePath(unit: string, phase: DesignPhase): string {
24
+ return path.join(this.constructionDir, unit, phase.designDocFileName);
25
+ }
26
+
27
+ async exists(unit: string, phase: DesignPhase): Promise<boolean> {
28
+ try {
29
+ await fs.access(this.resolvePath(unit, phase));
30
+ return true;
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
35
+
36
+ async write(unit: string, phase: DesignPhase, content: string): Promise<string> {
37
+ const targetPath = this.resolvePath(unit, phase);
38
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
39
+ await fs.writeFile(targetPath, content, 'utf-8');
40
+ return targetPath;
41
+ }
42
+ }
@@ -0,0 +1,35 @@
1
+ // @unit ci-governance
2
+ // @layer infrastructure
3
+
4
+ import * as fs from 'node:fs/promises';
5
+ import * as path from 'node:path';
6
+ import type { TemplateRepositoryPort } from '../../domain/ports/template-repository-port.js';
7
+ import type { DesignPhase } from '../../domain/value-objects/design-phase.js';
8
+
9
+ export class FileSystemTemplateRepositoryAdapter implements TemplateRepositoryPort {
10
+ private readonly templatesDir: string;
11
+
12
+ constructor(harnessRoot: string, subDir: string = 'templates') {
13
+ this.templatesDir = path.isAbsolute(subDir)
14
+ ? subDir
15
+ : path.join(harnessRoot, subDir);
16
+ }
17
+
18
+ resolvePath(phase: DesignPhase): string {
19
+ return path.join(this.templatesDir, phase.templateFileName);
20
+ }
21
+
22
+ async read(phase: DesignPhase): Promise<string> {
23
+ const filePath = this.resolvePath(phase);
24
+ try {
25
+ return await fs.readFile(filePath, 'utf-8');
26
+ } catch (err) {
27
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
28
+ throw new Error(
29
+ `テンプレートが見つかりません: ${filePath} (phase=${phase.value})`,
30
+ );
31
+ }
32
+ throw err;
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,97 @@
1
+ // @unit ci-governance
2
+ // @layer presentation
3
+
4
+ import { DesignPhase } from '../../domain/value-objects/design-phase.js';
5
+ import type { ScaffoldDesignUseCase } from '../../application/usecases/scaffold-design-usecase.js';
6
+
7
+ export interface ScaffoldDesignHandlerArgs {
8
+ readonly unit?: string;
9
+ readonly phase?: string;
10
+ readonly force?: boolean;
11
+ readonly format?: 'human' | 'json';
12
+ }
13
+
14
+ export interface ScaffoldDesignHandlerResult {
15
+ readonly exitCode: number;
16
+ readonly output: string;
17
+ }
18
+
19
+ export class ScaffoldDesignHandler {
20
+ constructor(private readonly useCase: ScaffoldDesignUseCase) {}
21
+
22
+ async handle(args: ScaffoldDesignHandlerArgs): Promise<ScaffoldDesignHandlerResult> {
23
+ const format = args.format ?? 'human';
24
+
25
+ if (!args.unit || args.unit.trim().length === 0) {
26
+ return this.fail(format, '--unit <unit-id> は必須です', 2);
27
+ }
28
+ if (!args.phase || args.phase.trim().length === 0) {
29
+ return this.fail(
30
+ format,
31
+ `--phase <name> は必須です(許容値: logical, domain, uiux, unit-test, it-test)`,
32
+ 2,
33
+ );
34
+ }
35
+ if (!DesignPhase.isValid(args.phase)) {
36
+ return this.fail(
37
+ format,
38
+ `未知の phase: "${args.phase}"(許容値: logical, domain, uiux, unit-test, it-test)`,
39
+ 2,
40
+ );
41
+ }
42
+
43
+ let result;
44
+ try {
45
+ result = await this.useCase.execute({
46
+ unit: args.unit,
47
+ phase: args.phase,
48
+ force: args.force,
49
+ });
50
+ } catch (err) {
51
+ const msg = err instanceof Error ? err.message : String(err);
52
+ return this.fail(format, `scaffold 失敗: ${msg}`, 2);
53
+ }
54
+
55
+ if (format === 'json') {
56
+ return {
57
+ exitCode: result.alreadyExists && !result.written ? 2 : 0,
58
+ output: JSON.stringify(result, null, 2),
59
+ };
60
+ }
61
+
62
+ if (result.alreadyExists && !result.written) {
63
+ return {
64
+ exitCode: 2,
65
+ output: [
66
+ `既に存在します: ${result.targetPath}`,
67
+ '上書きするには --force を指定してください。',
68
+ ].join('\n'),
69
+ };
70
+ }
71
+
72
+ const headerVerb = result.overwritten ? '上書き保存しました' : '生成しました';
73
+ return {
74
+ exitCode: 0,
75
+ output: [
76
+ `設計文書を${headerVerb}: ${result.targetPath}`,
77
+ `テンプレ: ${result.templatePath}`,
78
+ `Unit: ${result.unit} / phase: ${result.phase}`,
79
+ 'TODO プレースホルダを実体で埋めてください。',
80
+ ].join('\n'),
81
+ };
82
+ }
83
+
84
+ private fail(
85
+ format: 'human' | 'json',
86
+ message: string,
87
+ exitCode: number,
88
+ ): ScaffoldDesignHandlerResult {
89
+ if (format === 'json') {
90
+ return {
91
+ exitCode,
92
+ output: JSON.stringify({ error: message }, null, 2),
93
+ };
94
+ }
95
+ return { exitCode, output: message };
96
+ }
97
+ }
@@ -44,7 +44,7 @@ export const L2_ERROR_DEFINITIONS = Object.freeze([
44
44
  "const requiredPlanPath = 'docs/inception/harness-error/it_test_logic_plan.md';",
45
45
  defaultSuggestedSkill: '/story-implementor',
46
46
  defaultScaffoldCommand: 'npx phasegate scaffold-design --unit <unit-id> --phase logical',
47
- defaultTemplatePath: 'docs/templates/logical_design.template.md',
47
+ defaultTemplatePath: 'templates/logical_design.template.md',
48
48
  }),
49
49
  createDefinition({
50
50
  code: 'L2-002',
@@ -89,6 +89,7 @@ Commands:
89
89
  ci:migrate-agents-md Migrate AGENTS.md (--dry-run, --validate-only, --json)
90
90
  ci:check-repetition Check error repetition (--code <errorCode>, --reset, --json)
91
91
  baseline Create retrofit baseline snapshot (--dry-run, --force, --paths <glob,glob,...>, --json)
92
+ scaffold-design Scaffold a design doc (--unit <id>, --phase <logical|domain|uiux|unit-test|it-test>, --force, --json)
92
93
 
93
94
  skill:execute-tdd-cycle Execute TDD cycle (--unit, --story, --desc, --phase RED|GREEN|REFACTOR, --passed)
94
95
  skill:check-coverage Check coverage (--story <storyId>, --json)
@@ -917,6 +918,23 @@ Examples:
917
918
  break;
918
919
  }
919
920
 
921
+ case 'scaffold-design': {
922
+ const mod = buildCiGovernance(rootDir, harnessRoot);
923
+ const unit = parseFlag(args, '--unit') ?? '';
924
+ const phase = parseFlag(args, '--phase') ?? '';
925
+ const force = hasFlag(args, '--force');
926
+ const format = json ? 'json' : 'human';
927
+ const result = await mod.scaffoldDesignHandler.handle({
928
+ unit,
929
+ phase,
930
+ force,
931
+ format,
932
+ });
933
+ console.log(result.output);
934
+ process.exit(result.exitCode);
935
+ break;
936
+ }
937
+
920
938
  // ── skill-quality ──
921
939
  case 'skill:execute-tdd-cycle': {
922
940
  const mod = createSkillQualityHandlers();
@@ -0,0 +1,51 @@
1
+ ---
2
+ traceability:
3
+ initial_creation: true
4
+ ---
5
+
6
+ # ドメインモデル: {{unit}}
7
+
8
+ > **対応ストーリー**: <HXX-XX, HYY-YY>
9
+ > **作成日**: <YYYY-MM-DD>
10
+ > **Unit**: {{unit}}
11
+
12
+ ---
13
+
14
+ ## 集約 / エンティティ / 値オブジェクト
15
+
16
+ @story-id <HXX-XX>
17
+ ### <集約名>
18
+
19
+ **責務**: TODO: この集約が持つ責務
20
+
21
+ **不変条件**:
22
+ - TODO: 不変条件 1
23
+ - TODO: 不変条件 2
24
+
25
+ **関連**:
26
+ - TODO: 他集約・エンティティへの参照
27
+
28
+ ---
29
+
30
+ ## ドメインサービス
31
+
32
+ @story-id <HXX-XX>
33
+ ### <ドメインサービス名>
34
+
35
+ **責務**: TODO: このサービスが担う domain ロジック
36
+
37
+ **入出力**:
38
+ - 入力: TODO
39
+ - 出力: TODO
40
+
41
+ ---
42
+
43
+ ## ポート(依存反転インタフェース)
44
+
45
+ @story-id <HXX-XX>
46
+ ### <Port 名>
47
+
48
+ **役割**: TODO: domain が infrastructure に求める契約
49
+
50
+ **メソッド**:
51
+ - `methodName(arg: Type): ReturnType` — TODO
@@ -0,0 +1,38 @@
1
+ ---
2
+ traceability:
3
+ initial_creation: true
4
+ ---
5
+
6
+ # IT(Integration)テスト設計: {{unit}}
7
+
8
+ > **対応ストーリー**: <HXX-XX, HYY-YY>
9
+ > **作成日**: <YYYY-MM-DD>
10
+ > **Unit**: {{unit}}
11
+
12
+ ---
13
+
14
+ ## 結合スコープ
15
+
16
+ - TODO: 結合対象(UseCase + Repository、Handler + UseCase など)
17
+ - TODO: 外部依存(DB / API / FileSystem)の扱い
18
+
19
+ ---
20
+
21
+ ## テストケース一覧
22
+
23
+ @story-id <HXX-XX>
24
+ ### IT-{{unit}}-001: <ケース名>
25
+
26
+ **対象**: TODO: 結合対象
27
+ **Arrange**: TODO: テンポラリ環境/フィクスチャ
28
+ **Act**: TODO: 実行する操作
29
+ **Assert**: TODO: 検証内容
30
+ **副作用検証**: TODO: 書き込み/ログ等の副作用確認
31
+
32
+ ---
33
+
34
+ ## テスト環境
35
+
36
+ - テンポラリディレクトリ: `fs.mkdtemp` ベース
37
+ - ネットワーク: 禁止(外部 API は fake/stub)
38
+ - クリーンアップ: afterEach で確実に破棄
@@ -3,17 +3,17 @@ traceability:
3
3
  initial_creation: true
4
4
  ---
5
5
 
6
- # 論理設計: <Unit名>
6
+ # 論理設計: {{unit}}
7
7
 
8
8
  > **対応ストーリー**: <HXX-XX, HYY-YY>
9
9
  > **作成日**: <YYYY-MM-DD>
10
- > **Unit**: <UNIT_NAME>
10
+ > **Unit**: {{unit}}
11
11
 
12
12
  ---
13
13
 
14
14
  ## 概要
15
15
 
16
- <このUnitが解決するビジネス課題を 2〜3 行で記述>
16
+ TODO: Unit `{{unit}}` が解決するビジネス課題を 2〜3 行で記述
17
17
 
18
18
  ---
19
19
 
@@ -22,7 +22,7 @@ traceability:
22
22
  @story-id <HXX-XX>
23
23
  ### <集約 / エンティティ / 値オブジェクト名>
24
24
 
25
- <不変条件・責務・関連の説明>
25
+ TODO: 不変条件・責務・関連の説明
26
26
 
27
27
  ---
28
28
 
@@ -36,13 +36,13 @@ traceability:
36
36
  **So that** <得られる価値>
37
37
 
38
38
  #### 事前条件
39
- - <前提>
39
+ - TODO: 前提
40
40
 
41
41
  #### 基本フロー
42
- 1. <ステップ>
42
+ 1. TODO: ステップ
43
43
 
44
44
  #### 例外フロー
45
- - <エラーケース>
45
+ - TODO: エラーケース
46
46
 
47
47
  ---
48
48
 
@@ -74,6 +74,3 @@ presentation/ : CLI Handler / Controller
74
74
  - 直後に設計要素(空行を挟まない)
75
75
  - `HXX-XX` は `docs/product/user_stories.md` に存在する ID
76
76
  - 複数ストーリー時は連続並列で並べ、最後の直後に設計要素
77
-
78
- これらは `MetadataValidator.validateDesignDocument` で検証され、
79
- ISSUE-008 Phase B-2 / B-3 以降は `npx phasegate validate-metadata` / pre-commit で自動チェックされる。
@@ -0,0 +1,45 @@
1
+ ---
2
+ traceability:
3
+ initial_creation: true
4
+ ---
5
+
6
+ # UI/UX 設計: {{unit}}
7
+
8
+ > **対応ストーリー**: <HXX-XX, HYY-YY>
9
+ > **作成日**: <YYYY-MM-DD>
10
+ > **Unit**: {{unit}}
11
+
12
+ ---
13
+
14
+ ## ユーザーフロー
15
+
16
+ @story-id <HXX-XX>
17
+ ### <フロー名>
18
+
19
+ 1. TODO: ユーザー操作 1
20
+ 2. TODO: システム応答
21
+ 3. TODO: 画面遷移
22
+
23
+ ---
24
+
25
+ ## 画面構成
26
+
27
+ @story-id <HXX-XX>
28
+ ### <画面名>
29
+
30
+ **役割**: TODO: この画面が提供する価値
31
+
32
+ **主要コンポーネント**:
33
+ - TODO: コンポーネント 1
34
+ - TODO: コンポーネント 2
35
+
36
+ **状態**:
37
+ - loading / success / error / empty
38
+
39
+ ---
40
+
41
+ ## アクセシビリティ
42
+
43
+ - TODO: キーボード操作
44
+ - TODO: スクリーンリーダ対応
45
+ - TODO: カラーコントラスト
@@ -0,0 +1,39 @@
1
+ ---
2
+ traceability:
3
+ initial_creation: true
4
+ ---
5
+
6
+ # Unit テスト設計: {{unit}}
7
+
8
+ > **対応ストーリー**: <HXX-XX, HYY-YY>
9
+ > **作成日**: <YYYY-MM-DD>
10
+ > **Unit**: {{unit}}
11
+
12
+ ---
13
+
14
+ ## テストケース一覧
15
+
16
+ @story-id <HXX-XX>
17
+ ### UT-{{unit}}-001: <ケース名>
18
+
19
+ **対象**: TODO: target クラス/関数
20
+ **Arrange**: TODO: 前提条件セットアップ
21
+ **Act**: TODO: 実行する操作
22
+ **Assert**: TODO: 検証内容
23
+ **期待結果**: TODO: 期待値
24
+
25
+ ---
26
+
27
+ ## カバレッジ方針
28
+
29
+ - 分岐カバレッジ 90% 以上
30
+ - ドメイン層のモック禁止
31
+ - 値オブジェクトの不変条件は個別にテスト
32
+
33
+ ---
34
+
35
+ ## テスト命名規約
36
+
37
+ - ケース名: 日本語で記述
38
+ - ファイル名: kebab-case(例: `user-entity.test.ts`)
39
+ - AAA パターン準拠