phasegate 0.83.0 → 0.91.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 +144 -0
- package/docs/ADR/ADR-014-presentation-domain-dependency.md +82 -0
- package/package.json +1 -1
- package/scripts/harness/adr-foundation/application/dto/application-errors.ts +0 -13
- package/scripts/harness/agent-integration/domain/ports/error-guidance-query-port.ts +0 -8
- package/scripts/harness/biome-ast-engine/domain/services/rule-definition-registry.ts +1 -0
- package/scripts/harness/biome-ast-engine/domain/value-objects/layer-name.ts +1 -1
- package/scripts/harness/traceability-model/domain/services/metadata-validator.ts +1 -1
- package/scripts/harness/traceability-model/domain/value-objects/story-id.ts +3 -3
- package/scripts/harness/traceability-model/infrastructure/parsers/story-catalog-parser.ts +2 -2
- package/scripts/harness/adr-foundation/application/dto/seed-adr-definition.ts +0 -21
- package/scripts/harness/adr-foundation/application/usecases/seed-initial-adrs-use-case.ts +0 -84
- package/scripts/harness/adr-foundation/infrastructure/seeds/initial-adr-definitions.ts +0 -161
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,150 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.91.0] - 2026-04-23
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **ISSUE-023: `StoryId` validator pattern が `HF\d+-\d{2}` を拒否する** — `HF2-XX` 形式(Phase 2 拡張 Epic)を正式サポート。
|
|
15
|
+
- `scripts/harness/traceability-model/domain/value-objects/story-id.ts`: `STORY_ID_PATTERN` を `/^H(?<epicNumber>F\d+|\d{2})-(?<storyNumber>\d{2})$/` に拡張。エラーメッセージも更新。
|
|
16
|
+
- `scripts/harness/traceability-model/domain/services/metadata-validator.ts:16`: `STORY_ID_PATTERN` を `/^H(?:F\d+|[0-9]{2})-[0-9]{2}$/` に同期。
|
|
17
|
+
- `scripts/harness/traceability-model/infrastructure/parsers/story-catalog-parser.ts`: `STORY_ID_LINE_PATTERN` と前後行コンテキスト形式の内部パターンを同期。`user_stories.md` から `HF2-XX` を StoryCatalog に収集可能に。
|
|
18
|
+
- `StoryId.getEpicNumber()` は `HF2-04` に対して `'F2'` を返す(従来の 2 桁数字は不変)。外部 API shape は維持。
|
|
19
|
+
- **ISSUE-010 完全 CLOSE(副次効果)** — `validate-metadata` FAIL: 103 → **0 件**。`docs/product/construction/` 配下の全 105 設計文書が PASS。Wave 1 (v0.87.0) / Wave 2 (v0.88.0) / Wave 3 (v0.89.0) / fuse-hooks-engine 削除 (v0.90.0) / 本リリースで完結。
|
|
20
|
+
|
|
21
|
+
### Tests
|
|
22
|
+
|
|
23
|
+
- `scripts/harness/__tests__/unit/traceability-model/story-id.test.ts` に HF prefix ケース 3 件追加(3308 → 3311):
|
|
24
|
+
- `HF2-04` を正常に parse できること
|
|
25
|
+
- `HF10-99` のような複数桁 F-prefix も受理すること
|
|
26
|
+
- `HF2-04` の `getEpicNumber()` が `'F2'` を返すこと
|
|
27
|
+
|
|
28
|
+
### Lint / Metadata state
|
|
29
|
+
|
|
30
|
+
- L1 violations: **0 件維持**(scanned 1289 files, no violations)
|
|
31
|
+
- `validate-metadata` FAIL: 7 → **0 件** 🎉
|
|
32
|
+
- 3311 件テスト全 green
|
|
33
|
+
|
|
34
|
+
## [0.90.0] - 2026-04-23
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
|
|
38
|
+
- **fuse-hooks-engine Unit の完全削除** — Unit 定義(`docs/product/units/fuse_hooks_engine_unit.md`)・設計文書(`docs/product/construction/fuse-hooks-engine/` 7 件)・inception プラン(`docs/inception/fuse-hooks-engine/` 配下 8 件)を削除。
|
|
39
|
+
- `scripts/harness/` 配下に実装コードは一切存在せず、他 Unit からの import / 参照もなかった(Future Phase / v1 スコープ外として設計段階で凍結されていた Unit)。
|
|
40
|
+
- `docs/product/user_stories.md` から HF1-01 〜 HF1-05 の 5 ストーリーセクションと `H-F1` Epic 行を削除。v1 合計を 54 維持、全体(Future 含む)を 62 → 57 に更新。
|
|
41
|
+
- `docs/product/units/integration_contract.md` の依存図・Wave 実行計画・Validator ID Registry / CLI Command Registry の `fuse-hooks-engine` 参照を削除。L0 拡張ポイント(6.1 / 6.3)は「OS-level enforcement」の抽象概念として残置。
|
|
42
|
+
- `docs/product/units/agent_integration_unit.md` Stop Hook Adapter 行の `fuse-hooks-engine(Future: FUSE完了ゲートの参照実装)` 参照を `—` に変更。
|
|
43
|
+
- `docs/product/construction/agent-integration/unit_test_design.md` UT-WTS-I021 のサンプルパスを `fuse-hooks-engine/HF1-06` → `some-unit/HF1-06` に変更(WORK_ITEM_ID_PATTERN 後方互換テストは維持)。
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **ISSUE-010 Wave 3 完全解消(fuse-hooks-engine 削除の副次効果)** — `validate-metadata` FAIL: 14 → **7**(fuse-hooks-engine 7 ファイル消失)。残 7 は `phase2-extensions` の `HF2-XX` 形式 StoryId で、validator `STORY_ID_PATTERN = /^H[0-9]{2}-[0-9]{2}$/` の拡張が別 issue 対象。
|
|
48
|
+
|
|
49
|
+
### Lint / Metadata state
|
|
50
|
+
|
|
51
|
+
- L1 violations: **0 件維持**(scanned 1289 files, no violations)
|
|
52
|
+
- `validate-metadata` FAIL: 14 → **7**(-7)
|
|
53
|
+
- 既存 3308 件テスト全 green(regression なし)
|
|
54
|
+
|
|
55
|
+
## [0.89.0] - 2026-04-23
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- **ISSUE-010 Wave 3(partial)** — 11 Unit × 7 設計文書 = 75 件に `@story-id` standalone 注釈を補填し PASS 化。
|
|
60
|
+
- `agent-integration` / `biome-ast-engine` / `ci-governance` / `harness-api` / `harness-error` / `nyquist-validation` / `phase-dependency-model` / `quick-mode` / `regression-suite` / `skill-quality` / `validator-system` の各 Unit の 7 ファイル(`coverage_report.md` / `domain_model.md` / `it_test_design.md` / `it_test_logic.md` / `logical_design.md` / `unit_test_design.md` / `unit_test_logic.md`)に H01-H15 系 StoryId を付与。
|
|
61
|
+
- 残 14 件(`fuse-hooks-engine` 7 + `phase2-extensions` 7)は `HF1-XX` / `HF2-XX` 形式の StoryId を必要とするが、`metadata-validator.STORY_ID_PATTERN = /^H[0-9]{2}-[0-9]{2}$/` が `HF` prefix 非対応のため PASS 化不可能。validator パターン拡張は別 issue 対象(ISSUE-019)として切り出し、本 Wave 3 は partial 完了。
|
|
62
|
+
|
|
63
|
+
### Lint / Metadata state
|
|
64
|
+
|
|
65
|
+
- L1 violations: **0 件維持**
|
|
66
|
+
- `validate-metadata` FAIL: 89 → **14**(-75: 11 Unit × 7 ファイル解消)
|
|
67
|
+
- 残 14 件は HF-prefix validator 制約による既知の限界(新規回帰ではない)
|
|
68
|
+
- 既存 3308 件テスト全 green(regression なし)
|
|
69
|
+
|
|
70
|
+
## [0.88.0] - 2026-04-23
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- **ISSUE-010 Wave 2** — `adr-foundation` / `config-foundation` Unit の設計文書 11 件に `@story-id` 注釈を standalone 形式で補填。
|
|
75
|
+
- adr-foundation 6 件(`coverage_report.md` / `domain_model.md` / `it_test_design.md` / `it_test_logic.md` / `unit_test_design.md` / `unit_test_logic.md`)に `@story-id H05-01 / H05-02 / H05-03` を追加。
|
|
76
|
+
- config-foundation 5 件(`coverage_report.md` / `domain_model.md` / `it_test_logic.md` / `unit_test_design.md` / `unit_test_logic.md`)に `@story-id H04-01 / H04-02 / H04-03` を追加。
|
|
77
|
+
- これにより両 Unit とも全 7 ファイル PASS 達成。
|
|
78
|
+
|
|
79
|
+
### Lint / Metadata state
|
|
80
|
+
|
|
81
|
+
- L1 violations: **0 件維持**
|
|
82
|
+
- `validate-metadata` FAIL: 100 → **89**(adr-foundation 6 件 + config-foundation 5 件解消)
|
|
83
|
+
- 既存 3308 件テスト全 green(regression なし)
|
|
84
|
+
|
|
85
|
+
## [0.87.0] - 2026-04-23
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- **ISSUE-010 Wave 1 + ISSUE-006 formal CLOSE** — traceability-model Unit の `@story-id` 注釈補填と ISSUE-006 機能的完遂の CLOSE 化。
|
|
90
|
+
- ISSUE-010 Wave 1: `docs/product/construction/traceability-model/` 残 3 件(`coverage_report.md` / `domain_model.md` / `unit_test_logic.md`)に `@story-id H03-01 / H03-02 / H03-03` を standalone 注釈として補填。`validate-metadata` の FAIL 件数 103 → 100(traceability-model Unit は 0 件到達)。
|
|
91
|
+
- ISSUE-006 CLOSE: Story A(v0.63.0 / `fullModeRequiredWhen` 設定駆動化)/ Story B(v0.64.0 / pre-tool-use hook 統合)/ P2-3(v0.45.0 / `docs/guide/quick-vs-full-mode.md`)すべて着地済のため formal CLOSE。外部PJ再レビュー(welcome-but-not-blocking)のみ残。
|
|
92
|
+
|
|
93
|
+
### Lint / Metadata state
|
|
94
|
+
|
|
95
|
+
- L1 violations: **0 件維持**(v0.86.0 時点で完全解消済、本版で変更なし)
|
|
96
|
+
- `validate-metadata` FAIL: 103 → **100**(traceability-model 3 件解消)
|
|
97
|
+
- 既存 3308 件テスト全 green(regression なし)
|
|
98
|
+
|
|
99
|
+
## [0.86.0] - 2026-04-23
|
|
100
|
+
|
|
101
|
+
### Changed
|
|
102
|
+
|
|
103
|
+
- **ISSUE-019 / ADR-014** — LayerBoundary の解釈を **Robert C. Martin 版 Clean Architecture** に切り替え、`presentation → domain` 直接依存を許容。
|
|
104
|
+
- 変更: `ALLOWED_DEPENDENCIES.presentation` に `'domain'` を追加(`scripts/harness/biome-ast-engine/domain/value-objects/layer-name.ts:15-20`)。
|
|
105
|
+
- 背景: 従来の厳格 DDD Layered 解釈では presenter / formatter / CLI handler が domain VO / type / policy を read-only で参照するだけで L1-003 違反となっていたが、これは CA では一般的実装。read-only で DIP の本質を侵さない限り許容する。
|
|
106
|
+
- 禁止は継続: `presentation → infrastructure`、`domain → 他層`、`application → presentation` 等の逆方向依存。
|
|
107
|
+
- 緩和策の opt-in 提供は ISSUE-014(アーキ config 化)で対応予定。厳格派は `preset: "strict-ddd"` で現行挙動を維持可能とする。
|
|
108
|
+
- 新規 ADR: `docs/ADR/ADR-014-presentation-domain-dependency.md`。
|
|
109
|
+
- 新規 test: `layer-boundary.test.ts` に presentation→domain allowed、presentation→infrastructure disallowed の 2 ケース追加。
|
|
110
|
+
|
|
111
|
+
### Lint state
|
|
112
|
+
|
|
113
|
+
- total: 8 → **0**(L1-003 presentation→domain 8 件解消、他 rule 増減無し)
|
|
114
|
+
- 既存 3308 件テスト全 green(新規 2 ケース込み)
|
|
115
|
+
|
|
116
|
+
## [0.85.0] - 2026-04-23
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- **ISSUE-022** — Unit barrel (`**/index.ts`) が `no-layer-violation` で誤検知される問題を解消。
|
|
121
|
+
- 問題: ISSUE-017(v0.83.0)の `extractImports` 修正で `export ... from` 再帰走査が有効化された結果、`quick-mode/index.ts` の barrel 再エクスポート 7 件が `L1-003` で新規露出していた。Unit barrel は `main.ts` / `composition-root.ts` / `presentation/*-hook.ts` と同じ composition root / entry point の性質を持つが、`no-layer-violation.ignorePatterns` に含まれていなかった。
|
|
122
|
+
- 修正: `scripts/harness/biome-ast-engine/domain/services/rule-definition-registry.ts` の `no-layer-violation.ignorePatterns` に `'**/index.ts'` を追加。`scripts/harness/*/index.ts` の 11 件の Unit barrel が一括で除外される(sub-layer barrel は存在せず副作用リスク無)。
|
|
123
|
+
- 残 L1-003 8 件は全て `presentation → domain` パターン(ISSUE-019 の philosophical 案件スコープ)。
|
|
124
|
+
|
|
125
|
+
### Lint state
|
|
126
|
+
|
|
127
|
+
- total: 15 → **8**(L1-003 barrel 誤検知 7 件解消)
|
|
128
|
+
- 残 L1-003: 8 件(全て ISSUE-019 スコープ: presentation → domain)
|
|
129
|
+
- 既存 3306 件テスト全 green(regression なし)
|
|
130
|
+
|
|
131
|
+
## [0.84.0] - 2026-04-23
|
|
132
|
+
|
|
133
|
+
### Removed
|
|
134
|
+
|
|
135
|
+
- **L1-006 解消** — `adr-foundation` の never-wired な seed 機能を削除。
|
|
136
|
+
- `scripts/harness/adr-foundation/infrastructure/seeds/initial-adr-definitions.ts` (11 件の seed 定義、docs/ADR/ 13 件の実 ADR と内容不一致で stale だった)
|
|
137
|
+
- `scripts/harness/adr-foundation/application/usecases/seed-initial-adrs-use-case.ts`
|
|
138
|
+
- `scripts/harness/adr-foundation/application/dto/seed-adr-definition.ts`
|
|
139
|
+
- `scripts/harness/__tests__/unit/adr-foundation/seed-initial-adrs-use-case.test.ts` (6 tests)
|
|
140
|
+
- `application-errors.ts` から未使用になった `SeedAdrDefinitionCountError` / `DuplicateAdrIdApplicationError` を削除
|
|
141
|
+
- `infrastructure/seeds/` ディレクトリ自体を削除
|
|
142
|
+
- composition-root に未配線・CLI 未公開だったため外部影響なし。実 ADR は `docs/ADR/` に直接 markdown として管理済み。
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- **L1-007 解消** — `agent-integration/domain/ports/error-guidance-query-port.ts` の JSDoc コメント密度超過を修正。WHAT を説明する冗長コメントを削除(型名から自明)。
|
|
147
|
+
|
|
148
|
+
### Lint state
|
|
149
|
+
|
|
150
|
+
- total: 17 → **15**(L1-006: 1 → 0, L1-007: 1 → 0)
|
|
151
|
+
- 残 L1-003: 15 件(全て ISSUE-019 スコープ: barrel 再エクスポート 7 件 + presentation→domain 8 件)
|
|
152
|
+
- 既存 3312 件 - 6 件削除 = **3306 件** テスト全 green
|
|
153
|
+
|
|
10
154
|
## [0.83.0] - 2026-04-23
|
|
11
155
|
|
|
12
156
|
### Fixed
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# ADR-014: presentation → domain 直接依存を許容する(Robert C. Martin 版 Clean Architecture 準拠)
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted — 2026-04-23
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
ADR-005 で採用した Hexagonal Architecture の派生で、phasegate の L1-003 `no-layer-violation` は当初 **presentation layer は presentation + application にしか依存できない**という厳格 DDD Layered 解釈を採用していた(`scripts/harness/biome-ast-engine/domain/value-objects/layer-name.ts:ALLOWED_DEPENDENCIES`)。
|
|
10
|
+
|
|
11
|
+
しかしこの解釈では、Clean Architecture 実装として一般的な以下のパターンが全て L1-003 違反として flag される:
|
|
12
|
+
|
|
13
|
+
- Presenter が Domain VO の値を読み取って表示用文字列に整形する
|
|
14
|
+
- Formatter が Domain Service(policy 系)の判定を呼んで整形する
|
|
15
|
+
- CLI handler が Domain Type(discriminated union 等)を switch して分岐する
|
|
16
|
+
|
|
17
|
+
ISSUE-019 で監査した時点で 8 件の違反が存在し、いずれも「read-only で VO/type/policy を display/format する」パターンで、Dependency Inversion Principle の本質(domain が外部の詳細に依存しない)は侵していなかった。
|
|
18
|
+
|
|
19
|
+
### 哲学的立場の整理
|
|
20
|
+
|
|
21
|
+
| 派 | `presentation → domain` | 出典 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Robert C. Martin 版 Clean Architecture** | ✅ 許容 | presenter は "Interface Adapters" ring にあり、Entity/VO は Enterprise Business Rules として全 ring から参照可能 |
|
|
24
|
+
| **厳格 DDD Layered** | ❌ 禁止 | presentation は application 経由で DTO を受け取り、domain を直接触らない |
|
|
25
|
+
| **phasegate 旧実装** | ❌ 禁止 | 厳格 DDD 派を採用(実装時の暗黙判断) |
|
|
26
|
+
|
|
27
|
+
## Decision
|
|
28
|
+
|
|
29
|
+
`ALLOWED_DEPENDENCIES.presentation` に `'domain'` を追加し、**Robert C. Martin 版 Clean Architecture の解釈を phasegate 標準とする**:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const ALLOWED_DEPENDENCIES = {
|
|
33
|
+
domain: ['domain'],
|
|
34
|
+
application: ['application', 'domain'],
|
|
35
|
+
infrastructure: ['infrastructure', 'application', 'domain'],
|
|
36
|
+
presentation: ['presentation', 'application', 'domain'], // domain を追加
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 許容される具体パターン
|
|
41
|
+
|
|
42
|
+
- presenter/formatter が Domain VO を read-only で取得して表示用文字列に変換
|
|
43
|
+
- CLI handler が Domain Type を参照して分岐
|
|
44
|
+
- formatter が Domain Service の pure method(副作用なし)を呼んで判定
|
|
45
|
+
|
|
46
|
+
### 依然として禁止されるパターン
|
|
47
|
+
|
|
48
|
+
- presentation → infrastructure の直接依存(DB/CLI/FS 直叩き)
|
|
49
|
+
- presentation から domain VO の mutation(domain は read-only で扱う)
|
|
50
|
+
- domain → presentation / application / infrastructure の逆方向依存(Dependency Inversion の核)
|
|
51
|
+
|
|
52
|
+
`infrastructure → domain` と `application → domain` の既存許容は維持。
|
|
53
|
+
|
|
54
|
+
## Consequences
|
|
55
|
+
|
|
56
|
+
### ポジティブ
|
|
57
|
+
|
|
58
|
+
- 既存 8 件の false positive が解消(L1-003 が 8 → 0 件)
|
|
59
|
+
- phasegate を他 PJ に導入したとき、Robert Martin 流 CA を採用している PJ で摩擦が激減
|
|
60
|
+
- `domain VO の直接 read` を presentation で許容する CA 一般的実装が lint を通るようになる
|
|
61
|
+
|
|
62
|
+
### ネガティブ / トレードオフ
|
|
63
|
+
|
|
64
|
+
- 厳格 DDD 派(presentation → application → domain を強制したい PJ)では緩すぎる
|
|
65
|
+
- **緩和策**: ISSUE-014(アーキテクチャスタイル config 化)で `preset: "strict-ddd"` を選択肢として提供予定。厳格派は opt-in できる
|
|
66
|
+
- presenter が domain mutation を行うリスクは残る
|
|
67
|
+
- **緩和策**: domain VO を immutable(`readonly` + `Object.freeze`)に保つ既存 ADR-009(DDD Tactical Patterns)の規約で抑止
|
|
68
|
+
|
|
69
|
+
### スコープ外(本 ADR で扱わない)
|
|
70
|
+
|
|
71
|
+
- application → presentation などの逆方向(Dependency Inversion 違反)の許容は検討対象外
|
|
72
|
+
- domain から他層への依存の許容は検討対象外
|
|
73
|
+
- preset による選択的緩和(`strict-ddd` / `classic-ca` / `custom` 等)は ISSUE-014 の範疇
|
|
74
|
+
|
|
75
|
+
## 関連
|
|
76
|
+
|
|
77
|
+
- `scripts/harness/biome-ast-engine/domain/value-objects/layer-name.ts:15-20` — ALLOWED_DEPENDENCIES 実体
|
|
78
|
+
- `scripts/harness/biome-ast-engine/domain/value-objects/layer-boundary.ts:31-45` — standardMatrix
|
|
79
|
+
- ADR-005 (Hexagonal Architecture 採用) — 本 ADR はその依存方向規則の一部緩和
|
|
80
|
+
- ADR-009 (DDD Tactical Patterns) — domain immutability 規約で mutation リスクを抑止
|
|
81
|
+
- ISSUE-019 (LayerBoundary 再評価) — 本 ADR で CLOSED
|
|
82
|
+
- ISSUE-014 (architecture style config) — preset 化での opt-in 厳格派提供を予定
|
package/package.json
CHANGED
|
@@ -9,13 +9,6 @@ export class AdrNotFoundApplicationError extends Error {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export class DuplicateAdrIdApplicationError extends Error {
|
|
13
|
-
constructor(adrRef: string) {
|
|
14
|
-
super(`ADR ID が重複しています: ${adrRef}`);
|
|
15
|
-
this.name = 'DuplicateAdrIdApplicationError';
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
12
|
export class SupersededTargetNotFoundApplicationError extends Error {
|
|
20
13
|
constructor(adrRef: string) {
|
|
21
14
|
super(`superseded_by の参照先ADRが存在しません: ${adrRef}`);
|
|
@@ -51,9 +44,3 @@ export class InvalidAdrDateError extends Error {
|
|
|
51
44
|
}
|
|
52
45
|
}
|
|
53
46
|
|
|
54
|
-
export class SeedAdrDefinitionCountError extends Error {
|
|
55
|
-
constructor(actualCount: number) {
|
|
56
|
-
super(`初期ADR定義は11件である必要があります: ${actualCount}`);
|
|
57
|
-
this.name = 'SeedAdrDefinitionCountError';
|
|
58
|
-
}
|
|
59
|
-
}
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
// @unit agent-integration
|
|
2
2
|
// @layer domain
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* phase-gate 等のエラーに紐づく actionable なガイダンス情報
|
|
6
|
-
* (harness-error Unit の ErrorDefinition.defaultSuggestedSkill 等から供給される)
|
|
7
|
-
*/
|
|
8
4
|
export interface ErrorGuidance {
|
|
9
5
|
readonly suggestedSkill: string | null;
|
|
10
6
|
readonly scaffoldCommand: string | null;
|
|
11
7
|
readonly templatePath: string | null;
|
|
12
8
|
}
|
|
13
9
|
|
|
14
|
-
/**
|
|
15
|
-
* エラーコード → actionable guidance の lookup を行う port
|
|
16
|
-
* 実装は harness-error Unit の ErrorDefinitionRegistry を参照する
|
|
17
|
-
*/
|
|
18
10
|
export interface ErrorGuidanceQueryPort {
|
|
19
11
|
getGuidance(errorCode: string): Promise<ErrorGuidance | null>;
|
|
20
12
|
}
|
|
@@ -16,7 +16,7 @@ const ALLOWED_DEPENDENCIES: Readonly<Record<LayerNameValue, readonly LayerNameVa
|
|
|
16
16
|
domain: Object.freeze(['domain']),
|
|
17
17
|
application: Object.freeze(['application', 'domain']),
|
|
18
18
|
infrastructure: Object.freeze(['infrastructure', 'application', 'domain']),
|
|
19
|
-
presentation: Object.freeze(['presentation', 'application']),
|
|
19
|
+
presentation: Object.freeze(['presentation', 'application', 'domain']),
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export class InvalidLayerNameError extends Error {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import type { StoryIdLike } from '../value-objects/story-reference.js';
|
|
14
14
|
import type { StoryIdAnnotation } from '../value-objects/story-id-annotation.js';
|
|
15
15
|
|
|
16
|
-
const STORY_ID_PATTERN = /^H[0-9]{2}-[0-9]{2}$/;
|
|
16
|
+
const STORY_ID_PATTERN = /^H(?:F\d+|[0-9]{2})-[0-9]{2}$/;
|
|
17
17
|
const VALID_LAYER_NAMES = new Set([
|
|
18
18
|
'domain',
|
|
19
19
|
'application',
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* @layer domain
|
|
3
3
|
* @unit traceability-model
|
|
4
4
|
*
|
|
5
|
-
* HXX-XX形式の正規ストーリーID
|
|
5
|
+
* HXX-XX形式の正規ストーリーID(Phase 2 拡張 Epic として HF\d+-XX も許容)
|
|
6
6
|
*/
|
|
7
|
-
const STORY_ID_PATTERN = /^H(?<epicNumber>
|
|
7
|
+
const STORY_ID_PATTERN = /^H(?<epicNumber>F\d+|\d{2})-(?<storyNumber>\d{2})$/;
|
|
8
8
|
|
|
9
9
|
export class StoryIdFormatError extends Error {
|
|
10
10
|
constructor(value: string) {
|
|
11
|
-
super(`StoryIdはHXX-XX
|
|
11
|
+
super(`StoryIdはHXX-XX形式(HF\\d+-XX も可)で指定してください: ${value}`);
|
|
12
12
|
this.name = 'StoryIdFormatError';
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -10,7 +10,7 @@ export interface ParsedStoryCatalog {
|
|
|
10
10
|
readonly aliasMap: ReadonlyMap<string, string>;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const STORY_ID_LINE_PATTERN = /\bH[0-9]{2}-[0-9]{2}\b/g;
|
|
13
|
+
const STORY_ID_LINE_PATTERN = /\bH(?:F\d+|[0-9]{2})-[0-9]{2}\b/g;
|
|
14
14
|
const TABLE_ALIAS_PATTERN =
|
|
15
15
|
/\|\s*(H[0-9]{2}-[0-9]{2})\s*\|.*?\|\s*(US-[0-9]{3})\s*\|/g;
|
|
16
16
|
const INLINE_ALIAS_PATTERN =
|
|
@@ -58,7 +58,7 @@ export function parseStoryCatalog(content: string): ParsedStoryCatalog {
|
|
|
58
58
|
|
|
59
59
|
// 前後行コンテキスト形式: H03-01 の直後に 旧US: US-001
|
|
60
60
|
for (let i = 0; i < lines.length; i++) {
|
|
61
|
-
const storyIdMatch = /\b(H[0-9]{2}-[0-9]{2})\b/.exec(lines[i]);
|
|
61
|
+
const storyIdMatch = /\b(H(?:F\d+|[0-9]{2})-[0-9]{2})\b/.exec(lines[i]);
|
|
62
62
|
if (storyIdMatch) {
|
|
63
63
|
const nextLine = i + 1 < lines.length ? lines[i + 1] : '';
|
|
64
64
|
const legacyMatch = /旧US\s*[::]\s*(US-[0-9]{3})/.exec(nextLine);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @layer application
|
|
3
|
-
* @unit adr-foundation
|
|
4
|
-
*/
|
|
5
|
-
export interface SeedAdrDefinition {
|
|
6
|
-
readonly title: string;
|
|
7
|
-
readonly status: 'Proposed' | 'Accepted' | 'Deprecated' | 'Superseded';
|
|
8
|
-
readonly date: string;
|
|
9
|
-
readonly body: {
|
|
10
|
-
readonly context: string;
|
|
11
|
-
readonly decision: string;
|
|
12
|
-
readonly consequences: string;
|
|
13
|
-
readonly alternatives?: string;
|
|
14
|
-
};
|
|
15
|
-
readonly archgate?: {
|
|
16
|
-
readonly enforcedBy: ReadonlyArray<{
|
|
17
|
-
readonly validatorId: string;
|
|
18
|
-
readonly errorCode: string;
|
|
19
|
-
}>;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @layer application
|
|
3
|
-
* @unit adr-foundation
|
|
4
|
-
*/
|
|
5
|
-
import { ADR } from '../../domain/aggregates/adr.js';
|
|
6
|
-
import type { AdrDocumentParserPort } from '../../domain/ports/adr-document-parser-port.js';
|
|
7
|
-
import type { AdrRepositoryPort } from '../../domain/ports/adr-repository-port.js';
|
|
8
|
-
import { AdrValidationService } from '../../domain/services/adr-validation-service.js';
|
|
9
|
-
import { AdrId } from '../../domain/value-objects/adr-id.js';
|
|
10
|
-
import {
|
|
11
|
-
DuplicateAdrIdApplicationError,
|
|
12
|
-
SeedAdrDefinitionCountError,
|
|
13
|
-
} from '../dto/application-errors.js';
|
|
14
|
-
import type { SeedAdrDefinition } from '../dto/seed-adr-definition.js';
|
|
15
|
-
|
|
16
|
-
export interface SeedInitialAdrsInput {
|
|
17
|
-
readonly definitions: SeedAdrDefinition[];
|
|
18
|
-
readonly overwrite?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface SeedInitialAdrsOutput {
|
|
22
|
-
readonly created: readonly string[];
|
|
23
|
-
readonly skipped: readonly string[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class SeedInitialAdrsUseCase {
|
|
27
|
-
constructor(
|
|
28
|
-
private readonly adrRepository: AdrRepositoryPort,
|
|
29
|
-
private readonly documentParser: AdrDocumentParserPort,
|
|
30
|
-
) {}
|
|
31
|
-
|
|
32
|
-
async execute(input: SeedInitialAdrsInput): Promise<Readonly<SeedInitialAdrsOutput>> {
|
|
33
|
-
if (input.definitions.length !== 11) {
|
|
34
|
-
throw new SeedAdrDefinitionCountError(input.definitions.length);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const created: string[] = [];
|
|
38
|
-
const skipped: string[] = [];
|
|
39
|
-
|
|
40
|
-
for (const [index, definition] of input.definitions.entries()) {
|
|
41
|
-
const adrId = AdrId.create(String(index + 1).padStart(3, '0'));
|
|
42
|
-
const adrRef = adrId.toAdrRef();
|
|
43
|
-
|
|
44
|
-
if (created.includes(adrRef) || skipped.includes(adrRef)) {
|
|
45
|
-
throw new DuplicateAdrIdApplicationError(adrRef);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const adr = ADR.create(
|
|
49
|
-
{
|
|
50
|
-
adr_id: adrId.value,
|
|
51
|
-
title: definition.title,
|
|
52
|
-
status: definition.status,
|
|
53
|
-
date: definition.date,
|
|
54
|
-
archgate: definition.archgate
|
|
55
|
-
? {
|
|
56
|
-
adr_id: adrId.value,
|
|
57
|
-
enforced_by: definition.archgate.enforcedBy.map((entry) => ({
|
|
58
|
-
validator_id: entry.validatorId,
|
|
59
|
-
error_code: entry.errorCode,
|
|
60
|
-
})),
|
|
61
|
-
}
|
|
62
|
-
: undefined,
|
|
63
|
-
},
|
|
64
|
-
definition.body,
|
|
65
|
-
new AdrValidationService(),
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
const exists = await this.adrRepository.exists(adrId);
|
|
69
|
-
if (exists && input.overwrite !== true) {
|
|
70
|
-
skipped.push(adrRef);
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this.documentParser.serializeDocument(adr);
|
|
75
|
-
await this.adrRepository.save(adr);
|
|
76
|
-
created.push(adrRef);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return Object.freeze({
|
|
80
|
-
created: Object.freeze(created),
|
|
81
|
-
skipped: Object.freeze(skipped),
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @layer infrastructure
|
|
3
|
-
* @unit adr-foundation
|
|
4
|
-
*/
|
|
5
|
-
import type { SeedAdrDefinition } from '../../application/dto/seed-adr-definition.js';
|
|
6
|
-
|
|
7
|
-
export const INITIAL_ADR_DEFINITIONS: readonly SeedAdrDefinition[] = [
|
|
8
|
-
{
|
|
9
|
-
title: 'Package separation',
|
|
10
|
-
status: 'Accepted',
|
|
11
|
-
date: '2026-03-13',
|
|
12
|
-
body: {
|
|
13
|
-
context:
|
|
14
|
-
'The harness codebase has grown beyond a single-package structure. Build times increase and cross-cutting changes create unnecessary coupling.',
|
|
15
|
-
decision:
|
|
16
|
-
'Separate the repository into discrete packages aligned with bounded contexts, each with its own build and test lifecycle.',
|
|
17
|
-
consequences:
|
|
18
|
-
'Packages can evolve independently. CI must orchestrate multi-package builds. Shared kernel contracts must be explicitly published.',
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
title: 'Full migration from ESLint to Biome',
|
|
23
|
-
status: 'Accepted',
|
|
24
|
-
date: '2026-03-13',
|
|
25
|
-
body: {
|
|
26
|
-
context:
|
|
27
|
-
'The project currently uses ESLint for linting. Biome offers faster execution and unified formatting with linting in a single tool.',
|
|
28
|
-
decision:
|
|
29
|
-
'Migrate all linting and formatting from ESLint and Prettier to Biome as the sole toolchain.',
|
|
30
|
-
consequences:
|
|
31
|
-
'Tooling becomes simpler and faster. Custom ESLint rules must be re-implemented as Biome plugins or GritQL patterns.',
|
|
32
|
-
alternatives:
|
|
33
|
-
'Keep dual toolchain with ESLint for rules not yet supported by Biome.',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
title: 'Quality harness owns K1-K13',
|
|
38
|
-
status: 'Accepted',
|
|
39
|
-
date: '2026-03-13',
|
|
40
|
-
body: {
|
|
41
|
-
context:
|
|
42
|
-
'Quality indicators K1 through K13 are defined across multiple documents with no single owner enforcing them.',
|
|
43
|
-
decision:
|
|
44
|
-
'The quality harness unit owns the enforcement of all K1-K13 indicators, providing validators and gates for each.',
|
|
45
|
-
consequences:
|
|
46
|
-
'A single unit is accountable for quality enforcement. Other units must integrate through the harness contract rather than implementing ad-hoc checks.',
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
title: 'FUSE Hooks Engine is out of v1 scope',
|
|
51
|
-
status: 'Proposed',
|
|
52
|
-
date: '2026-03-13',
|
|
53
|
-
body: {
|
|
54
|
-
context:
|
|
55
|
-
'The FUSE Hooks Engine provides extensible event-driven hooks but adds significant complexity to the initial delivery.',
|
|
56
|
-
decision:
|
|
57
|
-
'Defer the FUSE Hooks Engine to a post-v1 phase. The v1 harness will use direct invocation patterns.',
|
|
58
|
-
consequences:
|
|
59
|
-
'Reduced initial scope and risk. Hook-based extensibility will require a migration path when introduced later.',
|
|
60
|
-
alternatives:
|
|
61
|
-
'Include a minimal hooks engine in v1 with limited extensibility.',
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
title: 'HarnessError requires fix_example',
|
|
66
|
-
status: 'Accepted',
|
|
67
|
-
date: '2026-03-13',
|
|
68
|
-
body: {
|
|
69
|
-
context:
|
|
70
|
-
'Developers receiving harness errors often lack actionable guidance on how to resolve violations.',
|
|
71
|
-
decision:
|
|
72
|
-
'Every HarnessError definition must include a fix_example field demonstrating the corrective action.',
|
|
73
|
-
consequences:
|
|
74
|
-
'Error definitions are more verbose but significantly more useful. All existing error definitions must be updated to include examples.',
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
title: 'Strict quick mode eligibility',
|
|
79
|
-
status: 'Accepted',
|
|
80
|
-
date: '2026-03-13',
|
|
81
|
-
body: {
|
|
82
|
-
context:
|
|
83
|
-
'Quick mode bypasses expensive validators but must not compromise quality gates for critical changes.',
|
|
84
|
-
decision:
|
|
85
|
-
'Define strict eligibility criteria for quick mode based on file change scope and affected layers.',
|
|
86
|
-
consequences:
|
|
87
|
-
'Quick mode runs faster for eligible changes. Complex cross-layer changes always run the full validator stack.',
|
|
88
|
-
alternatives:
|
|
89
|
-
'Allow developers to manually opt into quick mode regardless of change scope.',
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
title: 'Separate config files',
|
|
94
|
-
status: 'Accepted',
|
|
95
|
-
date: '2026-03-13',
|
|
96
|
-
body: {
|
|
97
|
-
context:
|
|
98
|
-
'A single monolithic configuration file makes it difficult to manage unit-specific settings and increases merge conflicts.',
|
|
99
|
-
decision:
|
|
100
|
-
'Split configuration into separate files per concern: phasegate.config.json for core settings, with unit-specific overrides.',
|
|
101
|
-
consequences:
|
|
102
|
-
'Configuration is modular and easier to maintain. The config loader must implement a merge strategy for layered configs.',
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
title: 'Nyquist integration for truths and artifacts',
|
|
107
|
-
status: 'Proposed',
|
|
108
|
-
date: '2026-03-13',
|
|
109
|
-
body: {
|
|
110
|
-
context:
|
|
111
|
-
'Nyquist provides a truth-source registry and artifact tracking system that could centralize harness state management.',
|
|
112
|
-
decision:
|
|
113
|
-
'Integrate with Nyquist for truth registration and artifact lifecycle tracking.',
|
|
114
|
-
consequences:
|
|
115
|
-
'Harness gains a centralized truth source. A dependency on Nyquist availability is introduced.',
|
|
116
|
-
alternatives:
|
|
117
|
-
'Build a standalone truth registry within the harness codebase.',
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
title: 'Artifact-driven state derivation',
|
|
122
|
-
status: 'Accepted',
|
|
123
|
-
date: '2026-03-13',
|
|
124
|
-
body: {
|
|
125
|
-
context:
|
|
126
|
-
'Harness state is currently computed on-the-fly, leading to inconsistent results across different invocation points.',
|
|
127
|
-
decision:
|
|
128
|
-
'Derive harness state exclusively from persisted artifacts, making state deterministic and reproducible.',
|
|
129
|
-
consequences:
|
|
130
|
-
'State becomes auditable and cacheable. All state-changing operations must produce artifacts as their primary output.',
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
title: 'Validator stack detection',
|
|
135
|
-
status: 'Accepted',
|
|
136
|
-
date: '2026-03-13',
|
|
137
|
-
body: {
|
|
138
|
-
context:
|
|
139
|
-
'Validators are registered individually, but their execution order and dependencies are not explicitly managed.',
|
|
140
|
-
decision:
|
|
141
|
-
'Implement automatic validator stack detection that resolves execution order based on declared dependencies and layer constraints.',
|
|
142
|
-
consequences:
|
|
143
|
-
'Validator execution order is deterministic and verifiable. Circular dependencies are detected at registration time.',
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
title: 'Temporary 4-layer definition with return path to 5-layer',
|
|
148
|
-
status: 'Proposed',
|
|
149
|
-
date: '2026-03-13',
|
|
150
|
-
body: {
|
|
151
|
-
context:
|
|
152
|
-
'The target architecture defines 5 layers, but the current codebase structure and team familiarity support only 4 layers.',
|
|
153
|
-
decision:
|
|
154
|
-
'Adopt a temporary 4-layer definition (domain, application, infrastructure, presentation) with a documented return path to the 5-layer target.',
|
|
155
|
-
consequences:
|
|
156
|
-
'Initial implementation is simpler. The migration plan to 5 layers must be maintained and reviewed periodically.',
|
|
157
|
-
alternatives:
|
|
158
|
-
'Adopt the full 5-layer structure from the start despite the complexity cost.',
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
] as const;
|