phasegate 0.68.0 → 0.69.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 +223 -1
- package/README.ja.md +2 -2
- package/docs/guide/quick-vs-full-mode.md +32 -1
- package/package.json +1 -1
- package/scripts/harness/ci-governance/application/dto/scaffold-design-input.ts +8 -0
- package/scripts/harness/ci-governance/application/dto/scaffold-design-output.ts +12 -0
- package/scripts/harness/ci-governance/application/usecases/scaffold-design-usecase.ts +56 -0
- package/scripts/harness/ci-governance/composition-root.ts +22 -1
- package/scripts/harness/ci-governance/domain/ports/design-doc-writer-port.ts +18 -0
- package/scripts/harness/ci-governance/domain/ports/template-repository-port.ts +15 -0
- package/scripts/harness/ci-governance/domain/value-objects/design-phase.ts +65 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/file-system-design-doc-writer-adapter.ts +42 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/file-system-template-repository-adapter.ts +35 -0
- package/scripts/harness/ci-governance/presentation/handlers/scaffold-design-handler.ts +97 -0
- package/scripts/harness/harness-error/infrastructure/registry/l2-error-definitions.ts +1 -1
- package/scripts/harness/main.ts +18 -0
- package/templates/domain_model.template.md +51 -0
- package/templates/it_test_design.template.md +38 -0
- package/templates/logical_design.template.md +7 -10
- package/templates/uiux_design.template.md +45 -0
- package/templates/unit_test_design.template.md +39 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,199 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.69.0] - 2026-04-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- 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:` 行が実動作するようになった。
|
|
15
|
+
- `templates/{domain_model,uiux_design,unit_test_design,it_test_design}.template.md` を追加(5 phase すべてに minimum viable template)。
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Wave 3 の L2-001 `defaultTemplatePath` を `docs/templates/logical_design.template.md` → `templates/logical_design.template.md` に修正(配布物と整合)。
|
|
20
|
+
|
|
21
|
+
## [0.68.0] - 2026-04-22
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- `skills/` 同梱物のクリーンアップ — skill-creator の `scripts/__pycache__/` Python バイトコンパイルキャッシュが npm 配布物に混入していたため除去。`.gitignore` / `.npmignore` に `__pycache__/` と `*.pyc` を追加。skill-creator の使用例パスを Anthropic 原本の `skills/public` / `skills/private` から PhaseGate レイアウトに合わせた `skills` に統一。
|
|
26
|
+
|
|
27
|
+
## [0.67.0] - 2026-04-22
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- ISSUE-007 Wave 3 / Phase B — `phase-gate` の HarnessError をアクショナブル化(足りない設計文書のパスと推奨アクションを `fix_example` に明示)。
|
|
32
|
+
|
|
33
|
+
## [0.66.0] - 2026-04-22
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- ISSUE-007 Wave 2 / Phase A-2 — `.phasegate/baseline.json` に登録済みかつ sha1 が一致するファイルを `phase-gate` 対象から除外する **baseline grandfather** を pre-tool-use hook に統合。レガシーリポジトリへの後付け導入時の摩擦を解消する。
|
|
38
|
+
|
|
39
|
+
## [0.65.0] - 2026-04-21
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- 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}` スキーマを追加。
|
|
44
|
+
|
|
45
|
+
## [0.64.0] - 2026-04-21
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- ISSUE-006 Story B — `quickMode.fullModeRequiredWhen` の判定を pre-tool-use hook に統合。`mixedCategories` / `newDomainFile` / `apiContractChange` のいずれかが立つと書き込み時点で同期的に Full Mode へエスカレートしブロックする(block reason: `FULL_MODE_REQUIRED`)。
|
|
50
|
+
|
|
51
|
+
## [0.63.0] - 2026-04-21
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- ISSUE-006 Story A — `quickMode.fullModeRequiredWhen` 設定キー(`mixedCategories` / `newDomainFile` / `apiContractChange`、いずれもデフォルト `true`)を導入し、Quick Mode → Full Mode のエスカレート条件を設定駆動化。
|
|
56
|
+
- `npx phasegate check-change-category --paths <csv> [--format json] [--fail-on-full-required]` CLI — 任意のファイルリストを Quick Mode カテゴリに分類し、Full Mode が必要かを返す。CI gate での使用を想定。
|
|
57
|
+
|
|
58
|
+
## [0.62.0] - 2026-04-21
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
|
|
62
|
+
- ISSUE-013 C-6(軽量版)— UserPromptSubmit hook に violation detection を追加。
|
|
63
|
+
|
|
64
|
+
## [0.61.0] - 2026-04-21
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- ISSUE-013 C-5 — UserPromptSubmit hook で動的状態(現在の Quick/Full モード等)をプロンプトに注入。
|
|
69
|
+
|
|
70
|
+
## [0.60.0] - 2026-04-21
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- ISSUE-013 C-4 — SessionStart hook を追加し、セッション開始時に静的ルール(CLAUDE.md 等)を注入する仕組みを実装。
|
|
75
|
+
|
|
76
|
+
## [0.59.0] - 2026-04-21
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- ISSUE-013 A-1 / A-2 / B-3 — `phasegate init --agent <claude|codex|both>` オプションで Codex CLI 向けの `.codex/hooks.json` を自動配置。Codex dogfood セットアップを README に追記。
|
|
81
|
+
|
|
82
|
+
## [0.58.0] - 2026-04-21
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- ISSUE-013 Wave 2 — Codex CLI 統合の本体実装。`PreToolUse(Bash)` / `PostToolUse(Bash)` / `Stop` フックを Codex 向けに配線。
|
|
87
|
+
|
|
88
|
+
## [0.57.0] - 2026-04-20
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- ISSUE-013 Wave 1 — `BashWriteTargetExtractor` が Bash 経由 `apply_patch <<'PATCH'` heredoc の書き込み先パスを抽出するよう拡張。Codex の Bash ルートを pre-tool-use hook で押さえられるようになる。
|
|
93
|
+
|
|
94
|
+
## [0.56.0] - 2026-04-20
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
|
|
98
|
+
- ISSUE-011 Wave 3 / P3-4 / HF2-04 — `initial-creation-expiration-checker` バリデータを修正。
|
|
99
|
+
|
|
100
|
+
## [0.55.0] - 2026-04-20
|
|
101
|
+
|
|
102
|
+
### Fixed
|
|
103
|
+
|
|
104
|
+
- ISSUE-011 Wave 2 — Markdown parser の code-span / code-fence 内に書かれた `@unit` / `@layer` 等のメタタグを誤検出していたバグを修正(コードフェンス内をスキップするよう変更)。
|
|
105
|
+
|
|
106
|
+
## [0.54.0] - 2026-04-20
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- ISSUE-011 Wave 1 / P2-2 — CLI のエラー伝播を修正(内部エラーが exit code 0 で握り潰されていた問題)。
|
|
111
|
+
- ISSUE-011 Wave 1 / P2-3 — `.mdx` / `.markdown` 拡張子を Markdown ドキュメント検証の対象に追加。
|
|
112
|
+
|
|
113
|
+
## [0.53.0] - 2026-04-19
|
|
114
|
+
|
|
115
|
+
### Added
|
|
116
|
+
|
|
117
|
+
- ISSUE-008 Phase C-1〜C-3 + D — テストファイルへの `@story` メタデータ end-to-end 検証を完成。`templates/` 配下のサンプルファイルを実体化し、生成コードへのメタデータ付与を保証する経路を確立。
|
|
118
|
+
|
|
119
|
+
## [0.52.0] - 2026-04-19
|
|
120
|
+
|
|
121
|
+
### Changed
|
|
122
|
+
|
|
123
|
+
- ISSUE-008 Phase B-3 — pre-commit フローに `.md` 設計文書の検証を接続。`logical_design.md` 等の frontmatter / メタデータが欠けたままコミットされるのを防ぐ。
|
|
124
|
+
|
|
125
|
+
## [0.51.0] - 2026-04-19
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
|
|
129
|
+
- ISSUE-011 起票(`validate-metadata` UX / parser / drift 検出に関する改善集)。
|
|
130
|
+
|
|
131
|
+
## [0.50.0] - 2026-04-19
|
|
132
|
+
|
|
133
|
+
### Added
|
|
134
|
+
|
|
135
|
+
- ISSUE-008 Phase B-2 — `validate-metadata` CLI に `.md` 分岐を追加。Markdown 設計文書のメタデータ(frontmatter)も検証対象になる。
|
|
136
|
+
|
|
137
|
+
## [0.49.0] - 2026-04-19
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- ISSUE-008 Phase B-1 撤回 + P1-2 前提更新 — 設計文書 frontmatter 必須化(v0.48.0)の方針を再検討し前提を更新。
|
|
142
|
+
|
|
143
|
+
## [0.48.0] - 2026-04-19
|
|
144
|
+
|
|
145
|
+
### Added
|
|
146
|
+
|
|
147
|
+
- ISSUE-008 Phase B-1 / P1-2 — 設計文書(`logical_design.md` / `domain_model.md` 等)の frontmatter を必須化。
|
|
148
|
+
|
|
149
|
+
## [0.47.0] - 2026-04-18
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
|
|
153
|
+
- ISSUE-008 Phase A / P1-1 — 生成コードに `@unit` / `@layer` メタデータを必ず付与するよう、各実装スキル(`story-implementor` / `quick-implementor`)に指示を追加。
|
|
154
|
+
|
|
155
|
+
## [0.46.0] - 2026-04-18
|
|
156
|
+
|
|
157
|
+
### Added
|
|
158
|
+
|
|
159
|
+
- ISSUE-007 起票(リトロフィット導入障壁 — レガシーリポジトリでの初回 phase-gate ブロック問題)。
|
|
160
|
+
- ISSUE-008 起票(メタデータ emit 欠落 — 生成コードに `@unit` / `@layer` が付かないケース)。
|
|
161
|
+
|
|
162
|
+
## [0.45.0] - 2026-04-18
|
|
163
|
+
|
|
164
|
+
### Added
|
|
165
|
+
|
|
166
|
+
- ISSUE-006 起票 + Phase P2-3 — `docs/guide/quick-vs-full-mode.md`(Quick Mode と Full Mode の選択ガイド)を新設。
|
|
167
|
+
|
|
168
|
+
## [0.44.0] - 2026-04-18
|
|
169
|
+
|
|
170
|
+
### Fixed
|
|
171
|
+
|
|
172
|
+
- ISSUE-005 Phase D / P3-8 — Markdown のメタ見出し(`---` で囲まれた frontmatter 等)をパース時に正しくスキップするよう修正。
|
|
173
|
+
- ISSUE-005 Phase D / P3-9 — ファイルパスから `@unit` を推定するロジックを改善。
|
|
174
|
+
- ISSUE-005 Phase D / P3-10 — `list-errors` と `render-errors` の境界をドキュメント化(`list-errors` は定義駆動 / `render-errors` はランタイム駆動)。
|
|
175
|
+
|
|
176
|
+
## [0.43.0] - 2026-04-18
|
|
177
|
+
|
|
178
|
+
### Fixed
|
|
179
|
+
|
|
180
|
+
- ISSUE-005 Phase C / P2-6 — `phasegate:check-phase` の `--help` / `--json` フラグが positional 引数として食われ unit 名扱いされていたバグを修正。
|
|
181
|
+
- ISSUE-005 Phase C / P2-7 — `regression:*` 系コマンドの出力先を整理。
|
|
182
|
+
|
|
183
|
+
## [0.42.0] - 2026-04-18
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- ISSUE-005 Phase B-2 / P1-5 — `detect-drift` と L4-001 バリデータを統合し、設計-コード乖離検出の経路を一本化。
|
|
188
|
+
|
|
189
|
+
## [0.41.0] - 2026-04-18
|
|
190
|
+
|
|
191
|
+
### Fixed
|
|
192
|
+
|
|
193
|
+
- ISSUE-005 Phase B-1 / P1-3 — fresh repo(履歴がない初期化直後のリポジトリ)での git 解析が失敗するバグを fallback 経路で修正。
|
|
194
|
+
- ISSUE-005 Phase B-1 / P1-4 — `validate --layer` フィルタが効かないケースを修正。
|
|
195
|
+
|
|
196
|
+
## [0.40.0] - 2026-04-18
|
|
197
|
+
|
|
198
|
+
### Fixed
|
|
199
|
+
|
|
200
|
+
- ISSUE-005 Phase A / P0-1 — pre-commit 経路の復旧(一部バリデータが pre-commit から呼ばれていなかった問題)。
|
|
201
|
+
- ISSUE-005 Phase A / P0-2 — `ci:generate-template` の UX 改善(`--preset` 省略時のエラーメッセージを実用的に)。
|
|
202
|
+
|
|
10
203
|
## [0.39.0] - 2026-04-18
|
|
11
204
|
|
|
12
205
|
### Fixed
|
|
@@ -176,7 +369,36 @@ Pre-reset era (formerly v1.0.0 - v1.1.1). Initial release and early bug fixes:
|
|
|
176
369
|
- ajv v8互換対応
|
|
177
370
|
- 3件のバグ修正
|
|
178
371
|
|
|
179
|
-
[Unreleased]: https://github.com/junpei-9898/phasegate/compare/v0.
|
|
372
|
+
[Unreleased]: https://github.com/junpei-9898/phasegate/compare/v0.67.0...HEAD
|
|
373
|
+
[0.67.0]: https://github.com/junpei-9898/phasegate/compare/v0.66.0...v0.67.0
|
|
374
|
+
[0.66.0]: https://github.com/junpei-9898/phasegate/compare/v0.65.0...v0.66.0
|
|
375
|
+
[0.65.0]: https://github.com/junpei-9898/phasegate/compare/v0.64.0...v0.65.0
|
|
376
|
+
[0.64.0]: https://github.com/junpei-9898/phasegate/compare/v0.63.0...v0.64.0
|
|
377
|
+
[0.63.0]: https://github.com/junpei-9898/phasegate/compare/v0.62.0...v0.63.0
|
|
378
|
+
[0.62.0]: https://github.com/junpei-9898/phasegate/compare/v0.61.0...v0.62.0
|
|
379
|
+
[0.61.0]: https://github.com/junpei-9898/phasegate/compare/v0.60.0...v0.61.0
|
|
380
|
+
[0.60.0]: https://github.com/junpei-9898/phasegate/compare/v0.59.0...v0.60.0
|
|
381
|
+
[0.59.0]: https://github.com/junpei-9898/phasegate/compare/v0.58.0...v0.59.0
|
|
382
|
+
[0.58.0]: https://github.com/junpei-9898/phasegate/compare/v0.57.0...v0.58.0
|
|
383
|
+
[0.57.0]: https://github.com/junpei-9898/phasegate/compare/v0.56.0...v0.57.0
|
|
384
|
+
[0.56.0]: https://github.com/junpei-9898/phasegate/compare/v0.55.0...v0.56.0
|
|
385
|
+
[0.55.0]: https://github.com/junpei-9898/phasegate/compare/v0.54.0...v0.55.0
|
|
386
|
+
[0.54.0]: https://github.com/junpei-9898/phasegate/compare/v0.53.0...v0.54.0
|
|
387
|
+
[0.53.0]: https://github.com/junpei-9898/phasegate/compare/v0.52.0...v0.53.0
|
|
388
|
+
[0.52.0]: https://github.com/junpei-9898/phasegate/compare/v0.51.0...v0.52.0
|
|
389
|
+
[0.51.0]: https://github.com/junpei-9898/phasegate/compare/v0.50.0...v0.51.0
|
|
390
|
+
[0.50.0]: https://github.com/junpei-9898/phasegate/compare/v0.49.0...v0.50.0
|
|
391
|
+
[0.49.0]: https://github.com/junpei-9898/phasegate/compare/v0.48.0...v0.49.0
|
|
392
|
+
[0.48.0]: https://github.com/junpei-9898/phasegate/compare/v0.47.0...v0.48.0
|
|
393
|
+
[0.47.0]: https://github.com/junpei-9898/phasegate/compare/v0.46.0...v0.47.0
|
|
394
|
+
[0.46.0]: https://github.com/junpei-9898/phasegate/compare/v0.45.0...v0.46.0
|
|
395
|
+
[0.45.0]: https://github.com/junpei-9898/phasegate/compare/v0.44.0...v0.45.0
|
|
396
|
+
[0.44.0]: https://github.com/junpei-9898/phasegate/compare/v0.43.0...v0.44.0
|
|
397
|
+
[0.43.0]: https://github.com/junpei-9898/phasegate/compare/v0.42.0...v0.43.0
|
|
398
|
+
[0.42.0]: https://github.com/junpei-9898/phasegate/compare/v0.41.0...v0.42.0
|
|
399
|
+
[0.41.0]: https://github.com/junpei-9898/phasegate/compare/v0.40.0...v0.41.0
|
|
400
|
+
[0.40.0]: https://github.com/junpei-9898/phasegate/compare/v0.39.0...v0.40.0
|
|
401
|
+
[0.39.0]: https://github.com/junpei-9898/phasegate/compare/v0.38.0...v0.39.0
|
|
180
402
|
[0.38.0]: https://github.com/junpei-9898/phasegate/compare/v0.37.0...v0.38.0
|
|
181
403
|
[0.37.0]: https://github.com/junpei-9898/phasegate/compare/v0.36.0...v0.37.0
|
|
182
404
|
[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-
|
|
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.
|
package/package.json
CHANGED
|
@@ -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(
|
|
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: '
|
|
47
|
+
defaultTemplatePath: 'templates/logical_design.template.md',
|
|
48
48
|
}),
|
|
49
49
|
createDefinition({
|
|
50
50
|
code: 'L2-002',
|
package/scripts/harness/main.ts
CHANGED
|
@@ -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
|
-
# 論理設計:
|
|
6
|
+
# 論理設計: {{unit}}
|
|
7
7
|
|
|
8
8
|
> **対応ストーリー**: <HXX-XX, HYY-YY>
|
|
9
9
|
> **作成日**: <YYYY-MM-DD>
|
|
10
|
-
> **Unit**:
|
|
10
|
+
> **Unit**: {{unit}}
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
## 概要
|
|
15
15
|
|
|
16
|
-
|
|
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 パターン準拠
|