phasegate 0.121.0 → 0.123.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,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.123.0] - 2026-05-08
11
+
12
+ ### Added
13
+
14
+ - **WI-088 Phase A — bundled guidance skill `phasegate-toolkit-guide`** — phasegate を導入したプロジェクトで AI エージェントが phasegate ツールキット自体の概念 (L0-L4 / 防御プリセット / アーキプリセット / Quick Mode / Hook 仕様 / config 全般) について質問されたとき、`node_modules/phasegate/docs/guide/` 配下の canonical doc を読み込んで正確に回答するための skill を追加。
15
+ - **設計原則 (stale 回避)**: SKILL 本体に概念知識を固定せず、概念カテゴリごとに canonical doc へのポインタのみを記述。`npm update phasegate` で knowledge が自動追従する構造。
16
+ - **新規ファイル**: `skills/phasegate-toolkit-guide/SKILL.md` を `skill-creator` スキル (`init_skill.py`) 経由で作成 (validation pass)。9 概念カテゴリ (L0-L4 layer model / preset 2 系統 / Quick vs Full Mode / hook 仕様 / config 全般 / CLI / installation / skills overview / codex integration) ごとに `docs/guide/*.md` への参照を整理。
17
+ - **skill-deployer 拡張**: `scripts/harness/setup/skill-deployer.ts` の `SkillCategory` type union に `"guidance"` を追加、`SKILL_CATEGORIES.guidance = ["phasegate-toolkit-guide"]` を登録、`getSkillsForSet("all")` の返り値に guidance カテゴリを含めた。`getSkillsForSet("core")` には含めない (core は continuous governance 用、guidance は ad-hoc Q&A 用なので責務分離)。
18
+ - **テスト追加**: 4 ケース (`scripts/harness/__tests__/unit/setup/skill-deployer.test.ts` に `SKILL_CATEGORIES.guidance` 登録 / `getCategoryForSkill('phasegate-toolkit-guide') === 'guidance'` / `getSkillsForSet('all')` に含まれる / `getSkillsForSet('core')` に含まれない)。全 3495 テスト (前回 3491 + 新規 4) グリーン。
19
+ - **互換性**: 既存 deploy ロジックに変更なし、`getSkillsForSet("core")` の返り値も変更なし。consumer プロジェクトで `phasegate init` 実行時、`.claude/skills/` 配下に `phasegate-toolkit-guide` が追加 deploy されるのみ。
20
+
21
+ ## [0.122.0] - 2026-05-08
22
+
23
+ ### Added
24
+
25
+ - **WI-087 Phase C-2 — Stop hook strict mode (`agentIntegration.stopHook.enforce`)** — 外部レポーター nakataj-mti が GitHub Issue [#3](https://github.com/junpei-9898/phasegate/issues/3) finding #4 で報告した「`phasegate hook stop` が Complete Check 失敗時に exit 1 を返すが、Claude Code の Stop hook block には exit 2 が必要」問題を解消。新 config flag `agentIntegration.stopHook.enforce: boolean` (default `false`) を v3 schema に追加し、true セット時のみ Complete Check 失敗で **exit 2 + `{"decision":"block","reason":"Complete Check failed (exitCode=N)"}`** を出力する strict mode に切り替わる。default は従来挙動 (exit cliResult.exitCode、stderr メッセージのみ) を完全維持。
26
+ - **schema 拡張**: `scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json` に top-level `agentIntegration.stopHook.enforce: boolean` を追加 (`additionalProperties: false`)。boolean 以外 / 未定義 key は AJV validator が reject。
27
+ - **新ポートメソッド**: `ConfigQueryPort.getStopHookEnforce(): Promise<boolean>` を追加 (`scripts/harness/agent-integration/domain/ports/config-query-port.ts`)。
28
+ - **infrastructure 実装**: `HarnessConfigConfigQueryAdapter.getStopHookEnforce()` が `agentIntegration.stopHook.enforce === true` のときのみ true を返す strict 一致判定。
29
+ - **application 拡張**: `HandleStopOutput` DTO に `shouldEnforceFailure?: boolean` を追加。`HandleStopUseCase.execute` 内で `enforce && cliResult.exitCode !== 0` の合成条件を populate。reentry 検出時は populate されない (現行挙動保持)。
30
+ - **presentation 分岐拡張**: `stop-hook.ts` で `output.shouldEnforceFailure === true` のとき stdout に decision JSON 出力 + stderr に reason 付きメッセージ + exit 2。それ以外は現行通り cliResult.exitCode で抜ける。
31
+ - **テスト追加**: 11 ケース (`ajv-config-schema-validator-v3.test.ts` +5、`harness-config-config-query-adapter.test.ts` +2、`handle-stop-usecase.test.ts` +4)。全 3491 テスト (前回 3480 + 新規 11) グリーン。
32
+ - **dogfood 検証**: phasegate 自身の `phasegate.config.json` に `enforce: true` を一時注入し `stop-hook.ts` を手動実行 → exit 2 + decision JSON 出力を確認。enforce 削除後は exit 1 + decision JSON なしの後方互換挙動を確認。
33
+ - **既存テストへの影響**: `ConfigQueryPort` インターフェース拡張に伴い、`handle-pre-tool-use-usecase.test.ts` / `handle-post-tool-use-usecase.test.ts` / `handle-stop-usecase.test.ts` / `ci-governance-baseline-grandfather-adapter.test.ts` の mock literal に `getStopHookEnforce: vi.fn().mockResolvedValue(false)` を追加 (default 後方互換を維持しつつ TypeScript 型契約を満たす)。
34
+ - **ドキュメント整合**: `docs/guide/configuration.md` に `agentIntegration` セクションを追加 (sub-field 表 + 用途説明)、`docs/guide/hooks-integration.md` の Stop hook 説明に enforce オプションを追記。
35
+ - **互換性**: 既存 v2/v3 config (agentIntegration セクション不在) は default false で v0.121.0 以前と完全同一挙動。schema validator 経路 / ConfigQueryPort 既存メソッド経路への影響なし。
36
+
10
37
  ## [0.121.0] - 2026-05-07
11
38
 
12
39
  ### Fixed
@@ -416,6 +416,28 @@ Introduced in ISSUE-007 Wave 1 (v0.65.0) and wired into the pre-tool-use hook by
416
416
 
417
417
  Generate or refresh the snapshot with `npx phasegate baseline` (`--dry-run` to inspect, `--force` to overwrite, `--paths <glob,glob,...>` to scope, `--json` for CI-friendly output). See the [Baseline section in CLI Reference](cli-reference.md#baseline-retrofit-grandfather) for details.
418
418
 
419
+ #### `agentIntegration` (Stop hook strict mode)
420
+
421
+ Controls how phasegate's agent-side hooks integrate with Claude Code. Currently only `stopHook.enforce` is exposed.
422
+
423
+ ```jsonc
424
+ {
425
+ "agentIntegration": {
426
+ "stopHook": {
427
+ "enforce": true
428
+ }
429
+ }
430
+ }
431
+ ```
432
+
433
+ | Sub-field | Type | Default | Description |
434
+ |--------------------|-----------|---------|----------------------------------------------------------------------------------------------------------------------|
435
+ | `stopHook.enforce` | `boolean` | `false` | When `true`, a non-zero exit from `phasegate:complete-check` causes the Stop hook to emit `{"decision":"block","reason":"Complete Check failed (exitCode=N)"}` on stdout and exit with code 2, blocking Claude Code's turn. When `false` (default), the hook exits with the inner CLI's exit code, which Claude Code surfaces only as a transcript warning. |
436
+
437
+ Use `enforce: true` when your team treats Complete Check failures as hard gates (e.g., disallow ending a session with failing tests or lint). Leave it as default `false` for an opt-in / advisory experience.
438
+
439
+ Reentry-detection cases (`REENTRY_DETECTED`) always exit with code 0 regardless of this setting; strict mode applies only to actual Complete Check failures.
440
+
419
441
  ---
420
442
 
421
443
  ### Quick Mode
@@ -91,7 +91,8 @@ Use /quick-implementor skill for version changes in package.json.
91
91
 
92
92
  ### Stop (before session end)
93
93
  - Runs `phasegate:complete-check` (L2-L4 full validation)
94
- - Session end is held if checks are not all green
94
+ - By default, the hook exits with the inner CLI's exit code, which Claude Code shows as a transcript warning but does not turn-block on.
95
+ - Set `agentIntegration.stopHook.enforce: true` in `phasegate.config.json` to enable **strict mode**: on Complete Check failure, the hook emits `{"decision":"block","reason":"Complete Check failed (exitCode=N)"}` on stdout and exits with code 2, hard-blocking Claude Code's turn end. Reentry-detection still exits 0 regardless of this setting. See `docs/guide/configuration.md` `agentIntegration` section for details.
95
96
 
96
97
  ## Optional Shell Script Hooks
97
98
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phasegate",
3
- "version": "0.121.0",
3
+ "version": "0.123.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",
@@ -14,4 +14,5 @@ export interface HandleStopOutput {
14
14
  executed: boolean;
15
15
  skipReason?: SkipReason;
16
16
  cliResult?: CliExecutionResult;
17
+ shouldEnforceFailure?: boolean;
17
18
  }
@@ -69,9 +69,13 @@ export class HandleStopUseCase {
69
69
 
70
70
  try {
71
71
  const cliResult = await this.cliExecutorPort.execute('phasegate:complete-check', []);
72
+ // WI-087 finding #4: enforce=true かつ Complete Check 失敗時のみ shouldEnforceFailure=true
73
+ const enforce = await this.configQueryPort.getStopHookEnforce();
74
+ const shouldEnforceFailure = enforce && cliResult.exitCode !== 0;
72
75
  return {
73
76
  executed: true,
74
77
  cliResult,
78
+ shouldEnforceFailure,
75
79
  };
76
80
  } finally {
77
81
  // deactivate は成否問わず必ず実行(finally保証)
@@ -17,4 +17,7 @@ export interface ConfigQueryPort {
17
17
  getRelaxedGates(): Promise<readonly string[]>;
18
18
  getProjectPaths(): ProjectPaths;
19
19
  getBaselineConfig(): Promise<BaselineConfig>;
20
+ // WI-087 finding #4: Stop hook strict mode 設定。true なら Complete Check 失敗時に
21
+ // exit 2 + decision JSON を出して Claude Code セッションを block する。
22
+ getStopHookEnforce(): Promise<boolean>;
20
23
  }
@@ -48,12 +48,21 @@ interface BaselineSection {
48
48
  path?: string;
49
49
  }
50
50
 
51
+ interface AgentIntegrationStopHookSection {
52
+ enforce?: boolean;
53
+ }
54
+
55
+ interface AgentIntegrationSection {
56
+ stopHook?: AgentIntegrationStopHookSection;
57
+ }
58
+
51
59
  interface HarnessConfigDocument {
52
60
  harnesses?: HarnessesSection;
53
61
  project?: ProjectSection;
54
62
  protectedFiles?: ProtectedFilesSection;
55
63
  quickMode?: QuickModeSection;
56
64
  baseline?: BaselineSection;
65
+ agentIntegration?: AgentIntegrationSection;
57
66
  }
58
67
 
59
68
  export class HarnessConfigConfigQueryAdapter implements ConfigQueryPort {
@@ -128,4 +137,11 @@ export class HarnessConfigConfigQueryAdapter implements ConfigQueryPort {
128
137
  path: baseline.path ?? '.phasegate/baseline.json',
129
138
  };
130
139
  }
140
+
141
+ async getStopHookEnforce(): Promise<boolean> {
142
+ const config = this.loadConfig();
143
+ const enforce = config.agentIntegration?.stopHook?.enforce;
144
+ // type guard: boolean 以外(schema validator ですり抜ける null/undefined を含む)は false にフォールバック
145
+ return enforce === true;
146
+ }
131
147
  }
@@ -88,6 +88,15 @@ async function main(): Promise<void> {
88
88
 
89
89
  if (output.executed && output.cliResult) {
90
90
  if (output.cliResult.exitCode !== 0) {
91
+ // WI-087 finding #4: enforce=true なら exit 2 + decision JSON で turn block
92
+ if (output.shouldEnforceFailure === true) {
93
+ const reason = `Complete Check failed (exitCode=${output.cliResult.exitCode})`;
94
+ process.stdout.write(`${JSON.stringify({ decision: 'block', reason })}\n`);
95
+ process.stderr.write(
96
+ `Complete Check失敗 (exitCode=${output.cliResult.exitCode}) — strict mode により turn を block します\n`,
97
+ );
98
+ process.exit(2);
99
+ }
91
100
  process.stderr.write(`Complete Check失敗 (exitCode=${output.cliResult.exitCode})\n`);
92
101
  }
93
102
  process.exit(output.cliResult.exitCode);
@@ -482,6 +482,21 @@
482
482
  }
483
483
  }
484
484
  },
485
+ "agentIntegration": {
486
+ "type": "object",
487
+ "additionalProperties": false,
488
+ "properties": {
489
+ "stopHook": {
490
+ "type": "object",
491
+ "additionalProperties": false,
492
+ "properties": {
493
+ "enforce": {
494
+ "type": "boolean"
495
+ }
496
+ }
497
+ }
498
+ }
499
+ },
485
500
  "architecture": {
486
501
  "type": "object",
487
502
  "additionalProperties": false,
@@ -17,7 +17,7 @@ const HOOKS_TARGET_DIR = ".claude";
17
17
 
18
18
  // ── Skill Category Map ──
19
19
 
20
- export type SkillCategory = "core" | "aidlc" | "utility";
20
+ export type SkillCategory = "core" | "aidlc" | "utility" | "guidance";
21
21
  export type SkillSet = "core" | "all";
22
22
 
23
23
  export const SKILL_CATEGORIES: Record<SkillCategory, readonly string[]> = {
@@ -52,13 +52,19 @@ export const SKILL_CATEGORIES: Record<SkillCategory, readonly string[]> = {
52
52
  "unit-test-logic-designer",
53
53
  ],
54
54
  utility: ["codex-delegator", "skill-creator"],
55
+ guidance: ["phasegate-toolkit-guide"],
55
56
  } as const;
56
57
 
57
58
  export function getSkillsForSet(skillSet: SkillSet): string[] {
58
59
  if (skillSet === "core") {
59
60
  return [...SKILL_CATEGORIES.core];
60
61
  }
61
- return [...SKILL_CATEGORIES.core, ...SKILL_CATEGORIES.aidlc, ...SKILL_CATEGORIES.utility];
62
+ return [
63
+ ...SKILL_CATEGORIES.core,
64
+ ...SKILL_CATEGORIES.aidlc,
65
+ ...SKILL_CATEGORIES.utility,
66
+ ...SKILL_CATEGORIES.guidance,
67
+ ];
62
68
  }
63
69
 
64
70
  export function getCategoryForSkill(skillName: string): SkillCategory | null {
@@ -0,0 +1,166 @@
1
+ ---
2
+ name: phasegate-toolkit-guide
3
+ description: phasegate ツールキット自体に関する Q&A スキル。ユーザーが phasegate の概念 (L0-L4 レイヤーモデル / 防御プリセット / アーキプリセット / Quick Mode と Full Mode / Hook 仕様 / config 全般) について質問したとき、対応する canonical doc を読み込んでから回答する。使用タイミング:「phasegate の L1 と L2 の違いは?」「Quick Mode で許可されるカテゴリを増やしたい」「architecture.preset の使い分けは?」「phasegate の hook って何が動いている?」「phasegate.config.json の relaxedGates は何のため?」など phasegate ツールキット内部の仕様・設定を尋ねる質問。
4
+ ---
5
+
6
+ # Phasegate Toolkit Guide
7
+
8
+ phasegate ツールキット自体の概念・仕様・設定について、ユーザーの質問に正確に答えるための skill。
9
+
10
+ ## このスキルが解決する問題
11
+
12
+ ユーザーが phasegate を導入したプロジェクトで、AI に phasegate 関連の質問や設定変更を依頼したとき、AI が `node_modules/phasegate/` を grep で調査して仕様を推測する非効率を防ぐ。
13
+
14
+ phasegate の概念と仕様は **canonical doc が `node_modules/phasegate/docs/guide/` 配下に同梱されている**。本 skill はそれらへの正確なポインタを提供する。
15
+
16
+ ## 重要な設計原則
17
+
18
+ **knowledge を skill 本体に固定しない**。本 SKILL.md は「どの doc を読めば答えられるか」のポインタだけを持つ。実際の概念知識は phasegate 同梱 canonical doc から動的に読み込む。
19
+
20
+ これにより `npm update phasegate` で knowledge が自動追従する (skill markdown に概念本文を書いてしまうとバージョン乖離が起きる)。
21
+
22
+ ## 回答プロセス
23
+
24
+ 1. ユーザー質問を以下の **概念カテゴリ** にマッピング
25
+ 2. 対応する canonical doc を **Read tool で読む**
26
+ 3. Read した内容に基づいて回答
27
+ 4. 回答内に **doc 内の該当セクションへのポインタ** を含める (ユーザーが詳細確認できるように)
28
+
29
+ ### canonical doc の場所
30
+
31
+ phasegate がインストールされたプロジェクトでは、以下のいずれかにある:
32
+
33
+ ```
34
+ node_modules/phasegate/docs/guide/ # npm 経由でインストールされた consumer プロジェクト
35
+ docs/guide/ # phasegate リポジトリ自体 (dogfood)
36
+ ```
37
+
38
+ **先に `node_modules/phasegate/docs/guide/` を試し**、見つからなければ `docs/guide/` を試す。
39
+
40
+ ## 概念カテゴリと参照先 doc
41
+
42
+ ### 1. L0-L4 レイヤーモデル
43
+
44
+ ユーザー質問例:
45
+ - 「phasegate の L1 と L2 の違いって何?」
46
+ - 「L0 ってどこで動いてる?」
47
+ - 「L3 と L4 の検査内容を教えて」
48
+
49
+ **参照先**: `docs/guide/layer-model.md`
50
+
51
+ **読み方**: ファイル全体を読む (各層のセクションが明確に分かれている)。
52
+
53
+ ### 2. 防御プリセット / アーキプリセット (重要: 2 系統あり)
54
+
55
+ ユーザー質問例:
56
+ - 「preset って何?」
57
+ - 「standard と strict の違いは?」
58
+ - 「architecture.preset で onion と clean どっち選ぶべき?」
59
+ - 「アーキプリセットを custom にしたいんだけど」
60
+
61
+ **重要**: phasegate には **「防御プリセット」(`project.preset`) と「アーキプリセット」(`architecture.preset`) の 2 系統** がある。質問が曖昧な場合は **どちらを聞いているか確認** すること:
62
+
63
+ | 呼称 | 概念 | 設定キー | 値の例 |
64
+ |---|---|---|---|
65
+ | **防御プリセット** | L3 CI で検査強度を選ぶ | `project.preset` | `minimal` / `standard` / `strict` |
66
+ | **アーキプリセット** | L1 の層構造と依存方向を定義 | `architecture.preset` | `clean` / `strict-ddd` / `onion` / `hexagonal` / `layered` / `flat` / `custom` |
67
+
68
+ **参照先**: `docs/guide/preset-selection.md` (両系統の詳細解説)
69
+
70
+ ### 3. Quick Mode と Full Mode
71
+
72
+ ユーザー質問例:
73
+ - 「Quick Mode と Full Mode の違いは?」
74
+ - 「Quick Mode で書き込みが許可されるカテゴリを増やしたい」
75
+ - 「relaxedGates って何のため?」
76
+ - 「allowedCategories はどこで設定する?」
77
+
78
+ **参照先**: `docs/guide/quick-vs-full-mode.md`
79
+
80
+ 設定キーは `phasegate.config.json` の `quickMode` セクション (`allowedCategories` / `relaxedGates` / `fullModeRequiredWhen`)。詳細は `docs/guide/configuration.md` の `quickMode` セクションも併読。
81
+
82
+ ### 4. Hook 仕様 (PreToolUse / PostToolUse / Stop / SessionStart / UserPromptSubmit)
83
+
84
+ ユーザー質問例:
85
+ - 「phasegate の hook って何が動いてる?」
86
+ - 「PreToolUse で何が走る?」
87
+ - 「Stop hook の enforce オプションって何?」
88
+ - 「post-tool-use で format / lint が走らない、なぜ?」
89
+
90
+ **参照先**: `docs/guide/hooks-integration.md`
91
+
92
+ `Responsibility Separation` セクションに pre / post / Stop の責務分担表がある (WI-086 で追加)。Stop hook の `agentIntegration.stopHook.enforce` オプションは WI-087 Phase C-2 で追加された。
93
+
94
+ ### 5. config 全般 (`phasegate.config.json`)
95
+
96
+ ユーザー質問例:
97
+ - 「phasegate.config.json の各セクションの意味は?」
98
+ - 「baseline.enabled って何?」
99
+ - 「protectedFiles って何?」
100
+ - 「project.paths にはどうやって書く?」
101
+
102
+ **参照先**: `docs/guide/configuration.md`
103
+
104
+ 各 top-level セクションごとに説明あり: `project` / `layers` / `quickMode` / `phaseDependencies` / `harnesses` / `paths` / `reporting` / `architecture` / `agentIntegration` / `protectedFiles` / `baseline`。
105
+
106
+ ### 6. CLI コマンド一覧
107
+
108
+ ユーザー質問例:
109
+ - 「phasegate のコマンド一覧を教えて」
110
+ - 「validate と lint と check-phase の違いは?」
111
+ - 「init コマンドは何をする?」
112
+
113
+ **参照先**: `docs/guide/cli-reference.md`
114
+
115
+ ### 7. インストールと初期設定
116
+
117
+ ユーザー質問例:
118
+ - 「phasegate のインストール方法は?」
119
+ - 「monorepo で使うときは?」
120
+ - 「既存プロジェクトに後から導入したい」
121
+
122
+ **参照先**:
123
+ - 新規導入: `docs/guide/installation.md`, `docs/guide/quickstart.md` (存在する場合)
124
+ - 既存プロジェクト導入: `docs/guide/retrofit-adoption.md`
125
+
126
+ ### 8. skill 一覧と使い分け
127
+
128
+ ユーザー質問例:
129
+ - 「phasegate にはどんな skill がある?」
130
+ - 「story-implementor と quick-implementor の違いは?」
131
+
132
+ **参照先**: `docs/guide/skills-overview.md`
133
+
134
+ ### 9. Codex 統合
135
+
136
+ ユーザー質問例:
137
+ - 「codex CLI と組み合わせて使うには?」
138
+ - 「codex-delegator って何?」
139
+
140
+ **参照先**: `docs/guide/codex-integration.md`
141
+
142
+ ## 回答時のスタイル
143
+
144
+ - 簡潔に答える (2-3 段落 + コード例 1 つ程度)
145
+ - canonical doc の **該当セクション名** を必ず引用 (ユーザーが doc を直接開いたときの navigation 補助)
146
+ - 質問が複数カテゴリにまたがる場合は、最も関連性の高い doc を先に読む
147
+ - doc を読まずに回答しない (本 skill の存在意義は「正確な情報源を引く」こと)
148
+
149
+ ## マッピングが曖昧な場合
150
+
151
+ ユーザー質問が上記カテゴリのいずれにも明確に当てはまらない場合:
152
+
153
+ 1. `docs/guide/` 配下の doc 一覧 (`ls node_modules/phasegate/docs/guide/`) を取得
154
+ 2. ファイル名から推測して最も近い doc を読む
155
+ 3. それでも見つからなければ、ユーザーに **どの観点を知りたいか** を質問で絞り込む
156
+
157
+ ## 設定変更を伴う質問
158
+
159
+ 「config の X を変更したい」など **設定変更を伴う質問** は、本 skill の範囲外。phasegate-config-doctor skill (存在すれば) に委譲するか、ユーザーに「設定変更には phasegate-config-doctor を起動するのが推奨」と案内する。本 skill は **read-only な Q&A に徹する**。
160
+
161
+ ## アンチパターン
162
+
163
+ - ❌ canonical doc を読まずに training data 依存で答える (バージョン乖離リスク)
164
+ - ❌ doc 全文をユーザーに貼り付ける (要約して該当セクションへのポインタを返す)
165
+ - ❌ `phasegate.config.json` を直接編集する (本 skill は read-only)
166
+ - ❌ skill 本文に概念解説を書き加える (doc に書くべき。skill はポインタ役)