phasegate 0.111.0 → 0.114.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,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.114.0] - 2026-05-07
11
+
12
+ ### Security
13
+
14
+ - **WI-035: phase2-extensions の git-log adapter におけるコマンドインジェクション脆弱性 (HIGH) を修正** — `/security-review` で発見。`execSync` テンプレート文字列に `documentPath` / `filePath` をダブルクオート展開していたため、ファイル名に `$()` / バッククオート / `;` 等のシェルメタ文字を含めると `/bin/sh -c` 経由で任意コードが実行される経路があった(攻撃者は POSIX 許容範囲のファイル名を含む公開リポジトリを 1 つ用意するだけで成立。clone / `gh pr checkout` でローカルに展開された時点で発火し、マージは不要)。
15
+ - `scripts/harness/phase2-extensions/infrastructure/adapters/git-log-document-age-adapter.ts` の `gitLogExecutor` を `execFileSync` 配列引数形式(`('git', ['log', '--format=%ai', '-1', '--', documentPath], ...)`)に置換。
16
+ - `scripts/harness/phase2-extensions/infrastructure/adapters/git-log-initial-creation-age-adapter.ts` の `gitExecutor` を同形式に置換(`runGit(args)` の signature も合わせて変更)。
17
+ - DI ポートの signature を `(command: string) => Buffer` から `(file: string, args: readonly string[], options) => Buffer` に変更。
18
+ - 悪意あるファイル名(`$()` / バッククオート / `;` / `"` / `|` 含む)でも引数が **配列要素のまま** 渡され、シェルメタ文字として評価されないことを assert する unit test を 2 ファイルに追加。
19
+ - 横展開監査結果: 同種パターン (`execSync(\`...${var}...\`)`) は他に `scripts/harness/skill-quality/infrastructure/adapters/git-commit-executor-adapter.ts:14` に 1 箇所存在(`JSON.stringify` 経由だが `$` / バッククオートが残存)。本 WI のスコープ (`affects: [phase2-extensions]`) 外のため follow-up WI として WI-035 description に記録。
20
+
10
21
  ## [0.110.0] - 2026-04-25
11
22
 
12
23
  ### Documentation
package/README.ja.md CHANGED
@@ -1,10 +1,12 @@
1
+ ![Phasegate header](assets/phasegate-header.png)
2
+
1
3
  # Phasegate
2
4
 
3
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
5
7
 
6
- **AI が書いたコードに「設計してから書け」を物理的に強制するツールキット。**
7
- Claude Code / Codex / Cursor / Copilot — どの AI agent でも同じ防御が効きます。
8
+ **AI agent に「設計してから書け」を hooks / git / CI で強制するツールキット。**
9
+ Claude Code / Codex / Cursor / Copilot — どの AI agent でも設計意図・レイヤー境界・テスト規約を守らせます。
8
10
 
9
11
  [English README](README.md) ・ [開発者ガイド](DEVELOPMENT.ja.md)
10
12
 
@@ -12,7 +14,7 @@ Claude Code / Codex / Cursor / Copilot — どの AI agent でも同じ防御が
12
14
 
13
15
  ## 30 秒でわかる Phasegate
14
16
 
15
- 1. **AI agent が設計文書なしで実装ファイルを書こうとすると、Write/Edit/Bash がブロックされる**(PreToolUse hook
17
+ 1. **AI agent が設計文書なしで実装ファイルを書こうとすると、Write/Edit/Bash または git hook で止まる**
16
18
  2. **コミット前に L1〜L3 のバリデーションが自動で走り**、レイヤー違反・テスト品質違反・依存方向違反を弾く
17
19
  3. **ブロック時のエラーは AI が読んで自己修正できる形式**(理由・必要な設計文書・次に打つべきスキル名が出る)
18
20
 
@@ -24,7 +26,7 @@ Claude Code / Codex / Cursor / Copilot — どの AI agent でも同じ防御が
24
26
 
25
27
  AI agent は速いが、設計を飛ばして実装に走ります。レイヤー境界を平気で越え、`any` 型で型システムを骨抜きにし、テストはあるけど実装の写経になっている — そんなコードを高速に量産します。レビューで全部捕まえるのは現実的ではありません。
26
28
 
27
- Phasegate はこれを **「人がレビューで防ぐ」のではなく「ツールがファイルシステム/git/CI レベルで防ぐ」** で解決します。設計文書がなければそもそも書けない。レイヤー違反があれば commit が通らない。AI agent 自身が「次にどの設計スキルを呼べばいいか」を読んで自走します。
29
+ Phasegate はこれを **「人がレビューで防ぐ」のではなく「ツールが hooks / git / CI レベルで防ぐ」** で解決します。設計文書がなければ書き込みまたは commit が止まる。レイヤー違反があれば CI が通らない。AI agent 自身が「次にどの設計スキルを呼べばいいか」を読んで自走します。
28
30
 
29
31
  ### こんなプロジェクトで効きます
30
32
 
@@ -51,7 +53,7 @@ AI agent が設計なしに `src/order/order-service.ts` を書こうとする
51
53
  実行例: /story-implementor --unit order
52
54
  ```
53
55
 
54
- Claude Code / Codex はこのメッセージを読んで `/story-implementor` を起動し、ドメイン設計→論理設計→TDD 実装の順で進みます。人間が「設計やってからね」と言わなくても自走します。
56
+ Claude Code / Codex はこのメッセージを読んで `/story-implementor` を起動し、ドメイン設計→論理設計→TDD 実装の順で進みます。単に失敗させるのではなく、AI agent が復帰できる形で「次に何を作るべきか」を返します。
55
57
 
56
58
  ---
57
59
 
@@ -81,9 +83,19 @@ claude
81
83
  - `skills/` — 28 の AIDLC スキル一式
82
84
  - `.claude/skills/` ・ `.codex/skills/` — agent 向けの skill symlink
83
85
  - `.claude/settings.json` — PreToolUse / PostToolUse / Stop hook
84
- - `docs/principles/` ・ `docs/folder_management_rules.md` — 設計原則 docs
86
+ - `.codex/hooks.json` — Codex CLI hooks 設定(`--agent codex|both` 時)
87
+ - `docs/principles/*.md` — アーキテクチャ哲学・テスト規約(immutable)
88
+ - `docs/folder_management_rules.md` — ドキュメント配置ルール(**正本**)
85
89
  - `--with-husky` を付けると `.husky/pre-commit` ・ `.husky/commit-msg` も配置
86
90
 
91
+ **`init` が生成しないもの**(後で skill が作る):
92
+
93
+ - `docs/inception/` 配下の WI directory — `/product-architect` 以降のスキル実行で生成
94
+ - `docs/product/` 配下の確定設計文書 — `/domain-designer` `/logical-designer` 等が生成
95
+ - `docs/ADR/` — `/skill-creator` や手動で必要に応じて作成
96
+
97
+ 「設計してから書け」を強制する仕組みなので、設計文書はユーザーがスキル経由で作るのが既定動作です。
98
+
87
99
  ### Codex CLI を使う場合
88
100
 
89
101
  ```bash
@@ -91,7 +103,7 @@ npx phasegate init --name my-project --agent codex --with-husky
91
103
  codex features enable codex_hooks # Codex 本体の feature flag を手動で有効化
92
104
  ```
93
105
 
94
- 両方使う場合は `--agent both`。詳細は [Codex Integration Guide](docs/guide/codex-integration.md) を参照。
106
+ 両方使う場合は `--agent both`。Codex のネイティブ `apply_patch` は現時点で事前 hook を発火しないため、pre-commit (L2) で commit 時にブロックします。Bash 経由の書き込みは実行前に止まります。詳細は [Codex Integration Guide](docs/guide/codex-integration.md) を参照。
95
107
 
96
108
  ### アップデート
97
109
 
@@ -113,6 +125,7 @@ npx phasegate update-skills # スキルを最新版に再デプロイ
113
125
  | **Claude Code / Codex Hooks** | Write/Edit/Bash 時に自動でゲートチェック・lint を実行 |
114
126
  | **HarnessError 形式** | 全エラーに ADR 参照 + 修正例が含まれ、AI が自己修正できる |
115
127
  | **Baseline (retrofit)** | 既存リポジトリ導入時、`baseline` snapshot に登録した既存ファイルは構造的に編集されるまで gate 対象外 |
128
+ | **カスタム gate** | AIDLC 以外のプロジェクトでも schema-first など独自の前提条件を設定できる |
116
129
 
117
130
  ---
118
131
 
@@ -176,21 +189,43 @@ AIDLC (AI-Driven Development Life Cycle) は **要求定義 → 設計 → テ
176
189
 
177
190
  ## メタデータ規約
178
191
 
179
- ソースファイル先頭に `@unit` / `@layer` を、テストには `@story` を記載します。L1 はこれを使ってレイヤー違反検出と drift-detection を行います。
192
+ ソースファイル先頭に `@unit` / `@layer` を、テストには `@story` または `@work-item-id` を記載します。L1 / L2 はこれを使ってレイヤー違反検出・drift-detection・WI トレーサビリティを行います。
180
193
 
181
194
  ```typescript
182
195
  // @unit config-foundation
183
196
  // @layer domain
184
- // @story US-001 テストファイルのみ
197
+ // @work-item-id WI-042 任意(traceability に貢献)
198
+ // @story US-001 ← テストファイルのみ(legacy 互換)
185
199
 
186
200
  export class ConfigSchema { ... }
187
201
  ```
188
202
 
189
- | タグ | 値 |
190
- |---|---|
191
- | `@unit` | `/unit-designer` が定義した Unit 名(例: `config-foundation`) |
192
- | `@layer` | `architecture.preset` で定義した層名(例: `domain` / `application` / `infrastructure` / `presentation`) |
193
- | `@story` | 検証する US の ID(例: `US-001`) |
203
+ | タグ | 値 | 必須性 |
204
+ |---|---|---|
205
+ | `@unit` | `/unit-designer` が定義した Unit 名(例: `config-foundation`) | **必須**(L1-001 が検証) |
206
+ | `@layer` | `architecture.preset` で定義した層名(例: `domain` / `application` / `infrastructure` / `presentation`) | **必須**(L1-002 が検証) |
207
+ | `@work-item-id` | このファイル変更を駆動した WI(例: `WI-042`) | 任意 |
208
+ | `@story` | 検証する US / WI の ID(例: `US-001`, `H02-04`) | テストでは推奨(legacy 互換) |
209
+
210
+ ### product 文書での反映宣言
211
+
212
+ product 文書(`docs/product/construction/{unit}/*.md`)の章ごとに、反映元の WI を `@work-item-id` で記載します:
213
+
214
+ ```markdown
215
+ ## ポート定義
216
+
217
+ <!-- @work-item-id WI-042 -->
218
+ ### OrderRepository Port
219
+ - findById(id: OrderId): Promise<Order>
220
+
221
+ <!-- @work-item-id WI-042, WI-051 -->
222
+ ### PaymentGateway Port
223
+ - charge(amount: Money): Promise<Receipt>
224
+ ```
225
+
226
+ L2-STORY-REFLECTION バリデータがこのアノテーションを検出し、inception 設計が product に反映されているかを判定します。
227
+
228
+ > **legacy 互換**: 既存 product 文書の `@story-id US-XXX` / `@story-id H##-##` / `@issue-id ISSUE-XXX` は、WI frontmatter の `legacy_id` 経由で読み替えられます。一括置換は **しません**。新規記述は `@work-item-id WI-XXX` を使ってください。
194
229
 
195
230
  ---
196
231
 
@@ -260,7 +295,7 @@ npx phasegate <command> [options]
260
295
  | `phasegate:status` | 全体の健全性サマリ |
261
296
  | `phasegate:check-phase --unit <id>` | 指定 Unit の現在フェーズ |
262
297
  | `phasegate:detect-drift` | 設計-コード乖離レポート |
263
- | `migrate work-items --dry-run` / `--apply` | `ISSUE-XXX` / `H{NN}-{NN}` を `WI-XXX` 統一レイアウトへ移行 |
298
+ | `migrate work-items --dry-run` / `--apply` | 既存リポジトリの旧 `ISSUE-XXX` / `H{NN}-{NN}` directory WI 統一レイアウト(`_cross/{WI-XXX}/` / `{unit}/{WI-XXX}/`)へ移行。frontmatter(`type` / `severity` / `legacy_id` / `affects`)を自動注入。冪等。`--json` で CI/スクリプト連携可。詳細: [Work Item Migration](docs/guide/cli-reference.md#work-item-migration) |
264
299
  | `migrate --schema v3` | `phasegate.config.json` を v3 schema へ昇格(`architecture` キー追加) |
265
300
  | `ci:generate-template --type <aidlc-gate\|pre-commit\|consistency-check>` | CI/CD テンプレート生成(`--render` でファイル出力) |
266
301
  | `list-errors --layer <L0-L4>` | エラー定義一覧 |
@@ -299,21 +334,104 @@ npx phasegate <command> [options]
299
334
 
300
335
  ---
301
336
 
337
+ ## ドキュメント・ライフサイクル
338
+
339
+ Phasegate は **「inception で設計を起こし → product に確定させ → src に実装する」** という単方向のデータフローを物理的に強制します。各段階で生成される文書と PhaseGate の振る舞いが対応しています。
340
+
341
+ ### 三階層モデル
342
+
343
+ ```
344
+ docs/inception/{unit}/{WI-XXX}/ ← 一時的な計画・設計(WI ごと、流動)
345
+ ↓ 設計成果物の反映(@work-item-id 付きで累積更新)
346
+ docs/product/construction/{unit}/ ← 確定設計(Unit ごとの正本、永続)
347
+ ↕ フェーズゲート
348
+ scripts/harness/{unit}/(domain|application|infrastructure|presentation)/*.ts
349
+ ```
350
+
351
+ ### Work Item (WI) の置き場
352
+
353
+ WI は規模・影響範囲に応じて 3 通りに振り分けます。
354
+
355
+ | 配置先 | 用途 |
356
+ |---|---|
357
+ | `docs/inception/_shared/` | 非 WI の横断計画・戦略・調査メモ |
358
+ | `docs/inception/_cross/{WI-XXX}/` | 複数 Unit に影響する cross-cutting WI |
359
+ | `docs/inception/{unit}/{WI-XXX}/` | 単一 Unit が所有する WI |
360
+
361
+ > **廃止済み**(v0.104.0 で物理削除): `docs/inception/issues/`, `docs/inception/{unit}/issues/`, `docs/inception/{unit}/{US-XXX}/`。既存資産は `npx phasegate migrate work-items --apply` で `WI-XXX` へ移行済み。`legacy_id` で旧 ID の grep 互換は維持。
362
+
363
+ ### WI frontmatter(必須)
364
+
365
+ 各 WI の `description.md` 先頭に:
366
+
367
+ ```yaml
368
+ ---
369
+ id: WI-042
370
+ type: story | issue | fix | refactor | chore # 後述
371
+ severity: trivial | normal | high
372
+ status: drafted | reflected | implemented | tested # PhaseGate が自動更新
373
+ affects: [unit-a, unit-b] # cross-unit のみ列挙
374
+ legacy_id: ISSUE-XXX | US-XXX | H{NN}-{NN} # 任意
375
+ ---
376
+ ```
377
+
378
+ L2 metadata validator が frontmatter の妥当性を検証します。
379
+
380
+ ### type による要求成果物の段階化
381
+
382
+ | `type` | inception 必須 | product 反映 | 用途 |
383
+ |---|---|---|---|
384
+ | `story` | description + logical_design + domain_model + test 設計 | 全カテゴリ累積 | 新機能 |
385
+ | `issue` | description + logical_design + domain_model + 関係 test 設計 | 関係カテゴリ累積 | バグ・仕様不整合 |
386
+ | `refactor` | description + logical_design | logical_design 更新 | リファクタ |
387
+ | `fix` | description + PR link | 関係カテゴリに `@work-item-id` 追記 | typo・依存更新等 |
388
+ | `chore` | description.md 1 行 + PR link | 不要 | 雑用 |
389
+
390
+ `fix` / `chore` は軽量パスとして提供。formal な story で起票するには重すぎる修正もここで証跡が残せます。
391
+
392
+ ### State Machine
393
+
394
+ ```
395
+ DRAFTED (inception 揃う)
396
+ ↓ Phase 0/2 reflection
397
+ REFLECTED (product に @work-item-id 反映済み)
398
+ ↓ Phase 3 implementation
399
+ IMPLEMENTED (src 実装あり / lint・type・test green)
400
+ ↓ Phase 4 test
401
+ TESTED (@work-item-id 付きテストあり / green)
402
+ ```
403
+
404
+ `type: chore` は DRAFTED で完結。`type: fix` は DRAFTED → REFLECTED → IMPLEMENTED の簡略パス。`status` は PhaseGate が自動更新します。
405
+
406
+ 詳細仕様: [`docs/folder_management_rules.md`](docs/folder_management_rules.md)
407
+
408
+ ---
409
+
302
410
  ## 導入後のプロジェクト構造
303
411
 
304
412
  ```
305
413
  your-project/
306
414
  ├── phasegate.config.json
307
415
  ├── docs/
308
- │ ├── folder_management_rules.md
309
- │ ├── principles/ # アーキテクチャ哲学・テスト規約
310
- │ ├── product/construction/{unit}/ # 確定版設計(domain_model.md / logical_design.md)
311
- │ ├── inception/{unit}/{US-XXX}/ # AIDLC が生成する設計計画
416
+ │ ├── folder_management_rules.md # WI 仕様の正本(init で配置)
417
+ │ ├── principles/ # 開発原則(init で配置・immutable)
418
+ │ ├── inception/ # AIDLC スキルが生成
419
+ ├── _shared/ # 横断計画
420
+ │ │ ├── _cross/{WI-XXX}/ # cross-unit WI
421
+ │ │ └── {unit}/{WI-XXX}/ # Unit 所有 WI
422
+ │ ├── product/ # 確定設計(累積更新)
423
+ │ │ ├── product_overview.md
424
+ │ │ ├── user_stories.md
425
+ │ │ ├── units/{unit}.md
426
+ │ │ └── construction/{unit}/
427
+ │ │ ├── domain_model.md
428
+ │ │ ├── logical_design.md
429
+ │ │ └── ...
312
430
  │ └── ADR/
313
- ├── src/ # 実装コード(@unit/@layer 必須)
431
+ ├── src/ # 実装コード(@unit/@layer 必須)
314
432
  ├── .claude/{settings.json, skills/}
315
- ├── .codex/{hooks.json, skills/}
316
- └── skills/ # init で再生成可能
433
+ ├── .codex/{hooks.json, skills/} # --agent codex|both 時
434
+ └── skills/ # init で再生成可能
317
435
  ```
318
436
 
319
437
  推奨 `.gitignore`:
@@ -329,9 +447,9 @@ reports/
329
447
 
330
448
  ---
331
449
 
332
- ## ロードマップ
450
+ ## 既知の制約とロードマップ
333
451
 
334
- ドキュメントで言及があるが現状 partial 実装または user 配線に依存しているもの。各 Work Item は `docs/inception/_cross/WI-XXX/description.md` に起票済み。
452
+ 主要な導入パスはそのまま利用できますが、一部の機能は user 側の配線が必要、または今後の minor release での改善対象です。各 Work Item は `docs/inception/_cross/WI-XXX/description.md` に起票済みです。
335
453
 
336
454
  | Work Item | 内容 |
337
455
  |---|---|
@@ -340,7 +458,7 @@ reports/
340
458
  | **[WI-033](docs/inception/_cross/WI-033/description.md)** | `doc-freshness` / `pointer-validation` を L4 validator に昇格 |
341
459
  | **[WI-034](docs/inception/_cross/WI-034/description.md)** | L0 legacy validator (`L0-001` / `L0-002`) の撤去 |
342
460
 
343
- L3 Nyquist Validation の `requirement-test-matrix.json` 自動生成パイプラインも未完成(手動セットアップで利用可)。
461
+ L3 Nyquist Validation の `requirement-test-matrix.json` 自動生成はまだ未自動化です。現時点では手動セットアップで利用できます。
344
462
 
345
463
  ---
346
464
 
package/README.md CHANGED
@@ -1,61 +1,124 @@
1
+ ![Phasegate header](assets/phasegate-header.png)
2
+
1
3
  # Phasegate
2
4
 
3
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
  [![Node.js >= 18](https://img.shields.io/badge/Node.js-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
5
7
 
6
- **Phasegate -- AI-agnostic quality defense toolkit.**
8
+ **A toolkit that makes AI agents design before they code.**
9
+
10
+ Phasegate adds project-local hooks, validators, and agent skills that keep generated code aligned with design intent, layer boundaries, and test discipline across Claude Code, Codex, Cursor, Copilot, and other AI coding agents.
7
11
 
8
- Enforces structural integrity between design intent and code, regardless of which AI agent you use.
12
+ [日本語版](README.ja.md) | [Developer Guide](DEVELOPMENT.md)
9
13
 
10
14
  ---
11
15
 
12
- ## Why Phasegate?
16
+ ## Phasegate in 30 Seconds
13
17
 
14
- AI coding agents are fast but unconstrained. They skip design steps, violate layer boundaries, and produce code that drifts from intent. Phasegate solves this with a portable, agent-independent defense layer that makes it **physically impossible** to implement without design, commit without validation, or merge without traceability.
18
+ 1. **When an AI agent tries to write implementation code without design docs, Phasegate blocks the write** through agent hooks or git hooks.
19
+ 2. **Before commit and CI, validators check layer boundaries, metadata, test quality, security, performance, and traceability.**
20
+ 3. **Every failure is returned in an agent-readable format** with the reason, missing artifacts, references, and the next skill or command to run.
15
21
 
16
- Works with **Claude Code, Codex, Cursor, Copilot**, or any other AI agent.
22
+ Run `npx phasegate init` once and the project gets the guardrails, skills, and configuration needed to make that flow repeatable.
17
23
 
18
24
  ---
19
25
 
20
- ## Features
26
+ ## Why Phasegate?
27
+
28
+ AI coding agents are fast, but they do not naturally protect your architecture. They skip design steps, cross layer boundaries, weaken type systems with `any`, and generate tests that mirror implementation instead of proving behavior. Human review cannot reliably catch that at AI speed.
21
29
 
22
- | Feature | Description |
30
+ Phasegate turns those expectations into enforcement. If the design is missing, the agent is told what to create first. If a change violates the architecture, commit or CI fails. If a design has not been reflected into canonical product docs, implementation is blocked until the trace exists.
31
+
32
+ ### Where it fits
33
+
34
+ | Good fit | Poor fit |
23
35
  |---|---|
24
- | **5-Layer Defense Model** | L0 through L4 validators from editor time to scheduled audits |
25
- | **28 AIDLC Skills** | Full coverage from product architecture to story implementation |
26
- | **Phase Dependency Model** | Blocks implementation when required design documents are missing |
27
- | **Quick Mode** | Lightweight gate for bugfixes, docs, tests, and config changes |
28
- | **Claude Code Hooks** | Native PreToolUse / PostToolUse / Stop hook integration |
29
- | **Codex CLI Hooks** | `PreToolUse(Bash)` / `PostToolUse(Bash)` / `Stop` hook integration (native `apply_patch` falls back to pre-commit) |
30
- | **HarnessError Format** | Every error includes ADR references and fix examples for AI self-correction |
31
- | **Configurable Phase Gates** | Define custom gates with `gates[]` in config. Default uses AIDLC phase dependencies |
32
- | **Protected File Control** | Configure which files are protected from AI writes via `protectedFiles.exclude` |
33
- | **Bash Write Detection** | Detects and blocks shell-based file writes (`sed -i`, `tee`, `cp`, `mv`, redirects) |
34
- | **Presets** | minimal, standard, and strict -- choose your quality level |
36
+ | Medium to large projects where AI agents implement multiple features | Throwaway scripts with no lasting structure |
37
+ | Clean Architecture, DDD, Hexagonal, or layered systems | Codebases where architecture is intentionally ad hoc |
38
+ | Teams that want TDD and test conventions enforced automatically | Projects that do not write automated tests |
39
+ | Products that need design-code drift detection over time | Projects where code is the only source of truth |
40
+
41
+ ---
42
+
43
+ ## What It Looks Like
44
+
45
+ When an agent tries to write `src/order/order-service.ts` before the `order` unit has design docs, Phasegate stops it:
46
+
47
+ ```text
48
+ Phase gate violation: src/order/order-service.ts
49
+ Scope: Level 3 (implementation), Unit: order
50
+ Blocked because:
51
+ - docs/product/construction/order/domain_model.md is missing
52
+ - docs/product/construction/order/logical_design.md is missing
53
+ Next action: run the /story-implementor skill and start from design.
54
+ Example: /story-implementor --unit order
55
+ ```
56
+
57
+ The point is not just to fail the edit. The error gives the AI agent enough structure to recover: create the missing design, reflect it into product docs, then implement with tests.
35
58
 
36
59
  ---
37
60
 
38
61
  ## Quick Start
39
62
 
40
- ### 1. Install
63
+ ### Requirements
64
+
65
+ Node.js >= 18, npm >= 9, TypeScript 5.x
66
+
67
+ ### 3 steps
41
68
 
42
69
  ```bash
70
+ # 1. Install
43
71
  npm install --save-dev phasegate
72
+
73
+ # 2. Initialize the project
74
+ npx phasegate init --name my-project --with-husky
75
+
76
+ # 3. Start your AI agent and begin with product design
77
+ claude
78
+ > /product-architect
44
79
  ```
45
80
 
46
- ### 2. Initialize
81
+ `init` creates:
82
+
83
+ - `phasegate.config.json` as the quality settings source of truth
84
+ - `skills/` with 28 AIDLC skills
85
+ - `.claude/skills` and/or `.codex/skills` links for agent use
86
+ - `.claude/settings.json` and/or `.codex/hooks.json` hook configuration
87
+ - `docs/principles/*.md` and `docs/folder_management_rules.md`
88
+ - `.husky/pre-commit` and `.husky/commit-msg` when `--with-husky` is passed
89
+
90
+ `init` intentionally does **not** create `docs/inception/` work item directories or `docs/product/` design documents. Those are produced later by skills such as `/product-architect`, `/domain-designer`, and `/logical-designer`. That is the core contract: no design, no code.
91
+
92
+ ### Codex CLI
47
93
 
48
94
  ```bash
49
- npx phasegate init --name my-project
95
+ npx phasegate init --name my-project --agent codex --with-husky
96
+ codex features enable codex_hooks
50
97
  ```
51
98
 
52
- This deploys 28 skills to `skills/`, creates agent-specific links such as `.claude/skills` or `.codex/skills`, installs design principles docs (`docs/principles/*.md`, `docs/folder_management_rules.md`), and generates `phasegate.config.json`.
99
+ Use `--agent both` for projects that use Claude Code and Codex together. Codex native `apply_patch` currently cannot be intercepted before the edit, so those violations are caught at pre-commit; Bash-based writes are blocked before execution.
53
100
 
54
- Optional: add `--with-husky` to also install a `.husky/pre-commit` hook that runs L2 validators.
101
+ ### Update
55
102
 
56
- ### 3. Start the AIDLC
103
+ ```bash
104
+ npm update phasegate
105
+ npx phasegate update-skills
106
+ ```
107
+
108
+ ---
57
109
 
58
- Launch your AI agent and run the `/product-architect` skill to begin.
110
+ ## Core Capabilities
111
+
112
+ | Capability | What it does |
113
+ |---|---|
114
+ | **Phase gates** | Blocks implementation writes until required design documents exist and have been reflected into product docs |
115
+ | **5-layer validation** | Runs checks from agent runtime and editor time through pre-commit, CI, and scheduled audits |
116
+ | **28 AIDLC skills** | Guides AI agents through product architecture, story writing, domain design, test design, and TDD implementation |
117
+ | **Quick Mode** | Keeps bugfixes, docs, test-only changes, and config changes lightweight while preserving traceability |
118
+ | **Claude Code / Codex hooks** | Runs checks around Write/Edit/Bash operations and session boundaries |
119
+ | **Agent-readable HarnessError output** | Gives AI agents the reason, missing artifacts, references, and examples needed to self-correct |
120
+ | **Retrofit baseline** | Lets existing repositories adopt Phasegate gradually by grandfathering unchanged files |
121
+ | **Configurable gates** | Supports AIDLC defaults or custom gates such as schema-first API development |
59
122
 
60
123
  ---
61
124
 
@@ -100,60 +163,130 @@ Launch your AI agent and run the `/product-architect` skill to begin.
100
163
 
101
164
  ## 28 Skills
102
165
 
103
- Skills cover the full **AIDLC (AI-Driven Development Life Cycle)**, enforcing phase dependencies so that implementation cannot begin without design.
166
+ Skills cover the full **AIDLC (AI-Driven Development Life Cycle)**: product definition, design, test design, and TDD implementation. Each skill consumes the artifacts from the previous phase.
104
167
 
105
- ### Foundation (4)
168
+ **First step**: run `/product-architect` inside Claude Code or Codex.
106
169
 
107
- | Skill | Purpose |
170
+ | Group | Skills |
108
171
  |---|---|
109
- | `/product-architect` | Define product vision, domains, architecture, and constraints |
110
- | `/story-writer` | Create Who/What/Why user stories with acceptance criteria |
111
- | `/story-mapper` | Prioritize stories and define MVP scope |
112
- | `/unit-designer` | Group stories into independently buildable Units |
172
+ | **Foundation (4)** | `/product-architect` `/story-writer` `/story-mapper` `/unit-designer` |
173
+ | **Design (5)** | `/domain-designer` `/logical-designer` `/mock-designer` `/uiux-designer` `/environment-designer` |
174
+ | **Test Engineering (7)** | `/unit-test-designer` `/it-test-designer` `/scenario-test-designer` `/unit-test-logic-designer` `/it-test-logic-designer` `/scenario-test-logic-designer` `/test-coverage-checker` |
175
+ | **Implementation (4)** | `/story-implementor` `/quick-implementor` `/implementation-planner` `/implementation-readiness-checker` |
176
+ | **Verification (8)** | `/consistency-checker` `/cascade-updater` `/codex-delegator` `/codebase-mapper` `/doc-freshness-checker` `/pointer-validator` `/engineering-perspective` `/skill-creator` |
113
177
 
114
- ### Design (5)
178
+ Details, prerequisites, and generated artifacts: [Skills Overview](docs/guide/skills-overview.md)
115
179
 
116
- | Skill | Purpose |
117
- |---|---|
118
- | `/domain-designer` | DDD tactical design -- aggregates, entities, value objects, events |
119
- | `/logical-designer` | Hexagonal architecture design (ports and adapters) |
120
- | `/mock-designer` | UI mockup design for early validation |
121
- | `/uiux-designer` | Final UI/UX definition from test cases and logical design |
122
- | `/environment-designer` | Local dev environment and infrastructure design |
180
+ ---
123
181
 
124
- ### Test Engineering (7)
182
+ ## Document Lifecycle
125
183
 
126
- | Skill | Purpose |
127
- |---|---|
128
- | `/unit-test-designer` | Unit test case design from domain models |
129
- | `/it-test-designer` | Integration test case design from logical design |
130
- | `/scenario-test-designer` | E2E scenario test case design |
131
- | `/unit-test-logic-designer` | Vitest implementation logic with pseudocode |
132
- | `/it-test-logic-designer` | Integration test Vitest implementation logic |
133
- | `/scenario-test-logic-designer` | Playwright E2E implementation logic |
134
- | `/test-coverage-checker` | Coverage verification and Nyquist validation |
184
+ Phasegate enforces a single-direction data flow: **inception → product → src**. Each step has a designated location and a corresponding PhaseGate behavior.
135
185
 
136
- ### Implementation (4)
186
+ ### Three-tier model
137
187
 
138
- | Skill | Purpose |
139
- |---|---|
140
- | `/story-implementor` | TDD implementation (Red-Green-Refactor) with atomic commits |
141
- | `/quick-implementor` | Lightweight implementation for bugfixes, docs, tests, config |
142
- | `/implementation-planner` | Implementation plan from Unit specs and domain models |
143
- | `/implementation-readiness-checker` | Pre-implementation readiness verification |
188
+ ```
189
+ docs/inception/{unit}/{WI-XXX}/ ← transient planning/design (per WI, fluid)
190
+ reflection (with @work-item-id, accumulated update)
191
+ docs/product/construction/{unit}/ ← canonical design (per Unit, persistent)
192
+ phase gate
193
+ scripts/harness/{unit}/(domain|application|infrastructure|presentation)/*.ts
194
+ ```
144
195
 
145
- ### Verification (8)
196
+ ### Work Item (WI) layout
146
197
 
147
- | Skill | Purpose |
198
+ WIs are placed in one of three buckets based on scope:
199
+
200
+ | Path | Use |
148
201
  |---|---|
149
- | `/consistency-checker` | Cross-layer consistency check across design documents |
150
- | `/cascade-updater` | Propagate lower-phase discoveries to upstream design docs |
151
- | `/codex-delegator` | Delegate tasks to Codex CLI with quality oversight |
152
- | `/codebase-mapper` | Generate structure map from `@unit`/`@layer` annotations |
153
- | `/doc-freshness-checker` | Design document staleness detection (L4 extension) |
154
- | `/pointer-validator` | Validate file path references in design documents |
155
- | `/engineering-perspective` | Multi-perspective design review (Beck, Fowler, Martin, Evans) |
156
- | `/skill-creator` | Create or update agent skills |
202
+ | `docs/inception/_shared/` | Cross-cutting plans/strategy/research not tied to a WI |
203
+ | `docs/inception/_cross/{WI-XXX}/` | Cross-cutting WI affecting multiple Units |
204
+ | `docs/inception/{unit}/{WI-XXX}/` | WI owned by a single Unit |
205
+
206
+ > **Removed in v0.104.0**: `docs/inception/issues/`, `docs/inception/{unit}/issues/`, `docs/inception/{unit}/{US-XXX}/`. Existing assets are migrated via `npx phasegate migrate work-items --apply`. Legacy IDs are retained via `legacy_id` for grep compatibility.
207
+
208
+ ### WI frontmatter (required)
209
+
210
+ Each WI's `description.md` must start with:
211
+
212
+ ```yaml
213
+ ---
214
+ id: WI-042
215
+ type: story | issue | fix | refactor | chore # see below
216
+ severity: trivial | normal | high
217
+ status: drafted | reflected | implemented | tested # auto-updated by PhaseGate
218
+ affects: [unit-a, unit-b] # cross-unit only
219
+ legacy_id: ISSUE-XXX | US-XXX | H{NN}-{NN} # optional
220
+ ---
221
+ ```
222
+
223
+ L2 metadata validator verifies the frontmatter shape.
224
+
225
+ ### Required artifacts by `type`
226
+
227
+ | `type` | inception artifacts | product reflection | Use |
228
+ |---|---|---|---|
229
+ | `story` | description + logical_design + domain_model + test designs | All categories accumulated | New feature |
230
+ | `issue` | description + logical_design + domain_model + relevant test designs | Relevant categories | Bug / spec mismatch |
231
+ | `refactor` | description + logical_design | logical_design update | Refactor |
232
+ | `fix` | description + PR link | `@work-item-id` annotation in relevant category | Typo / dep update |
233
+ | `chore` | description.md (1 line) + PR link | None | Chore |
234
+
235
+ `fix` / `chore` are lightweight paths — fixes too small for a formal story still get audit trail.
236
+
237
+ ### State machine
238
+
239
+ ```
240
+ DRAFTED (inception artifacts present per `type`)
241
+ ↓ Phase 0/2 reflection
242
+ REFLECTED (product carries @work-item-id WI-XXX)
243
+ ↓ Phase 3 implementation
244
+ IMPLEMENTED (src exists / lint+type+test green)
245
+ ↓ Phase 4 test
246
+ TESTED (test files annotated with @work-item-id, all green)
247
+ ```
248
+
249
+ `type: chore` ends at DRAFTED. `type: fix` shortcuts via DRAFTED → REFLECTED → IMPLEMENTED. PhaseGate auto-updates `status`.
250
+
251
+ Full spec: [`docs/folder_management_rules.md`](docs/folder_management_rules.md)
252
+
253
+ ---
254
+
255
+ ## Metadata Conventions
256
+
257
+ Each source file declares its `@unit` / `@layer`. Tests add `@story` or `@work-item-id` for traceability.
258
+
259
+ ```typescript
260
+ // @unit config-foundation
261
+ // @layer domain
262
+ // @work-item-id WI-042 ← optional (boosts traceability)
263
+ // @story US-001 ← test files only (legacy)
264
+
265
+ export class ConfigSchema { ... }
266
+ ```
267
+
268
+ | Tag | Value | Required |
269
+ |---|---|---|
270
+ | `@unit` | Unit name from `/unit-designer` (e.g., `config-foundation`) | **Yes** (L1-001) |
271
+ | `@layer` | Layer name from `architecture.preset` | **Yes** (L1-002) |
272
+ | `@work-item-id` | WI driving this file change (e.g., `WI-042`) | Optional |
273
+ | `@story` | US/WI being verified by tests (legacy) | Recommended for tests |
274
+
275
+ In product docs, declare reflection per section using HTML-comment annotations:
276
+
277
+ ```markdown
278
+ ## Port Definitions
279
+
280
+ <!-- @work-item-id WI-042 -->
281
+ ### OrderRepository Port
282
+ - findById(id: OrderId): Promise<Order>
283
+
284
+ <!-- @work-item-id WI-042, WI-051 -->
285
+ ### PaymentGateway Port
286
+ - charge(amount: Money): Promise<Receipt>
287
+ ```
288
+
289
+ L2-STORY-REFLECTION uses these annotations to verify inception design has been cascaded into product. Legacy `@story-id US-XXX` / `@story-id H##-##` / `@issue-id ISSUE-XXX` are still resolved via WI `legacy_id` — no bulk replacement needed for existing docs.
157
290
 
158
291
  ---
159
292
 
@@ -376,9 +509,9 @@ Additional resources:
376
509
 
377
510
  ---
378
511
 
379
- ## Roadmap (Planned but not yet implemented)
512
+ ## Known Limits and Roadmap
380
513
 
381
- The following are documented behaviors that are partially implemented or rely on user-side wiring. Each is tracked as a Work Item and will land in a future minor release. Inception docs live under `docs/inception/_cross/WI-XXX/description.md`.
514
+ The main path is ready for project use, but a few documented behaviors still require user-side wiring or are tracked for a future minor release. Each item has a Work Item under `docs/inception/_cross/WI-XXX/description.md`.
382
515
 
383
516
  | Work Item | Title | Why it matters |
384
517
  |---|---|---|
@@ -387,7 +520,7 @@ The following are documented behaviors that are partially implemented or rely on
387
520
  | **[WI-033](docs/inception/_cross/WI-033/description.md)** | Promote `doc-freshness` / `pointer-validation` to L4 validators | Both capabilities exist as `p2:check-freshness` / `p2:validate-pointers` CLI commands but are not registered as L4 validators, so `validate --layer L4` skips them. WI-033 plumbs them through `validator-system` so they run via the standard L4 path and presets. |
388
521
  | **[WI-034](docs/inception/_cross/WI-034/description.md)** | Retire legacy L0 validators (`L0-001` / `L0-002`) | The `fuse-hook-config` / `fuse-mount-status` validator IDs are leftovers from an earlier FUSE-based design. They are disabled by default and have no actual implementation behind them. WI-034 removes them and lets the agent-integration runtime hooks be the sole L0 surface. |
389
522
 
390
- `requirement-test-matrix.json` auto-generation for L3 Nyquist Validation is also a known gap; see the L3 section above.
523
+ `requirement-test-matrix.json` auto-generation for L3 Nyquist Validation is not automated yet; see the L3 guide for the current manual setup.
391
524
 
392
525
  ---
393
526
 
@@ -1,251 +1,316 @@
1
1
  # docs ディレクトリ管理ガイド
2
2
 
3
- 本ドキュメントは`docs/`配下のドキュメント管理方針を定義します。
3
+ 本ドキュメントは `docs/` 配下のドキュメント管理方針を定義します。Phasegate が「設計なしの実装を物理的に拒否する」ための **正本となる構造とアノテーション規約**を記述しています。
4
+
5
+ > WI-026 (v0.100.0..v0.104.0) で work item taxonomy が `WI-XXX` に統一されました。`docs/inception/issues/` および `docs/inception/{unit}/issues/` は **廃止済み**です。本ドキュメントは v0.105.0 以降の最新仕様で記述されています。
4
6
 
5
7
  ---
6
8
 
7
- ## ディレクトリ構造
9
+ ## 1. ディレクトリ構造(全体像)
8
10
 
9
11
  ```
10
12
  docs/
11
- ├── ADR/ # Architecture Decision Records
12
- ├── basic_input/ # 入力サンプル・テンプレート
13
- ├── principles/ # 開発原則・ルール
14
- ├── inception/ # 計画ドキュメント + 作業単位(US・issue)の設計
15
- └── product/ # 共有設計ドキュメント(確定版)
13
+ ├── ADR/ # Architecture Decision Records
14
+ ├── principles/ # 開発原則・テスト規約(immutable)
15
+ ├── guide/ # 公開ユーザーガイド
16
+ ├── inception/ # 計画・work item の一時設計(流動)
17
+ │ ├── _shared/ # 非 WI の横断計画(戦略・タスクリスト等)
18
+ │ ├── _cross/ # cross-cutting WI(複数 Unit に影響)
19
+ │ │ └── {WI-XXX}/
20
+ │ └── {unit}/ # Unit 所有の WI と Unit 横断計画
21
+ │ └── {WI-XXX}/
22
+ └── product/ # 確定した設計成果物(累積更新・正本)
23
+ ├── product_overview.md
24
+ ├── user_stories.md
25
+ ├── user_story_mapping.md
26
+ ├── units/{unit}.md
27
+ └── construction/{unit}/
28
+ ├── domain_model.md
29
+ ├── logical_design.md
30
+ ├── uiux_design.md
31
+ ├── unit_test_design.md
32
+ ├── it_test_design.md
33
+ ├── unit_test_logic.md
34
+ ├── it_test_logic.md
35
+ └── coverage_report.md
16
36
  ```
17
37
 
18
- ---
19
-
20
- ## 各ディレクトリの役割
38
+ ### 役割の対応
21
39
 
22
- ### ADR/
23
- アーキテクチャ決定記録。技術選定や設計方針の決定理由を記録する。
40
+ | ディレクトリ | 役割 | 寿命 |
41
+ |---|---|---|
42
+ | `ADR/` | アーキテクチャ意思決定の永続記録 | 永続(status で管理) |
43
+ | `principles/` | 全プロジェクトで遵守すべき不変ルール | 永続(変更には ADR 必須) |
44
+ | `guide/` | 利用者向け公開ドキュメント | 永続(仕様変更で追従) |
45
+ | `inception/` | 計画・調査・work item の一時設計 | 流動(実装後はアーカイブ) |
46
+ | `product/` | Unit 単位の確定設計(累積更新) | 永続(生きたドキュメント) |
24
47
 
25
- ### basic_input/
26
- 入力データのサンプルやテンプレートを格納する。
48
+ ---
27
49
 
28
- ### principles/
29
- 開発原則、テストルール、アーキテクチャ哲学など、プロジェクト全体で遵守すべきルールを定義する。
50
+ ## 2. 三階層モデル: inception → product → src
30
51
 
31
- ### inception/
32
- **計画ドキュメント**と**作業単位(US・issue)の設計**を格納する。inception 配下のドキュメントは一時的な作業用であり、設計成果物は `product/` に反映される。
52
+ Phasegate の中核は **「inception で設計を起こし、product に確定させ、src(実装)に展開する」** という単方向のデータフローです。逆流はフェーズゲートでブロックされます。
33
53
 
34
54
  ```
35
- inception/
36
- ├── _shared/ # 横断的な計画(複数Unitにまたがるもの)
37
- ├── _operation/ # 運用・デプロイ関連の計画
38
- ├── issues/ # 横断的なissue(複数Unitにまたがるもの)
39
- │ └── {ISSUE-XXX}/
40
- │ ├── issue_description.md # 問題の記述
41
- │ ├── logical_design.md # 論理設計
42
- │ └── ...
43
- ├── {Unit名}/ # Unit毎の階層
44
- │ ├── *_plan.md # Unit全体の計画
45
- │ ├── {US-XXX}/ # ストーリー単位の計画・設計
46
- │ │ ├── *_plan.md # 実装計画
47
- │ │ ├── uiux_design.md # UI/UX設計
48
- │ │ └── ... # その他ストーリー固有のドキュメント
49
- │ └── issues/ # Unit固有のissue(バグ・不整合)
50
- │ └── {ISSUE-XXX}/
51
- │ ├── issue_description.md # 問題の記述
52
- │ ├── logical_design.md # 論理設計
53
- │ └── tdd_implementation_plan.md
55
+ docs/inception/{unit}/{WI-XXX}/ ← 一時的な計画・設計(WI ごと)
56
+ 設計成果物の反映(@work-item-id 付きで累積更新)
57
+ docs/product/construction/{unit}/ ← 確定設計(Unit ごとの正本)
58
+ フェーズゲート
59
+ scripts/harness/{unit}/(domain|application|infrastructure|presentation)/*.ts
54
60
  ```
55
61
 
56
- ### product/
57
- **確定した設計ドキュメント**を格納する。作業単位(US-XXX / ISSUE-XXX)のドキュメントは含まない。
62
+ ### product docs ハブモデル(設計思想)
58
63
 
59
- > **設計思想(product docs ハブモデル)**:
60
- >
61
- > `product/` はUnit単位で確定済みの仕様を集約する **ハブ** である。
62
- >
63
- > ```
64
- > inception/{unit}/{作業単位}/ 一時設計(US・issue ごと)
65
- > ↓ 設計成果物の反映(累積更新)
66
- > product/construction/{unit}/ 正式設計(常に最新、Unitの真実のソース)
67
- > ↕ フェーズゲート
68
- > scripts/harness/{unit}/*.ts 実装ファイル
69
- > ```
64
+ - **inception → product**: WI の設計成果が確定したら、対応する `product/construction/{unit}/{category}.md` に **累積更新**する(新規ファイルは作らない)
65
+ - **product → src**: ソースの phase-gate は **product docs の存在**で判定する(inception の存在では判定しない)
66
+ - **ソースと WI を直接紐付けない**: 一つのファイルに紐づく WI が増えると依存が複雑化するため、product docs を媒介させて間接的に紐付ける
67
+
68
+ ---
69
+
70
+ ## 3. inception/ — work item と計画の置き場
71
+
72
+ ### 3.1 物理レイアウト(v0.105.0 以降)
73
+
74
+ | 配置先 | 用途 | 例 |
75
+ |---|---|---|
76
+ | `inception/_shared/` | 非 WI の横断計画・戦略・調査メモ | `oss_release_tasklist.md`, `wi-026-remediation-plan.md` |
77
+ | `inception/_cross/{WI-XXX}/` | 複数 Unit に影響する cross-cutting WI | `_cross/WI-026/`, `_cross/WI-031/` |
78
+ | `inception/{unit}/{WI-XXX}/` | 単一 Unit が所有する WI | `validator-system/WI-074/` |
79
+
80
+ > **廃止された配置**(v0.104.0 で物理削除):
81
+ > - `docs/inception/issues/{ISSUE-XXX}/`
82
+ > - `docs/inception/{unit}/issues/{ISSUE-XXX}/`
83
+ > - `docs/inception/{unit}/{US-XXX}/`(旧 US 形式)
70
84
  >
71
- > - **inception product**: US・issue の設計成果が確定したら product docs を累積更新する
72
- > - **product → source**: ソースファイルのフェーズゲートは product docs(Unit単位)の存在で判定する
73
- > - **ソースファイルと US/issue は直接紐付けない**: PJ のライフサイクルが進むほどにバグ修正や US 追加で一つのソースファイルに紐づくドキュメント数が増大し、依存関係が複雑になるため。product docs が常に最新に保たれることで、inception の一時ドキュメントと実装が間接的に紐づく
74
- > - **US/issue 単位で正として管理しない**: 整合性維持のコストが非常に大きくなるため、作業単位の設計は inception にアーカイブ的に保持し、確定した仕様のみを product に集約する
85
+ > 既存資産は `migrate work-items --apply` `WI-XXX` レイアウトに移行済み。`legacy_id` で旧 ID grep 互換性は維持されています。
75
86
 
87
+ ### 3.2 WI frontmatter(必須)
88
+
89
+ 各 WI の `description.md` 先頭に以下の YAML frontmatter を必須とします(L2 metadata validator が検証):
90
+
91
+ ```yaml
92
+ ---
93
+ id: WI-XXX # 必須: WI の一意 ID
94
+ type: story | issue | fix | refactor | chore # 必須: 後述
95
+ severity: trivial | normal | high # 必須
96
+ status: drafted | reflected | implemented | tested # PhaseGate が自動更新
97
+ affects: [unit-a, unit-b] # cross-unit のみ列挙。省略時は所有 Unit のみ
98
+ legacy_id: ISSUE-XXX | US-XXX | H{NN}-{NN} # 任意: 移行用エイリアス
99
+ source: github#123 | slack | internal # 任意: 外部報告源
100
+ ---
76
101
  ```
77
- product/
78
- ├── product_overview.md # プロダクト概要
79
- ├── user_stories.md # ユーザーストーリー一覧
80
- ├── user_story_mapping.md # ストーリーマッピング
81
- ├── construction/ # Unit毎の設計(確定版・累積更新)
82
- │ └── {Unit名}/
83
- │ ├── domain_model.md # ドメインモデル
84
- │ ├── logical_design.md # 論理設計
85
- │ ├── uiux_design.md # UI/UX設計(Unit全体で1ファイル)
86
- │ ├── unit_test_design.md # ユニットテストケース設計
87
- │ ├── it_test_design.md # ITテストケース設計
88
- │ ├── unit_test_logic.md # ユニットテストロジック設計
89
- │ ├── it_test_logic.md # ITテストロジック設計
90
- │ └── coverage_report.md # テストカバレッジレポート
91
- └── units/ # Unit設計ドキュメント
92
- ├── {unit_name}_unit.md # Unit定義
93
- └── integration_contract.md # 統合契約
94
- ```
95
102
 
96
- > **`construction/{Unit名}/` のドキュメントは累積更新される「生きたドキュメント」です。**
97
- > ストーリー実装のたびに、新しい仕様を既存ファイルに追記・更新します。
103
+ ### 3.3 type による要求成果物の段階化
104
+
105
+ WI の重さに応じて、生成必須の成果物が変わります。
106
+
107
+ | `type` | inception 必須成果物 | product 反映 | 用途 |
108
+ |---|---|---|---|
109
+ | `story` | description + logical_design + domain_model + test 設計(+ uiux) | 全カテゴリ累積更新 | 新機能 |
110
+ | `issue` | description + logical_design + domain_model + 関係 test 設計 | 関係カテゴリ累積更新 | バグ・仕様不整合 |
111
+ | `refactor` | description + logical_design(構造変更の意図) | logical_design 更新 | リファクタ |
112
+ | `fix` | description.md + PR link | 関係カテゴリに `@work-item-id` 追記 | typo・依存更新等 |
113
+ | `chore` | description.md 1 行 + PR link | 不要 | 雑用 |
114
+
115
+ `fix` / `chore` は軽量パスとして提供されています。formal な US で起票するには重すぎる修正もここで証跡が残せます。
116
+
117
+ ### 3.4 _shared/ の使い方
118
+
119
+ `inception/_shared/` は **WI に紐付かない計画・調査文書**を置きます。例:
120
+
121
+ - 戦略文書(`oss_public_release_strategy.md`)
122
+ - 横断 remediation 計画(`wi-026-remediation-plan.md`)
123
+ - TDD 実装計画の集約(`configurable_phase_gate_b4_tdd_plan.md`)
124
+
125
+ `_shared/` 配下の文書は WI ではないため `description.md` の frontmatter は不要ですが、L2 metadata validator が staged 時に `@story-id` または `@work-item-id` を要求します。新規作成時は `traceability.initial_creation: true` か該当する `@story-id`(catalog 登録済み H##-##)を付与してください。
98
126
 
99
127
  ---
100
128
 
101
- ## 重要なルール
129
+ ## 4. product/ — 確定設計の正本
102
130
 
103
- ### 1. productには作業単位(US・issue)の設計を入れない
131
+ ### 4.1 構造
104
132
 
105
133
  ```
106
- # NG: product配下にUS-XXX/ISSUE-XXXディレクトリを作成
107
- product/construction/withholding_tax/US-217/
108
- product/construction/withholding_tax/issues/ISSUE-001/
109
-
110
- # OK: inception配下に作成
111
- inception/withholding_tax/US-217/
112
- inception/withholding_tax/issues/ISSUE-001/
134
+ product/
135
+ ├── product_overview.md # プロダクト全体像
136
+ ├── user_stories.md # US / WI catalog(H## ID と WI のマッピングを含む)
137
+ ├── user_story_mapping.md # MVP スコープ・優先順位
138
+ ├── units/
139
+ │ ├── {unit}.md # Unit 定義
140
+ │ └── integration_contract.md # Unit 間統合契約
141
+ └── construction/{unit}/
142
+ ├── domain_model.md # ドメインモデル
143
+ ├── logical_design.md # Hexagonal 論理設計
144
+ ├── uiux_design.md # UI/UX(Unit 全体で 1 ファイル)
145
+ ├── unit_test_design.md # ユニットテストケース設計
146
+ ├── it_test_design.md # IT テストケース設計
147
+ ├── unit_test_logic.md # ユニットテストロジック設計
148
+ ├── it_test_logic.md # IT テストロジック設計
149
+ └── coverage_report.md # カバレッジレポート
113
150
  ```
114
151
 
115
- ### 2. 仕様変更時は既存のproductドキュメントを更新する
152
+ ### 4.2 重要なルール
116
153
 
117
- US 実装や issue 修正で仕様が確定したら、`product/`配下の既存ドキュメント(domain_model.md等)を累積更新する。新規ファイルを作成するのではなく、既存ファイルに変更を追記する。product docs は常に最新の状態を維持する「生きたドキュメント」である。
154
+ 1. **work item ディレクトリを置かない**: `product/construction/{unit}/WI-XXX/` のような階層は作らない(NG)
155
+ 2. **累積更新する**: 新しい WI の設計成果が確定したら **既存の `{category}.md` を編集**する(新規ファイル作成は禁止)
156
+ 3. **`@work-item-id` で反映を宣言**: product 文書内で「この章は WI-XXX に基づく」と機械的に判定するため、該当章の冒頭に `@work-item-id WI-XXX` を記載する
118
157
 
119
- ### 3. ストーリー・issue単位の計画・設計は必ずinception配下に作成する
158
+ ### 4.3 `@work-item-id` の書き方
120
159
 
160
+ ```markdown
161
+ <!-- product/construction/order/logical_design.md -->
162
+
163
+ ## ポート定義
164
+
165
+ <!-- @work-item-id WI-042 -->
166
+ ### OrderRepository Port
167
+ - findById(id: OrderId): Promise<Order>
168
+
169
+ <!-- @work-item-id WI-042, WI-051 -->
170
+ ### PaymentGateway Port
171
+ - charge(amount: Money): Promise<Receipt>
121
172
  ```
122
- # 新しいストーリーUS-999の計画を作成する場合
123
- inception/{該当Unit}/US-999/
124
- ├── logical_design_plan.md
125
- ├── scenario_test_plan.md
126
- ├── scenario_test_design.md
127
- ├── scenario_test_logic.md
128
- ├── uiux_design_plan.md
129
- └── tdd_implementation_plan.md
130
-
131
- # Unit固有のissue(バグ・不整合)を起票する場合
132
- inception/{該当Unit}/issues/ISSUE-999/
133
- ├── issue_description.md
134
- ├── logical_design.md
135
- └── tdd_implementation_plan.md
136
-
137
- # 横断的なissue(複数Unitにまたがる)を起票する場合
138
- inception/issues/ISSUE-999/
139
- ├── issue_description.md
140
- └── logical_design.md
173
+
174
+ カンマ区切りで複数 WI を 1 つのアノテーションにまとめられます。
175
+
176
+ > **legacy 互換**: 既存 product 文書の `@story-id US-XXX` / `@issue-id ISSUE-XXX` / `@story-id H##-##` は WI の `legacy_id` 経由で読み替えられます。一括置換は **しません**(履歴の対応関係を破壊しないため)。新規記述は `@work-item-id WI-XXX` を使ってください。
177
+
178
+ ---
179
+
180
+ ## 5. ソースコードのアノテーション規約
181
+
182
+ `scripts/harness/` 配下のソースファイル先頭に以下を記載します。
183
+
184
+ ```typescript
185
+ // @unit config-foundation
186
+ // @layer domain
187
+ // @work-item-id WI-042 ← 任意(traceability に貢献)
188
+ // @story US-001 ← テストファイルのみ(legacy 互換)
189
+
190
+ export class ConfigSchema { ... }
141
191
  ```
142
192
 
193
+ | タグ | 意味 | 必須性 |
194
+ |---|---|---|
195
+ | `@unit` | このファイルが属する Unit 名 | **必須**(L1-001 が検証) |
196
+ | `@layer` | 層名(preset で定義された値) | **必須**(L1-002 が検証) |
197
+ | `@work-item-id` | このファイル変更を駆動した WI | 任意(traceability で活用) |
198
+ | `@story` | テストが検証する US / WI(legacy 互換) | テストでは推奨 |
199
+
200
+ `@layer` の有効値は `architecture.preset` で決まります(clean / onion / hexagonal / layered / strict-ddd / flat / custom)。
201
+
143
202
  ---
144
203
 
145
- ## ドキュメント作成フロー
204
+ ## 6. ドキュメント作成フロー(AIDLC 準拠)
146
205
 
147
- AIDLCプロセスは **US(新機能)** **issue(バグ・不整合)** の2つの起点を持つ。いずれも inception で計画を立て、product docs を更新し、実装に反映する流れは共通である。
206
+ WI は以下の 5 段階で進行します。各段階で配置先と PhaseGate の挙動が決まっています。
148
207
 
149
- ### US issue の違い
208
+ ### Phase 0 Product / 横断仕様(_cross WI のみ)
150
209
 
151
- | 起点 | フロー | inception 配置先 |
152
- |------|--------|-----------------|
153
- | **US(新機能)** | Phase 1 → Phase 2 → Phase 3 の全フローを上位から順に実行 | `inception/{unit}/{US-XXX}/` |
154
- | **issue(バグ・不整合)** | 原因フェーズを特定し、そのフェーズから下位に向けてドキュメント・実装をアップデート | `inception/{unit}/issues/{ISSUE-XXX}/` |
210
+ **対象**: `docs/product/product_overview.md` / `user_stories.md` / `user_story_mapping.md` / `units/*.md`
155
211
 
156
- #### issue の処理フロー
212
+ `_cross/{WI-XXX}/` かつ `type: story | issue` が戦略・スコープ・Unit 境界に影響する場合、上記いずれかに `@work-item-id WI-XXX` の反映が必要。未反映なら `affects` 全 Unit への Phase 2/3 書き込みをブロック。
157
213
 
158
- 1. **issue 起票**: `inception/{unit}/issues/{ISSUE-XXX}/issue_description.md` に問題の記述・原因分析を記載
159
- 2. **原因フェーズの特定**: バグや仕様の認識違いがどのフェーズに起因するかを判定
160
- - ドメイン設計に起因 → domain_model から下位に向けてリファクタ
161
- - 論理設計に起因 → logical_design から下位に向けてリファクタ
162
- - テスト設計に起因 → test_design から下位に向けてリファクタ
163
- - 実装のみに起因 → 実装の修正のみ
164
- 3. **inception で計画**: 特定したフェーズから下位のフェーズに向けて、inception 配下に計画・設計文書を作成
165
- 4. **product docs 更新**: 設計成果物を `product/construction/{unit}/` の該当ドキュメントに累積更新
166
- 5. **TDD 実装**: テスト設計→実装の順序で修正を適用
214
+ ### Phase 1 Inception(下書き・探索)
167
215
 
168
- > **issue が既存仕様に存在しない追加機能であった場合**: issue ではなく **US を新規作成** し、unit へのマッピングからドメイン設計→TDD 実装まで、下記の Phase 1〜3 の全フローに沿って実施する。
216
+ **対象**: `docs/inception/{unit}/{WI-XXX}/` / `docs/inception/_cross/{WI-XXX}/`
169
217
 
170
- ---
218
+ - WI directory 作成と `description.md` 編集は自由
219
+ - 設計カテゴリ文書(`logical_design.md` 等)が新規作成・実質更新された時点で「反映義務フラグ」が立つ(`status: drafted`)
220
+ - inception 配下のパスへの書き込みは Phase 1 work であり、**Phase 3 reflection check の対象外**(v0.103.0 で確定)
171
221
 
172
- ### US のドキュメント作成フロー
222
+ ### Phase 2 — Product Construction(確定設計の累積)
173
223
 
174
- US は3つのフェーズで構成される。各フェーズでドキュメントの配置先が異なる。
224
+ **対象**: `docs/product/construction/{unit}/{category}.md` / `product/*.md`
175
225
 
176
- ### Phase 1: プロダクト全体設計(横断的・初回)
226
+ - inception の各カテゴリ文書と同カテゴリの product 文書が `@work-item-id WI-XXX` を含み、かつ実質 diff を伴う
227
+ - `_cross/` WI は `affects` 全 Unit について満たす必要あり
177
228
 
178
- プロダクトの全体像を定義し、ストーリー・Unitの構造を確立する。
229
+ ### Phase 3 — Implementation (TDD)
179
230
 
180
- | Step | スキル | 計画(inception) | 成果物(product) |
181
- |------|--------|-------------------|-------------------|
182
- | Step 0 | product-architect | `_shared/product_overview_plan.md` | `product_overview.md` |
183
- | Step 1.1 | story-writer | `_shared/story_writer_plan.md` | `user_stories.md` |
184
- | Step 1.5 | story-mapper | `_shared/story_mapping_plan.md` | `user_story_mapping.md` |
185
- | Step 2 | unit-designer | `_shared/unit_design_plan.md` | `units/{unit_name}.md` + `units/integration_contract.md` |
231
+ **対象**: `scripts/harness/{unit}/(domain|application|infrastructure|presentation)/*.ts`
186
232
 
187
- ### Phase 2: Unit横断設計(Unit単位)
233
+ - 当該 Unit の open な WI のうち、Phase 2 反映が未完なら実装書き込みをブロック
234
+ - `_cross/` WI の `affects` に含まれる Unit は、当該 WI の Phase 0 / 2 反映が完了するまで実装ブロック
188
235
 
189
- 各Unitの設計を確定させる。成果物は`product/construction/{unit}/`に配置される累積更新ドキュメント。
236
+ ### Phase 4 — Test
190
237
 
191
- | Step | スキル | 計画(inception/{unit}/) | 成果物(product/construction/{unit}/) |
192
- |------|--------|--------------------------|----------------------------------------|
193
- | Step 3 | domain-designer | `domain_model_plan.md` | `domain_model.md` |
194
- | Step 4 | logical-designer(横断) | `logical_design_plan.md` | `logical_design.md` |
195
- | Step 5 | scenario-test-designer | → Phase 3で実行 | - |
196
- | Step 5 | it-test-designer | `it_test_design_plan.md` | `it_test_design.md` |
197
- | Step 5 | unit-test-designer | `unit_test_design_plan.md` | `unit_test_design.md` |
198
- | - | test-coverage-checker | `test_coverage_plan.md` | `coverage_report.md` |
199
- | Step 6 | unit-test-logic-designer | `unit_test_logic_plan.md` | `unit_test_logic.md` |
200
- | Step 6 | it-test-logic-designer | `it_test_logic_plan.md` | `it_test_logic.md` |
238
+ **対象**: `scripts/harness/__tests__/(unit|integration)/**/*.test.ts`
201
239
 
202
- ### Phase 3: ストーリー実装(US単位)/ issue 修正
240
+ - product 側の `unit_test_design.md` / `it_test_design.md` に該当 WI の反映があること
241
+ - テストファイルの `@work-item-id` から traceability-model が WI → test カバレッジを算出
203
242
 
204
- 個別ストーリーの設計・テスト・実装。計画・成果物は`inception/{unit}/{US-XXX}/`に配置。
205
- issue の場合は `inception/{unit}/issues/{ISSUE-XXX}/` に配置し、原因フェーズから下位に向けて同様のドキュメントを作成する。
243
+ ---
206
244
 
207
- | Step | スキル | 計画(inception/{unit}/{US-XXX}/) | 成果物配置先 |
208
- |------|--------|-----------------------------------|-------------|
209
- | Step 4 | logical-designer(固有) | `logical_design_plan.md` | `logical_design.md`(同ディレクトリ) |
210
- | Step 5 | scenario-test-designer | `scenario_test_plan.md` | `scenario_test_design.md`(同ディレクトリ) |
211
- | Step 6 | scenario-test-logic-designer | `scenario_test_logic_plan.md` | `scenario_test_logic.md`(同ディレクトリ) |
212
- | Step 7 | uiux-designer | `uiux_design_plan.md` | `product/construction/{unit}/uiux_design.md`(※累積更新) |
213
- | Step 8 | story-implementor | `tdd_implementation_plan.md` | コード(TDD実装) |
214
- | 実装完了後 | - | - | `product/construction/{unit}/` の各ドキュメントを更新 |
245
+ ## 7. State Machine(WI のステータス遷移)
215
246
 
216
- > **uiux_design.mdについて**: 計画はストーリー単位(`inception/{unit}/{US-XXX}/`)に作成するが、
217
- > 成果物は`product/construction/{unit}/uiux_design.md`にUnit全体で1ファイルとして累積更新する。
218
- > これはUI/UXの全体一貫性を保つためで、他のproduct/construction配下のドキュメントと同じルールに従う。
247
+ ```
248
+ DRAFTED inception の必要成果物が type に応じて揃っている
249
+ (Phase 0 / Phase 2 reflection)
250
+ REFLECTED affects 全 Unit の product に @work-item-id 反映済み
251
+ ↓ (Phase 3 implementation)
252
+ IMPLEMENTED scripts/harness 配下に対応実装が存在し lint/type/test green
253
+ ↓ (Phase 4 test)
254
+ TESTED @work-item-id 付きテストが存在し green
255
+ ```
219
256
 
220
- ### 横断的な計画
257
+ - `type: chore` は DRAFTED で完結(product 反映不要、PR trailer のみ)
258
+ - `type: fix` は DRAFTED → REFLECTED(@work-item-id の product 追記)→ IMPLEMENTED の簡略パス
259
+ - `type: story | issue | refactor` はフル状態遷移
260
+
261
+ `status` フィールドは PhaseGate が自動更新します(手動で書き換える必要はありません)。
262
+
263
+ ---
221
264
 
222
- 複数Unitにまたがる計画は `inception/_shared/` に作成する。
265
+ ## 8. WI ID 採番ルール
223
266
 
224
- ### 運用関連
267
+ `migrate work-items --apply` および新規 WI 起票時の採番:
225
268
 
226
- デプロイ、IaC、運用手順は `inception/_operation/` に作成する。
269
+ - 既存 WI 番号は予約(重複しない)
270
+ - 空き番号の **若い順**で sequential allocation
271
+ - legacy ID(`ISSUE-XXX` / `US-XXX` / `H{NN}-{NN}`)が存在する場合、frontmatter の `legacy_id` に保持
272
+
273
+ 詳細は [CLI Reference — Work Item Migration](./guide/cli-reference.md#work-item-migration) を参照。
227
274
 
228
275
  ---
229
276
 
230
- ## ファイル命名規則
277
+ ## 9. ファイル命名規則
231
278
 
232
- | 種別 | 命名パターン | 例 |
233
- |-----|------------|---|
234
- | issue記述 | `issue_description.md` | - |
235
- | 計画 | `*_plan.md` | `domain_model_plan.md` |
279
+ | 種別 | パターン | 例 |
280
+ |---|---|---|
281
+ | WI 記述 | `description.md` | `_cross/WI-026/description.md` |
282
+ | 計画 | `*_plan.md` | `domain_model_plan.md`(inception のみ) |
236
283
  | ドメインモデル | `domain_model.md` | - |
237
284
  | 論理設計 | `logical_design.md` | - |
238
- | UI/UX設計 | `uiux_design.md` | - |
285
+ | UI/UX 設計 | `uiux_design.md` | Unit 全体で 1 ファイル |
239
286
  | シナリオテスト設計 | `scenario_test_design.md` | - |
240
- | ITテスト設計 | `it_test_design.md` | - |
287
+ | IT テスト設計 | `it_test_design.md` | - |
241
288
  | ユニットテスト設計 | `unit_test_design.md` | - |
242
289
  | テストロジック設計 | `*_test_logic.md` | `unit_test_logic.md` |
243
290
  | カバレッジレポート | `coverage_report.md` | - |
244
- | Unit定義 | `{unit_name}_unit.md` | `withholding_tax_unit.md` |
291
+ | Unit 定義 | `{unit}.md` | `withholding_tax.md` |
245
292
  | 統合契約 | `integration_contract.md` | - |
246
293
 
247
294
  ---
248
295
 
296
+ ## 10. アンチパターン
297
+
298
+ | NG | 理由 |
299
+ |---|---|
300
+ | `product/construction/{unit}/WI-XXX/` を作る | product は累積更新の正本。WI ディレクトリは inception のみ |
301
+ | inception/{unit}/issues/ を新規作成する | v0.104.0 で廃止。`{unit}/{WI-XXX}/` を使う |
302
+ | inception/{unit}/{US-XXX}/ を新規作成する | 旧形式。`migrate work-items` で `WI-XXX` に移行 |
303
+ | product 文書に `@story-id US-XXX` を **新規記述**する | 新規は `@work-item-id WI-XXX` を使う(legacy は読み取り互換のみ) |
304
+ | frontmatter の `status` を手動編集する | PhaseGate が自動更新する。手動上書きは状態機械を壊す |
305
+ | `_cross/{WI-XXX}/` の `affects` を省略する | cross-unit WI は必須。省略するとどの Unit の reflection check も発火しない |
306
+
307
+ ---
308
+
249
309
  ## 関連ドキュメント
310
+
250
311
  - [アーキテクチャ哲学](./principles/architecture-philosophy.md)
251
312
  - [テストルール](./principles/testing-rules.md)
313
+ - [CLI Reference — Work Item Migration](./guide/cli-reference.md#work-item-migration)
314
+ - [Configuration — storyReflection / WI gate](./guide/configuration.md)
315
+ - [Layer Model](./guide/layer-model.md)
316
+ - WI 仕様の出典: [`docs/inception/_cross/WI-026/description.md`](./inception/_cross/WI-026/description.md)
@@ -140,6 +140,16 @@ exit code は `0` = 生成成功 / 上書き成功、`2` = 既存ファイルあ
140
140
  WI-026 で導入(v0.100.0、`ISSUE-XXX` 系統)、WI-027 で `H{NN}-{NN}` 形式の旧ストーリー
141
141
  directory にも拡張(v0.105.0)、WI-027 follow-up で apply の冪等性を確立(v0.107.0)。
142
142
 
143
+ > **WI taxonomy の正式仕様**は [`docs/folder_management_rules.md`](../folder_management_rules.md) を参照してください。本セクションは CLI の挙動に焦点を絞ります。
144
+
145
+ ### いつ使うか
146
+
147
+ - **既存リポジトリ**: `docs/inception/issues/` や `{unit}/{US-XXX}/` のような旧形式を残しているプロジェクトを v0.105.0 以降へ更新する初回マイグレーション
148
+ - **新規開発で旧 ID を持ち込む**: 別リポジトリから `ISSUE-XXX` / `H{NN}-{NN}` directory をコピーした後、`legacy_id` を保ったまま `WI-XXX` に統一したいとき
149
+ - **継続運用での再走査**: 既存 WI と新規 directory の混在状態に対し、未採番のものだけ採番する(既存 WI は idempotent skip)
150
+
151
+ 新規 PJ で最初から `WI-XXX` で起票している場合は不要です。
152
+
143
153
  | Command | Options | Description |
144
154
  |---|---|---|
145
155
  | `migrate work-items` | `--dry-run` / `--apply` / `--json` | 旧 directory を `WI-XXX` へ採番移行する。`--dry-run` と `--apply` は排他、どちらかが必須。|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phasegate",
3
- "version": "0.111.0",
3
+ "version": "0.114.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": "MIT",
@@ -2,7 +2,7 @@
2
2
  * @layer infrastructure
3
3
  * @unit phase2-extensions
4
4
  */
5
- import { execSync } from 'node:child_process';
5
+ import { execFileSync } from 'node:child_process';
6
6
  import * as fs from 'node:fs/promises';
7
7
  import * as path from 'node:path';
8
8
  import type { DocumentAgePort } from '../../domain/ports/document-age-port.js';
@@ -17,20 +17,26 @@ export class GitLogDocumentAgeAdapter implements DocumentAgePort {
17
17
  constructor(
18
18
  private readonly projectRoot: string,
19
19
  private readonly nowProvider: () => Date = () => new Date(),
20
+ // WI-035: 配列引数で execFileSync を直接呼ぶことでシェル経由のメタ文字評価を遮断する。
20
21
  private readonly gitLogExecutor: (
21
- command: string,
22
+ file: string,
23
+ args: readonly string[],
22
24
  options: { cwd: string; stdio?: readonly ['pipe', 'pipe', 'pipe'] },
23
- ) => Buffer = execSync,
25
+ ) => Buffer = execFileSync,
24
26
  ) {}
25
27
 
26
28
  async getAge(documentPath: string): Promise<DocumentAge> {
27
29
  try {
28
- const output = this.gitLogExecutor(`git log --format=%ai -1 -- "${documentPath}"`, {
29
- cwd: this.projectRoot,
30
- // ISSUE-005 P1-3: fresh repo では "fatal: your current branch ... does not have
31
- // any commits yet" が 34回 stderr に漏れる。pipe に束ねて静音化する。
32
- stdio: ['pipe', 'pipe', 'pipe'] as const,
33
- })
30
+ const output = this.gitLogExecutor(
31
+ 'git',
32
+ ['log', '--format=%ai', '-1', '--', documentPath],
33
+ {
34
+ cwd: this.projectRoot,
35
+ // ISSUE-005 P1-3: fresh repo では "fatal: your current branch ... does not have
36
+ // any commits yet" が 34回 stderr に漏れる。pipe に束ねて静音化する。
37
+ stdio: ['pipe', 'pipe', 'pipe'] as const,
38
+ },
39
+ )
34
40
  .toString()
35
41
  .trim();
36
42
 
@@ -2,14 +2,16 @@
2
2
  * @layer infrastructure
3
3
  * @unit phase2-extensions
4
4
  */
5
- import { execSync } from 'node:child_process';
5
+ import { execFileSync } from 'node:child_process';
6
6
  import * as fs from 'node:fs/promises';
7
7
  import * as path from 'node:path';
8
8
  import type { InitialCreationAgePort } from '../../domain/ports/initial-creation-age-port.js';
9
9
  import { InitialCreationAge } from '../../domain/value-objects/initial-creation-age.js';
10
10
 
11
+ // WI-035: 配列引数で execFileSync を直接呼ぶことでシェル経由のメタ文字評価を遮断する。
11
12
  type GitExecutor = (
12
- command: string,
13
+ file: string,
14
+ args: readonly string[],
13
15
  options: { cwd: string; stdio?: readonly ['pipe', 'pipe', 'pipe'] },
14
16
  ) => Buffer;
15
17
 
@@ -22,12 +24,12 @@ export class GitLogInitialCreationAgeAdapter implements InitialCreationAgePort {
22
24
  constructor(
23
25
  private readonly projectRoot: string,
24
26
  private readonly nowProvider: () => Date = () => new Date(),
25
- private readonly gitExecutor: GitExecutor = execSync,
27
+ private readonly gitExecutor: GitExecutor = execFileSync,
26
28
  ) {}
27
29
 
28
30
  async getAge(filePath: string): Promise<InitialCreationAge> {
29
- const dateOutput = this.runGit(`git log --diff-filter=A --format=%ai -- "${filePath}"`);
30
- const countOutput = this.runGit(`git rev-list --count HEAD -- "${filePath}"`);
31
+ const dateOutput = this.runGit(['log', '--diff-filter=A', '--format=%ai', '--', filePath]);
32
+ const countOutput = this.runGit(['rev-list', '--count', 'HEAD', '--', filePath]);
31
33
 
32
34
  if (dateOutput !== null && dateOutput.length > 0) {
33
35
  const commitCount = this.parseCount(countOutput);
@@ -42,9 +44,9 @@ export class GitLogInitialCreationAgeAdapter implements InitialCreationAgePort {
42
44
  return this.fileMtimeFallback(filePath);
43
45
  }
44
46
 
45
- private runGit(command: string): string | null {
47
+ private runGit(args: readonly string[]): string | null {
46
48
  try {
47
- return this.gitExecutor(command, {
49
+ return this.gitExecutor('git', args, {
48
50
  cwd: this.projectRoot,
49
51
  // ISSUE-005 P1-3 と同様に、fresh repo の fatal stderr を静音化する。
50
52
  stdio: ['pipe', 'pipe', 'pipe'] as const,