phasegate 0.283.0 → 0.335.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/docs/ADR/017-warning-severity-aggregation.md +17 -0
  3. package/docs/ADR/038-config-state-operation-permission-policy.md +78 -0
  4. package/docs/ADR/039-hook-observable-state-as-authorization-unit.md +74 -0
  5. package/docs/ADR/040-quick-mode-config-via-preset-resolution.md +66 -0
  6. package/docs/guide/cli-reference.md +89 -7
  7. package/docs/guide/configuration.md +43 -2
  8. package/docs/guide/layer-model.md +2 -0
  9. package/docs/guide/quick-vs-full-mode.md +63 -3
  10. package/docs/guide/troubleshooting.md +37 -0
  11. package/docs/templates/agent-context/CLAUDE.md.template.md +6 -6
  12. package/package.json +2 -2
  13. package/scripts/harness/agent-integration/application/dto/handle-pre-tool-use-dto.ts +5 -1
  14. package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +108 -20
  15. package/scripts/harness/agent-integration/domain/services/bash-write-target-extractor.ts +215 -5
  16. package/scripts/harness/agent-integration/domain/value-objects/protected-file-list.ts +5 -0
  17. package/scripts/harness/agent-integration/infrastructure/adapters/file-system-full-mode-session-query-adapter.ts +75 -23
  18. package/scripts/harness/agent-integration/infrastructure/adapters/harness-config-config-query-adapter.ts +18 -3
  19. package/scripts/harness/agent-integration/infrastructure/adapters/quick-mode-full-mode-requirement-adapter.ts +15 -1
  20. package/scripts/harness/agent-integration/presentation/pre-tool-use-hook.ts +57 -9
  21. package/scripts/harness/ci-governance/application/dto/scaffold-inception-input.ts +9 -0
  22. package/scripts/harness/ci-governance/application/dto/scaffold-inception-output.ts +13 -0
  23. package/scripts/harness/ci-governance/application/usecases/list-templates-usecase.ts +30 -0
  24. package/scripts/harness/ci-governance/application/usecases/scaffold-inception-usecase.ts +63 -0
  25. package/scripts/harness/ci-governance/application/usecases/show-template-usecase.ts +39 -0
  26. package/scripts/harness/ci-governance/composition-root.ts +57 -5
  27. package/scripts/harness/ci-governance/domain/ports/inception-doc-writer-port.ts +19 -0
  28. package/scripts/harness/ci-governance/domain/ports/inception-template-repository-port.ts +16 -0
  29. package/scripts/harness/ci-governance/domain/ports/template-catalog-port.ts +23 -0
  30. package/scripts/harness/ci-governance/domain/services/claude-md-composer.ts +20 -11
  31. package/scripts/harness/ci-governance/domain/value-objects/inception-doc-kind.ts +109 -0
  32. package/scripts/harness/ci-governance/domain/value-objects/template-catalog-entry.ts +53 -0
  33. package/scripts/harness/ci-governance/domain/value-objects/template-name.ts +50 -0
  34. package/scripts/harness/ci-governance/infrastructure/adapters/file-system-inception-doc-writer-adapter.ts +42 -0
  35. package/scripts/harness/ci-governance/infrastructure/adapters/file-system-inception-template-repository-adapter.ts +32 -0
  36. package/scripts/harness/ci-governance/infrastructure/adapters/file-system-template-catalog-adapter.ts +60 -0
  37. package/scripts/harness/ci-governance/presentation/handlers/check-repetition-handler.ts +10 -2
  38. package/scripts/harness/ci-governance/presentation/handlers/scaffold-inception-handler.ts +101 -0
  39. package/scripts/harness/ci-governance/presentation/handlers/templates-handler.ts +103 -0
  40. package/scripts/harness/config-foundation/domain/harness-config.ts +12 -0
  41. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +3 -3
  42. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +3 -3
  43. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +3 -3
  44. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +44 -1
  45. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +42 -1
  46. package/scripts/harness/harness-api/domain/services/command-dispatch-service.ts +12 -3
  47. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +2 -22
  48. package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +3 -1
  49. package/scripts/harness/harness-error/application/dto/create-harness-error-input.ts +3 -1
  50. package/scripts/harness/harness-error/application/dto/harness-error-contract.ts +3 -1
  51. package/scripts/harness/harness-error/application/mappers/harness-error-contract-mapper.ts +9 -17
  52. package/scripts/harness/harness-error/application/usecases/create-harness-error-use-case.ts +7 -7
  53. package/scripts/harness/harness-error/domain/services/harness-error-factory.ts +30 -33
  54. package/scripts/harness/harness-error/domain/value-objects/error-definition.ts +28 -17
  55. package/scripts/harness/harness-error/domain/value-objects/harness-error.ts +30 -9
  56. package/scripts/harness/harness-error/domain/value-objects/remediation-type.ts +30 -0
  57. package/scripts/harness/harness-error/infrastructure/registry/l2-error-definitions.ts +44 -29
  58. package/scripts/harness/harness-error/infrastructure/registry/l3-error-definitions.ts +44 -27
  59. package/scripts/harness/harness-error/infrastructure/registry/l4-error-definitions.ts +47 -32
  60. package/scripts/harness/installation/application/checks/claude-context-missing-check.ts +13 -7
  61. package/scripts/harness/installation/application/checks/config-status-check.ts +52 -0
  62. package/scripts/harness/installation/application/checks/husky-pre-commit-missing-check.ts +6 -0
  63. package/scripts/harness/installation/application/ports/config-status-probe-port.ts +9 -0
  64. package/scripts/harness/installation/application/usecases/run-doctor-diagnostics.ts +30 -8
  65. package/scripts/harness/installation/application/usecases/run-install.ts +44 -11
  66. package/scripts/harness/installation/application/usecases/run-reconcile.ts +44 -11
  67. package/scripts/harness/installation/composition-root.ts +13 -3
  68. package/scripts/harness/installation/domain/check-id.ts +2 -0
  69. package/scripts/harness/installation/domain/config-status.ts +17 -0
  70. package/scripts/harness/installation/domain/ports/heuristic-check.ts +10 -1
  71. package/scripts/harness/installation/infrastructure/adapters/config-status-probe-adapter.ts +79 -0
  72. package/scripts/harness/installation/presentation/cli/doctor-handler.ts +6 -1
  73. package/scripts/harness/installation/presentation/formatters/diagnostic-report-formatter.ts +19 -5
  74. package/scripts/harness/integrations/pre-commit.ts +17 -3
  75. package/scripts/harness/main.ts +159 -21
  76. package/scripts/harness/phase-dependency-model/application/services/evidence-bundle-assembler.ts +2 -1
  77. package/scripts/harness/phase-dependency-model/domain/ports/plan-document-reader-port.ts +12 -0
  78. package/scripts/harness/phase-dependency-model/infrastructure/filesystem/markdown-plan-document-reader.ts +64 -33
  79. package/scripts/harness/phase2-extensions/presentation/handlers/check-freshness-handler.ts +17 -9
  80. package/scripts/harness/quick-mode/application/ports/file-existence-port.ts +15 -0
  81. package/scripts/harness/quick-mode/application/usecases/classify-change-category-usecase.ts +60 -22
  82. package/scripts/harness/quick-mode/composition-root.ts +25 -15
  83. package/scripts/harness/quick-mode/domain/errors/quick-mode-config-error.ts +19 -0
  84. package/scripts/harness/quick-mode/domain/services/quick-mode-judgment-engine.ts +116 -18
  85. package/scripts/harness/quick-mode/domain/value-objects/category-override-rules.ts +147 -0
  86. package/scripts/harness/quick-mode/domain/value-objects/change-category.ts +33 -0
  87. package/scripts/harness/quick-mode/domain/value-objects/quick-mode-config.ts +31 -10
  88. package/scripts/harness/quick-mode/index.ts +7 -1
  89. package/scripts/harness/quick-mode/infrastructure/adapters/fs-file-existence-adapter.ts +38 -0
  90. package/scripts/harness/quick-mode/infrastructure/adapters/harness-config-quick-mode-config-adapter.ts +83 -32
  91. package/scripts/harness/skill-quality/infrastructure/adapters/file-system-requirement-test-matrix-adapter.ts +51 -8
  92. package/scripts/harness/skill-quality/presentation/handlers/check-coverage-handler.ts +13 -6
  93. package/scripts/harness/traceability-model/domain/value-objects/work-item-frontmatter.ts +5 -1
  94. package/scripts/harness/traceability-model/infrastructure/gateways/file-system-work-item-identity-gateway.ts +6 -1
  95. package/scripts/harness/traceability-model/infrastructure/gateways/file-system-work-item-status-gateway.ts +15 -2
  96. package/scripts/harness/validator-system/application/use-cases/aggregate-validation-results-usecase.ts +11 -14
  97. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +8 -0
  98. package/scripts/harness/validator-system/domain/services/effective-severity-policy.ts +39 -0
  99. package/scripts/harness/validator-system/domain/value-objects/consistency-report.ts +6 -4
  100. package/scripts/harness/validator-system/domain/value-objects/drift-report.ts +12 -7
  101. package/scripts/harness/validator-system/domain/value-objects/validation-result.ts +11 -3
  102. package/scripts/harness/validator-system/infrastructure/adapters/file-system-security-pattern-scanner-adapter.ts +20 -17
  103. package/scripts/harness/validator-system/infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.ts +35 -14
  104. package/scripts/harness/validator-system/infrastructure/adapters/traceability-metadata-policy-adapter.ts +13 -8
  105. package/scripts/harness/validator-system/presentation/formatters/agent-validation-result-formatter.ts +19 -10
  106. package/skills/product-architect/SKILL.md +19 -0
  107. package/skills/quick-implementor/SKILL.md +19 -0
  108. package/skills/story-mapper/SKILL.md +11 -0
  109. package/skills/story-writer/SKILL.md +11 -0
  110. package/skills/unit-designer/SKILL.md +11 -0
  111. package/templates/product_overview.template.md +85 -0
  112. package/templates/product_overview_plan.template.md +55 -0
  113. package/templates/story_mapping_plan.template.md +61 -0
  114. package/templates/story_writer_plan.template.md +61 -0
  115. package/templates/unit_design_plan.template.md +63 -0
@@ -6,7 +6,7 @@
6
6
  * ConsistencyReport 値オブジェクト
7
7
  * 設計文書間のレイヤー整合性検証結果VO(L4-002専用)
8
8
  */
9
- import type { HarnessErrorLike } from './validation-result.js';
9
+ import type { HarnessErrorLike } from "./validation-result.js";
10
10
 
11
11
  export interface MismatchPair {
12
12
  readonly expected: string;
@@ -48,10 +48,12 @@ export class ConsistencyReport {
48
48
  // ADR-017 / WI-094: error catalog の defaultSeverity: warning と整合
49
49
  toHarnessErrors(): readonly HarnessErrorLike[] {
50
50
  return this.mismatchPairs.map((pair) => ({
51
- code: { value: 'L4-002', toString: () => 'L4-002' },
52
- severity: { value: 'warning', toString: () => 'warning' },
51
+ code: { value: "L4-002", toString: () => "L4-002" },
52
+ severity: { value: "warning", toString: () => "warning" },
53
53
  message: `レイヤー整合性違反: expected "${pair.expected}" but got "${pair.actual}" at ${pair.location}`,
54
- suggestion: pair.nextAction ?? '設計文書間のレイヤー依存方向を統一してください',
54
+ suggestion: pair.nextAction ?? "設計文書間のレイヤー依存方向を統一してください",
55
+ // WI-335: 文書間整合の回復は「どちらの記述が正か」の判断を伴う(ai-assisted)。
56
+ remediationType: "ai-assisted" as const,
55
57
  }));
56
58
  }
57
59
  }
@@ -5,9 +5,9 @@
5
5
  * DriftReport 値オブジェクト
6
6
  * 設計文書とコード実装の双方向乖離検出結果VO(L4-001専用)
7
7
  */
8
- import type { HarnessErrorLike } from './validation-result.js';
8
+ import type { HarnessErrorLike } from "./validation-result.js";
9
9
 
10
- export type DriftDirection = 'design→code' | 'code→design';
10
+ export type DriftDirection = "design→code" | "code→design";
11
11
 
12
12
  export interface DriftReportProps {
13
13
  readonly direction: DriftDirection;
@@ -29,14 +29,16 @@ export class DriftReport {
29
29
  this.direction = props.direction;
30
30
  this.unitName = props.unitName;
31
31
  this.element = props.element;
32
- this.recommendation = props.recommendation ?? (props.description ?? '');
32
+ this.recommendation = props.recommendation ?? props.description ?? "";
33
33
  this.location = Object.freeze(props.location ?? {});
34
34
  Object.freeze(this);
35
35
  }
36
36
 
37
37
  static create(props: DriftReportProps): DriftReport {
38
- if (props.direction !== 'design→code' && props.direction !== 'code→design') {
39
- throw new Error(`Invalid DriftReport direction: "${props.direction}". Must be "design→code" or "code→design" (INV-10)`);
38
+ if (props.direction !== "design→code" && props.direction !== "code→design") {
39
+ throw new Error(
40
+ `Invalid DriftReport direction: "${props.direction}". Must be "design→code" or "code→design" (INV-10)`,
41
+ );
40
42
  }
41
43
  return new DriftReport(props);
42
44
  }
@@ -44,10 +46,13 @@ export class DriftReport {
44
46
  toHarnessError(): HarnessErrorLike {
45
47
  // ADR-017 / WI-094: error catalog の defaultSeverity: warning と整合
46
48
  return {
47
- code: { value: 'L4-001', toString: () => 'L4-001' },
48
- severity: { value: 'warning', toString: () => 'warning' },
49
+ code: { value: "L4-001", toString: () => "L4-001" },
50
+ severity: { value: "warning", toString: () => "warning" },
49
51
  message: `乖離検出 [${this.direction}] Unit: ${this.unitName}, Element: ${this.element}`,
50
52
  suggestion: this.recommendation,
53
+ // WI-335: design drift の解消は設計意図の理解が必要で機械適用不能。AI が設計文書を
54
+ // 読んで自己修正できる分類(ai-assisted)。
55
+ remediationType: "ai-assisted",
51
56
  };
52
57
  }
53
58
 
@@ -5,7 +5,7 @@
5
5
  * ValidationResult 値オブジェクト
6
6
  * バリデータ実行結果のスナップショット(不変)
7
7
  */
8
- import type { ValidatorId } from './validator-id.js';
8
+ import type { ValidatorId } from "./validator-id.js";
9
9
 
10
10
  /** HarnessError の最小互換型(harness-error Unit の HarnessError との疎結合) */
11
11
  export interface HarnessErrorLike {
@@ -13,6 +13,12 @@ export interface HarnessErrorLike {
13
13
  readonly severity: { readonly value?: string; toString(): string };
14
14
  readonly message: string;
15
15
  readonly suggestion: string;
16
+ /**
17
+ * WI-335: suggestion の修復方式分類。未設定は 'manual' 扱い(機械適用可能と過剰宣言しない)。
18
+ * 'mechanical' を宣言したエラーは remediation-round-trip テストで
19
+ * 「エラー → suggestion を機械適用 → 再実行 → pass」が CI 保証される。
20
+ */
21
+ readonly remediationType?: "mechanical" | "ai-assisted" | "manual";
16
22
  [key: string]: unknown;
17
23
  }
18
24
 
@@ -49,10 +55,12 @@ export class ValidationResult {
49
55
  throw new Error(`ValidationResult durationMs must be >= 0 (got: ${props.durationMs})`);
50
56
  }
51
57
  if (props.passed && props.errors.length > 0) {
52
- throw new Error('ValidationResult invariant violation: passed=true but errors is not empty (INV-5)');
58
+ throw new Error("ValidationResult invariant violation: passed=true but errors is not empty (INV-5)");
53
59
  }
54
60
  if (props.skipped && (!props.passed || props.errors.length > 0)) {
55
- throw new Error('ValidationResult invariant violation: skipped=true requires passed=true and empty errors (INV-8)');
61
+ throw new Error(
62
+ "ValidationResult invariant violation: skipped=true requires passed=true and empty errors (INV-8)",
63
+ );
56
64
  }
57
65
  return new ValidationResult(props);
58
66
  }
@@ -5,11 +5,12 @@
5
5
  *
6
6
  * FileSystemSecurityPatternScannerAdapter — SecurityPatternScannerPort実装
7
7
  */
8
- import type { SecurityPatternScannerPort } from '../../domain/ports/security-pattern-scanner-port.js';
9
- import type { HarnessErrorLike } from '../../domain/value-objects/validation-result.js';
10
- import { readFile } from 'node:fs/promises';
11
8
 
12
- const ALLOWLIST_MARKER = 'phasegate-allow-secret-fixture';
9
+ import { readFile } from "node:fs/promises";
10
+ import type { SecurityPatternScannerPort } from "../../domain/ports/security-pattern-scanner-port.js";
11
+ import type { HarnessErrorLike } from "../../domain/value-objects/validation-result.js";
12
+
13
+ const ALLOWLIST_MARKER = "phasegate-allow-secret-fixture";
13
14
 
14
15
  interface SecurityPattern {
15
16
  readonly ruleId: string;
@@ -18,15 +19,15 @@ interface SecurityPattern {
18
19
  }
19
20
 
20
21
  const SECURITY_PATTERNS: readonly SecurityPattern[] = Object.freeze([
21
- { ruleId: 'secret.openai', pattern: /\b(?:sk|rk|sess)-[a-zA-Z0-9_-]{20,}\b/g, description: 'OpenAI token family' },
22
- { ruleId: 'secret.github', pattern: /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g, description: 'GitHub token family' },
23
- { ruleId: 'secret.aws-access-key', pattern: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g, description: 'AWS access key id' },
24
- { ruleId: 'secret.npm', pattern: /\bnpm_[A-Za-z0-9]{24,}\b/g, description: 'npm token family' },
25
- { ruleId: 'secret.slack', pattern: /\bxox[abprs]-[A-Za-z0-9-]{20,}\b/g, description: 'Slack token family' },
22
+ { ruleId: "secret.openai", pattern: /\b(?:sk|rk|sess)-[a-zA-Z0-9_-]{20,}\b/g, description: "OpenAI token family" },
23
+ { ruleId: "secret.github", pattern: /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g, description: "GitHub token family" },
24
+ { ruleId: "secret.aws-access-key", pattern: /\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g, description: "AWS access key id" },
25
+ { ruleId: "secret.npm", pattern: /\bnpm_[A-Za-z0-9]{24,}\b/g, description: "npm token family" },
26
+ { ruleId: "secret.slack", pattern: /\bxox[abprs]-[A-Za-z0-9-]{20,}\b/g, description: "Slack token family" },
26
27
  {
27
- ruleId: 'secret.keyword-context',
28
+ ruleId: "secret.keyword-context",
28
29
  pattern: /\b(?:API_KEY|api_key|apikey|password|PASSWORD|passwd|secret|token)\b\s*[:=]\s*["'][^"']{8,}["']/g,
29
- description: 'keyword-context secret',
30
+ description: "keyword-context secret",
30
31
  },
31
32
  ]);
32
33
 
@@ -39,8 +40,8 @@ export class FileSystemSecurityPatternScannerAdapter implements SecurityPatternS
39
40
 
40
41
  for (const filePath of targetPaths) {
41
42
  try {
42
- const content = await readFile(filePath, 'utf-8');
43
- const lines = content.split('\n');
43
+ const content = await readFile(filePath, "utf-8");
44
+ const lines = content.split("\n");
44
45
  lines.forEach((line, idx) => {
45
46
  // WI-120: allowlist は行/領域スコープ。以前はファイル内のどこかに
46
47
  // マーカーが 1 つでもあればファイル全体をスキップしていたため、同一
@@ -54,12 +55,14 @@ export class FileSystemSecurityPatternScannerAdapter implements SecurityPatternS
54
55
  pattern.lastIndex = 0;
55
56
  const matches = [...line.matchAll(pattern)];
56
57
  for (const match of matches) {
57
- const secretValue = match[0] ?? '';
58
+ const secretValue = match[0] ?? "";
58
59
  findings.push({
59
- code: { value: 'L3-001', toString: () => 'L3-001' },
60
- severity: { value: 'error', toString: () => 'error' },
60
+ code: { value: "L3-001", toString: () => "L3-001" },
61
+ severity: { value: "error", toString: () => "error" },
61
62
  message: `セキュリティ問題: ${description} (${ruleId}) at ${filePath}:${idx + 1} value=${redactSecret(secretValue)}`,
62
63
  suggestion: `${ruleId}: 秘密情報は環境変数または秘密管理サービスを使用してください。fixture/docs のダミー値は ${ALLOWLIST_MARKER} を明示してください。`,
64
+ // WI-335: 秘密情報の無効化・ローテーション・保管方式の選定は人間の判断が必須(manual)。
65
+ remediationType: "manual",
63
66
  });
64
67
  }
65
68
  }
@@ -88,6 +91,6 @@ function isAllowlisted(line: string, previousLine: string | undefined): boolean
88
91
 
89
92
  function redactSecret(secretValue: string): string {
90
93
  const value = secretValue.trim();
91
- if (value.length <= 8) return '<redacted>';
94
+ if (value.length <= 8) return "<redacted>";
92
95
  return `${value.slice(0, 3)}...<redacted:${value.length}>`;
93
96
  }
@@ -4,8 +4,27 @@
4
4
  *
5
5
  * PhaseDependencyPhaseGatePolicyAdapter — PhaseGatePolicyPort実装
6
6
  */
7
- import type { PhaseGatePolicyPort } from '../../domain/ports/phase-gate-policy-port.js';
8
- import type { HarnessErrorLike } from '../../domain/value-objects/validation-result.js';
7
+ import type { PhaseGatePolicyPort } from "../../domain/ports/phase-gate-policy-port.js";
8
+ import type { HarnessErrorLike } from "../../domain/value-objects/validation-result.js";
9
+
10
+ /**
11
+ * WI-357 (issue #29): `validate --layer L2` の失敗出力には従来
12
+ * 'phase gate prerequisites are not met' という事実の再掲しか載らず、
13
+ * 「何を作れば通るのか」がどの経路からも得られなかった。
14
+ * hook の block メッセージ側にしか復旧手順がないため、CLI から検証した
15
+ * エージェントは不足文書を推測で書くしかなくなる。
16
+ *
17
+ * 実行可能な復旧手順(scaffold コマンド)と、文書のセクション構成の在り処
18
+ * (skills/<skill>/SKILL.md、未配置なら `phasegate skills info`)を suggestion に載せる。
19
+ */
20
+ export function buildPhaseGateRecoverySuggestion(unitName: string): string {
21
+ const unitArg = unitName.trim().length > 0 ? unitName.trim() : "<unit-id>";
22
+ return [
23
+ `不足している設計文書を scaffold で作成してください: npx phasegate scaffold-design --unit ${unitArg} --phase <logical|domain|uiux|unit-test|it-test> --apply`,
24
+ "各文書のセクション構成は導入先 repo の skills/<skill>/SKILL.md に記載されています(logical_design.md → skills/logical-designer/SKILL.md、domain_model.md → skills/domain-designer/SKILL.md、unit plan → skills/unit-designer/SKILL.md)。",
25
+ "skills/ が repo に無い場合は `npx phasegate skills info <skill-name>` で同じ内容を stdout から読めます。",
26
+ ].join("\n");
27
+ }
9
28
 
10
29
  export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPort {
11
30
  async checkPrerequisites(context: { unitName: string; currentPhase: string }): Promise<{
@@ -18,11 +37,13 @@ export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPor
18
37
 
19
38
  try {
20
39
  // WI-085: paths config を phase-dependency-model に流入させる
21
- const { createConfigFoundationModule } = await import('../../../config-foundation/composition-root.js');
22
- const { toPhaseConfigSection } = await import('../../../config-foundation/application/mappers/phase-config-section-mapper.js');
40
+ const { createConfigFoundationModule } = await import("../../../config-foundation/composition-root.js");
41
+ const { toPhaseConfigSection } = await import(
42
+ "../../../config-foundation/application/mappers/phase-config-section-mapper.js"
43
+ );
23
44
  const configModule = createConfigFoundationModule();
24
45
  const resolvedConfig = await configModule.usecases.loadResolvedConfigUseCase.execute();
25
- const { createPhaseDependencyModelModule } = await import('../../../phase-dependency-model/composition-root.js');
46
+ const { createPhaseDependencyModelModule } = await import("../../../phase-dependency-model/composition-root.js");
26
47
  const mod = createPhaseDependencyModelModule({
27
48
  rootDir: process.cwd(),
28
49
  phaseConfig: toPhaseConfigSection(resolvedConfig.config),
@@ -42,10 +63,10 @@ export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPor
42
63
  satisfied: false,
43
64
  violations: [
44
65
  {
45
- code: { value: 'L2-001', toString: () => 'L2-001' },
46
- severity: { value: 'error', toString: () => 'error' },
66
+ code: { value: "L2-001", toString: () => "L2-001" },
67
+ severity: { value: "error", toString: () => "error" },
47
68
  message: result.text,
48
- suggestion: 'phase gate prerequisites are not met',
69
+ suggestion: buildPhaseGateRecoverySuggestion(context.unitName),
49
70
  },
50
71
  ],
51
72
  };
@@ -57,10 +78,10 @@ export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPor
57
78
  satisfied: false,
58
79
  violations: [
59
80
  {
60
- code: { value: 'L2-002', toString: () => 'L2-002' },
61
- severity: { value: 'error', toString: () => 'error' },
81
+ code: { value: "L2-002", toString: () => "L2-002" },
82
+ severity: { value: "error", toString: () => "error" },
62
83
  message: `phase gate check returned unexpected exit code ${result.exitCode}; prerequisites cannot be confirmed`,
63
- suggestion: 'phase gate prerequisites could not be evaluated; treating as NOT satisfied (fail-closed)',
84
+ suggestion: "phase gate prerequisites could not be evaluated; treating as NOT satisfied (fail-closed)",
64
85
  },
65
86
  ],
66
87
  };
@@ -73,10 +94,10 @@ export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPor
73
94
  satisfied: false,
74
95
  violations: [
75
96
  {
76
- code: { value: 'L2-002', toString: () => 'L2-002' },
77
- severity: { value: 'error', toString: () => 'error' },
97
+ code: { value: "L2-002", toString: () => "L2-002" },
98
+ severity: { value: "error", toString: () => "error" },
78
99
  message: `phase gate prerequisite check could not be evaluated: ${message}`,
79
- suggestion: 'phase gate prerequisites could not be evaluated; treating as NOT satisfied (fail-closed)',
100
+ suggestion: "phase gate prerequisites could not be evaluated; treating as NOT satisfied (fail-closed)",
80
101
  },
81
102
  ],
82
103
  };
@@ -4,8 +4,8 @@
4
4
  *
5
5
  * TraceabilityMetadataPolicyAdapter — MetadataPolicyPort実装
6
6
  */
7
- import type { MetadataPolicyPort } from '../../domain/ports/metadata-policy-port.js';
8
- import type { HarnessErrorLike } from '../../domain/value-objects/validation-result.js';
7
+ import type { MetadataPolicyPort } from "../../domain/ports/metadata-policy-port.js";
8
+ import type { HarnessErrorLike } from "../../domain/value-objects/validation-result.js";
9
9
 
10
10
  export class TraceabilityMetadataPolicyAdapter implements MetadataPolicyPort {
11
11
  async validateMetadata(context: { filePath: string; fileContent: string }): Promise<{
@@ -19,21 +19,26 @@ export class TraceabilityMetadataPolicyAdapter implements MetadataPolicyPort {
19
19
  const hasLayer = /@layer\s+\S+/.test(fileContent);
20
20
  const hasStoryId = /@story-id\s+H\d{2}-\d{2}/.test(fileContent) || /@story\s+H\d{2}-\d{2}/.test(fileContent);
21
21
 
22
+ // WI-335: この suggestion は「<directive> <値> を先頭コメントに追加」という機械適用可能な
23
+ // 文言契約を持つ(remediationType: 'mechanical')。文言をこの形から変える場合は
24
+ // remediation-round-trip テスト(機械適用器が同じ文言を解析する)が fail する。
22
25
  if (!hasUnit) {
23
26
  errors.push({
24
- code: { value: 'L2-002', toString: () => 'L2-002' },
25
- severity: { value: 'error', toString: () => 'error' },
27
+ code: { value: "L2-002", toString: () => "L2-002" },
28
+ severity: { value: "error", toString: () => "error" },
26
29
  message: `メタデータ不足: @unit アノテーションがありません (${filePath})`,
27
- suggestion: '// @unit <unit-name> を先頭コメントに追加してください',
30
+ suggestion: "// @unit <unit-name> を先頭コメントに追加してください",
31
+ remediationType: "mechanical",
28
32
  });
29
33
  }
30
34
 
31
35
  if (!hasLayer) {
32
36
  errors.push({
33
- code: { value: 'L2-002', toString: () => 'L2-002' },
34
- severity: { value: 'error', toString: () => 'error' },
37
+ code: { value: "L2-002", toString: () => "L2-002" },
38
+ severity: { value: "error", toString: () => "error" },
35
39
  message: `メタデータ不足: @layer アノテーションがありません (${filePath})`,
36
- suggestion: '// @layer domain|application|infrastructure|presentation を先頭コメントに追加してください',
40
+ suggestion: "// @layer domain|application|infrastructure|presentation を先頭コメントに追加してください",
41
+ remediationType: "mechanical",
37
42
  });
38
43
  }
39
44
 
@@ -4,34 +4,43 @@
4
4
  *
5
5
  * AgentValidationResultFormatter — AIエージェント向け詳細テキスト
6
6
  */
7
- import type { AggregatedValidationReport } from '../../application/dto/aggregated-validation-report.js';
7
+ import type { AggregatedValidationReport } from "../../application/dto/aggregated-validation-report.js";
8
8
 
9
9
  export class AgentValidationResultFormatter {
10
10
  format(report: AggregatedValidationReport): string {
11
11
  const lines: string[] = [];
12
- lines.push('VALIDATION_REPORT');
13
- lines.push(`OVERALL: ${report.overallPassed ? 'PASS' : 'FAIL'}`);
14
- lines.push(`TOTAL: ${report.totalValidators} PASSED: ${report.passedValidators} FAILED: ${report.failedValidators} SKIPPED: ${report.skippedValidators}`);
15
- lines.push('');
12
+ lines.push("VALIDATION_REPORT");
13
+ lines.push(`OVERALL: ${report.overallPassed ? "PASS" : "FAIL"}`);
14
+ lines.push(
15
+ `TOTAL: ${report.totalValidators} PASSED: ${report.passedValidators} FAILED: ${report.failedValidators} SKIPPED: ${report.skippedValidators}`,
16
+ );
17
+ lines.push("");
16
18
 
17
19
  for (const result of report.results) {
18
20
  lines.push(`VALIDATOR: ${result.validatorId}`);
19
- lines.push(`STATUS: ${result.skipped ? 'SKIPPED' : result.passed ? 'PASSED' : 'FAILED'}`);
21
+ lines.push(`STATUS: ${result.skipped ? "SKIPPED" : result.passed ? "PASSED" : "FAILED"}`);
20
22
  lines.push(`DURATION: ${result.durationMs}ms`);
21
23
  if (result.skipped && result.skipReason) {
22
24
  lines.push(`SKIP_REASON: ${result.skipReason}`);
23
25
  }
24
26
  if (result.errors.length > 0) {
25
- lines.push('ERRORS:');
27
+ lines.push("ERRORS:");
26
28
  for (const error of result.errors) {
27
29
  lines.push(` - CODE: ${error.code}`);
28
30
  lines.push(` MESSAGE: ${error.message}`);
29
- lines.push(` SUGGESTION: ${error.suggestion}`);
31
+ // WI-357: 復旧手順を載せた suggestion は複数行になりうる。
32
+ // 素朴に埋め込むと 2 行目以降がインデントを失い、ERRORS ブロックの
33
+ // 構造が壊れて機械読みできなくなるため継続行を明示的に字下げする。
34
+ const suggestionLines = String(error.suggestion).split("\n");
35
+ lines.push(` SUGGESTION: ${suggestionLines[0]}`);
36
+ for (const continuation of suggestionLines.slice(1)) {
37
+ lines.push(` ${continuation}`);
38
+ }
30
39
  }
31
40
  }
32
- lines.push('');
41
+ lines.push("");
33
42
  }
34
43
 
35
- return lines.join('\n');
44
+ return lines.join("\n");
36
45
  }
37
46
  }
@@ -35,6 +35,18 @@ languages: [typescript]
35
35
  ### 出力ファイル
36
36
  `docs/inception/_shared/product_overview_plan.md`
37
37
 
38
+ > **テンプレート実体の取得(正本)**: 下の構成ブロックは読み取り用の要約であり、
39
+ > 実体は `templates/product_overview_plan.template.md` にある。
40
+ > node_modules を Read せずに取得・生成するには次を使う:
41
+ >
42
+ > ```bash
43
+ > phasegate templates show product_overview_plan # 本文を stdout に出力
44
+ > phasegate scaffold-inception --kind product-overview-plan --apply # 実ファイルを生成
45
+ > ```
46
+ >
47
+ > scaffold した文書は無編集で Level-1 フェーズゲート(`interactive` モード)を通る。
48
+ > `[Answer]` は **人間が記入する**。AI が埋めると承認証跡の偽造になる。
49
+
38
50
  ### 計画ファイルの構成
39
51
 
40
52
  ```markdown
@@ -93,6 +105,13 @@ languages: [typescript]
93
105
  |------|--------|
94
106
  | 成果物 | `docs/product/product_overview.md` |
95
107
 
108
+ > **テンプレート実体の取得(正本)**: 実体は `templates/product_overview.template.md` にある。
109
+ >
110
+ > ```bash
111
+ > phasegate templates show product_overview
112
+ > phasegate scaffold-inception --kind product-overview --apply
113
+ > ```
114
+
96
115
  ### product_overview.md の構成
97
116
 
98
117
  ```markdown
@@ -21,6 +21,25 @@ Quick Mode下での軽微変更実装スキル。story-implementorの緩和版
21
21
  | `test` | テスト追加・修正(新機能のテストではない) |
22
22
  | `config` | 設定変更、依存バージョン更新 |
23
23
 
24
+ > **カテゴリ判定はファイルパスベース(意図ベースではない)**
25
+ > pre-tool-use hook は変更の「意図」ではなく **書き込み対象パス** からカテゴリを機械判定する。
26
+ > 特に `config` は allowlist で、以下だけが `config` に落ちる:
27
+ > `*.config.json` / `*.config.ts` / `phasegate.config.json` / `.github/workflows/*.y(a)ml` /
28
+ > リポジトリ直下の `.gitignore` `.gitattributes` `.editorconfig` `.npmrc` `.nvmrc` `tsconfig.json` `tsconfig.*.json` / `.husky/` 配下。
29
+ > allowlist 外のパスは新規作成(CREATE)なら `feature` に落ちて **必ずブロックされる**(fail-closed)。
30
+ >
31
+ > ブロックされたら、まず分類を確認する:
32
+ > ```bash
33
+ > npx phasegate check-change-category --paths <file1>,<file2>
34
+ > ```
35
+ > 判定が妥当で、かつ許可カテゴリの一時拡張が必要なら CLI 経由で計画・適用する
36
+ > (`phasegate.config.json` の手編集は保護ファイルとしてブロックされる):
37
+ > ```bash
38
+ > npx phasegate config:plan --intent quick-mode-relax --dry-run --json # 差分確認
39
+ > npx phasegate config:plan --intent quick-mode-relax --apply --json # 承認後に適用
40
+ > ```
41
+ > 判定が `feature` / `domain` / `api` なら、それは Quick Mode のスコープ外。`story-implementor` に切り替える。
42
+
24
43
  ### WI-aware trivial path(ISSUE-026 Phase D)
25
44
 
26
45
  作業対象に `WI-XXX` が明示されている場合、最初に `docs/inception/{unit}/WI-XXX/description.md` または `docs/inception/_cross/WI-XXX/description.md` のfrontmatterを確認する。
@@ -81,6 +81,17 @@ MVPスコープの方針・分類基準・不明点を整理し、人間の承
81
81
  ### 出力ファイル
82
82
  `docs/inception/_shared/story_mapping_plan.md`
83
83
 
84
+ > **テンプレート実体の取得(正本)**: 下の構成ブロックは読み取り用の要約であり、
85
+ > 実体は `templates/story_mapping_plan.template.md` にある。
86
+ > node_modules を Read せずに取得・生成するには次を使う:
87
+ >
88
+ > ```bash
89
+ > phasegate templates show story_mapping_plan
90
+ > phasegate scaffold-inception --kind story-mapping-plan --apply
91
+ > ```
92
+ >
93
+ > `[Answer]` は **人間が記入する**。AI が埋めると承認証跡の偽造になる。
94
+
84
95
  ### 計画ファイルの構成
85
96
 
86
97
  ```markdown
@@ -45,6 +45,17 @@ If not, halt and ask the user to create the WI first, or offer to run `phasegate
45
45
  ### 出力ファイル
46
46
  `docs/inception/_shared/story_writer_plan.md`
47
47
 
48
+ > **テンプレート実体の取得(正本)**: 下の構成ブロックは読み取り用の要約であり、
49
+ > 実体は `templates/story_writer_plan.template.md` にある。
50
+ > node_modules を Read せずに取得・生成するには次を使う:
51
+ >
52
+ > ```bash
53
+ > phasegate templates show story_writer_plan
54
+ > phasegate scaffold-inception --kind story-writer-plan --apply
55
+ > ```
56
+ >
57
+ > `[Answer]` は **人間が記入する**。AI が埋めると承認証跡の偽造になる。
58
+
48
59
  ### 計画ファイルの構成
49
60
 
50
61
  ```markdown
@@ -84,6 +84,17 @@ Unit分割の方針・グルーピングの根拠・不明点を整理し、人
84
84
 
85
85
  > **パス注記**: 本スキルが扱う設計文書パス(`docs/inception/...` / `docs/product/units/...`)は既定値であり、consumer が `phasegate.config.json` の `paths` 設定で上書きしている場合はそちらが優先される。
86
86
 
87
+ > **テンプレート実体の取得(正本)**: 下の構成ブロックは読み取り用の要約であり、
88
+ > 実体は `templates/unit_design_plan.template.md` にある。
89
+ > node_modules を Read せずに取得・生成するには次を使う:
90
+ >
91
+ > ```bash
92
+ > phasegate templates show unit_design_plan
93
+ > phasegate scaffold-inception --kind unit-design-plan --apply
94
+ > ```
95
+ >
96
+ > `[Answer]` は **人間が記入する**。AI が埋めると承認証跡の偽造になる。
97
+
87
98
  ### 計画ファイルの構成
88
99
 
89
100
  ```markdown
@@ -0,0 +1,85 @@
1
+ # <プロダクト名>
2
+
3
+ > **スキル**: `product-architect` Phase 2(実行)
4
+ > **入力**: `docs/inception/_shared/product_overview_plan.md`(承認済み)
5
+ > **作成日**: <YYYY-MM-DD>
6
+
7
+ このファイルは `phasegate scaffold-inception --kind product-overview --apply`
8
+ が生成した雛形です。TODO を実体で埋めてください。
9
+ このドキュメントは全スキルの**前提**として参照されます。
10
+
11
+ ---
12
+
13
+ ## 1. プロダクト定義
14
+
15
+ ### 1.1 根本思想
16
+
17
+ TODO: このプロダクトが何を信条として作られるかを 2〜3 行で記述
18
+
19
+ ### 1.2 解決する問題
20
+
21
+ TODO: 現状の痛みと、それが放置された場合のコスト
22
+
23
+ ### 1.3 対象ユーザー
24
+
25
+ TODO: 主ターゲットと、明示的に対象外とするユーザー
26
+
27
+ ## 2. コアドメイン
28
+
29
+ ### 2.1 主要概念(ユビキタス言語)
30
+
31
+ | 概念 | 定義 | 例 |
32
+ |------|------|-----|
33
+ | TODO | TODO | TODO |
34
+
35
+ ### 2.2 概念間の関係図
36
+
37
+ ```mermaid
38
+ graph TD
39
+ A[TODO] --> B[TODO]
40
+ ```
41
+
42
+ ## 3. アーキテクチャ仕様
43
+
44
+ ### 3.1 全体構造(レイヤー図)
45
+
46
+ ```
47
+ TODO: レイヤー構成
48
+ ```
49
+
50
+ ### 3.2 技術スタック
51
+
52
+ | レイヤー | 技術 | 選定理由 |
53
+ |---------|------|---------|
54
+ | TODO | TODO | TODO |
55
+
56
+ ### 3.3 分離方針
57
+
58
+ TODO: 認証/認可、同期/非同期 等の分離方針
59
+
60
+ ## 4. ADR Summary(技術決定記録)
61
+
62
+ | # | 決定事項 | 選択肢 | 決定 | 理由 |
63
+ |---|---------|-------|------|------|
64
+ | 1 | TODO | TODO | TODO | TODO |
65
+
66
+ ## 5. 制約
67
+
68
+ ### 5.1 運用上の制約
69
+
70
+ TODO
71
+
72
+ ### 5.2 実装上の制約
73
+
74
+ TODO
75
+
76
+ ### 5.3 パフォーマンス要件
77
+
78
+ TODO
79
+
80
+ ---
81
+
82
+ ## 注意事項
83
+
84
+ - ユビキタス言語はプロジェクト全体で一貫して使用する
85
+ - 技術選定の「なぜ」を必ず ADR Summary に記録する
@@ -0,0 +1,55 @@
1
+ # プロダクト設計計画
2
+
3
+ > **スキル**: `product-architect` Phase 1(計画)
4
+ > **成果物**: `docs/product/product_overview.md`(Phase 2 で作成)
5
+ > **作成日**: <YYYY-MM-DD>
6
+
7
+ このファイルは `phasegate scaffold-inception --kind product-overview-plan --apply`
8
+ が生成した雛形です。TODO を実体で埋めてください。
9
+ **QA セクションの `[Answer]` は人間が記入するもので、AI が埋めてはいけません。**
10
+
11
+ ---
12
+
13
+ ## 1. スコープ
14
+
15
+ - TODO: プロダクトの目的と対象ユーザー概要
16
+ - TODO: 設計対象セクション一覧
17
+
18
+ ## 2. ドメイン分析(ドラフト)
19
+
20
+ - TODO: 特定されたコアドメイン
21
+ - TODO: 主要業務概念の候補一覧(ユビキタス言語の種)
22
+
23
+ ## 3. アーキテクチャ方針(ドラフト)
24
+
25
+ - TODO: 想定されるアーキテクチャスタイル
26
+ - TODO: 技術スタック候補
27
+
28
+ ## 4. QA(不明点・確認事項)
29
+
30
+ ### [Question] Q1: <質問タイトル>
31
+
32
+ <質問の詳細と背景>
33
+
34
+ **推奨案:** <AI の推奨案>
35
+
36
+ > 下の `[Answer]` 行の直後に **人間が** 回答を記入してください。
37
+ > 空欄のままだと `planningMode: "embedded-qa"` のフェーズゲートは通りません(意図した挙動です)。
38
+
39
+ [Answer]
40
+
41
+ ## 5. 前提条件・リスク
42
+
43
+ - TODO: 前提条件
44
+ - TODO: リスクと対応方針
45
+
46
+ ---
47
+
48
+ ## フェーズゲートとの関係
49
+
50
+ - `planningMode.default: "interactive"`(既定)では、`## 4. QA(不明点・確認事項)`
51
+ という **QA セクション見出しの存在** が Level-1 ゲート通過条件です。
52
+ 見出しは `## QA` / `## Q&A` / `## 4. QA(...)` のいずれの表記でも構いません。
53
+ - `planningMode.default: "embedded-qa"` では、`[Question]` と `[Answer]` の
54
+ **個数一致かつ [Answer] に本文があること** が追加で要求されます。
55
+ この雛形のままではゲートを通りません(人間の回答が必要)。これは意図した挙動です。