phasegate 0.191.0 → 0.212.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 (67) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.ja.md +52 -15
  3. package/README.md +39 -11
  4. package/docs/ADR/030-injection-threat-model-and-trust-root.md +145 -0
  5. package/docs/guide/hooks-integration.md +50 -1
  6. package/docs/guide/installation.md +1 -1
  7. package/docs/guide/quick-vs-full-mode.md +1 -1
  8. package/docs/guide/skills-overview.md +7 -8
  9. package/package.json +1 -1
  10. package/scripts/harness/agent-integration/presentation/phasegate-status-context.ts +131 -63
  11. package/scripts/harness/agent-integration/presentation/session-start-hook.ts +31 -4
  12. package/scripts/harness/agent-integration/presentation/spotlight.ts +65 -0
  13. package/scripts/harness/ci-governance/application/dto/pin-integrity-input.ts +8 -0
  14. package/scripts/harness/ci-governance/application/dto/pin-integrity-output.ts +9 -0
  15. package/scripts/harness/ci-governance/application/dto/verify-integrity-input.ts +7 -0
  16. package/scripts/harness/ci-governance/application/dto/verify-integrity-output.ts +10 -0
  17. package/scripts/harness/ci-governance/application/usecases/pin-integrity-usecase.ts +60 -0
  18. package/scripts/harness/ci-governance/application/usecases/verify-integrity-usecase.ts +46 -0
  19. package/scripts/harness/ci-governance/composition-root.ts +67 -64
  20. package/scripts/harness/ci-governance/domain/ports/integrity-manifest-repository-port.ts +14 -0
  21. package/scripts/harness/ci-governance/domain/ports/sha256-hasher-port.ts +10 -0
  22. package/scripts/harness/ci-governance/domain/services/integrity-checker.ts +42 -0
  23. package/scripts/harness/ci-governance/domain/value-objects/integrity-drift.ts +16 -0
  24. package/scripts/harness/ci-governance/domain/value-objects/integrity-manifest.ts +49 -0
  25. package/scripts/harness/ci-governance/domain/value-objects/integrity-target.ts +40 -0
  26. package/scripts/harness/ci-governance/infrastructure/adapters/file-system-sha256-hasher-adapter.ts +17 -0
  27. package/scripts/harness/ci-governance/infrastructure/adapters/harness-api-command-existence-adapter.ts +7 -73
  28. package/scripts/harness/ci-governance/infrastructure/adapters/integrity-manifest-json-repository-adapter.ts +83 -0
  29. package/scripts/harness/ci-governance/presentation/handlers/integrity-handler.ts +76 -0
  30. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +53 -28
  31. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +33 -8
  32. package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +90 -0
  33. package/scripts/harness/installation/application/bundled-skill-selection.ts +2 -5
  34. package/scripts/harness/main.ts +257 -105
  35. package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +65 -3
  36. package/scripts/harness/quick-mode/domain/services/quick-mode-judgment-engine.ts +44 -40
  37. package/scripts/harness/setup/skill-deployer.ts +2 -4
  38. package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +82 -49
  39. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +87 -58
  40. package/scripts/harness/validator-system/composition-root.ts +141 -99
  41. package/scripts/harness/validator-system/domain/ports/coverage-attestation-gating-policy-port.ts +14 -0
  42. package/scripts/harness/validator-system/domain/ports/injection-scan-policy-port.ts +14 -0
  43. package/scripts/harness/validator-system/domain/services/coverage-attestation-gating-service.ts +56 -0
  44. package/scripts/harness/validator-system/domain/services/injection-pattern-scan-service.ts +118 -0
  45. package/scripts/harness/validator-system/domain/value-objects/coverage-gating-report.ts +67 -0
  46. package/scripts/harness/validator-system/domain/value-objects/injection-scan-report.ts +55 -0
  47. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +35 -31
  48. package/scripts/harness/validator-system/infrastructure/adapters/adr-foundation-reference-adapter.ts +13 -7
  49. package/scripts/harness/validator-system/infrastructure/adapters/file-system-coverage-attestation-gating-adapter.ts +87 -0
  50. package/scripts/harness/validator-system/infrastructure/adapters/file-system-injection-scan-adapter.ts +82 -0
  51. package/skills/README.md +1 -1
  52. package/skills/codebase-mapper/SKILL.md +1 -1
  53. package/skills/consistency-checker/references//343/203/201/343/202/247/343/203/203/343/202/257/343/203/252/343/202/271/343/203/210.md +1 -1
  54. package/skills/doc-health-checker/SKILL.md +148 -0
  55. package/skills/release-publisher/SKILL.md +101 -0
  56. package/skills/skill-creator/SKILL.md +74 -332
  57. package/skills/story-implementor/SKILL.md +52 -0
  58. package/skills/story-mapper/SKILL.md +4 -0
  59. package/skills/story-writer/SKILL.md +9 -0
  60. package/skills/uiux-designer/references/uiux-design-template.md +4 -4
  61. package/skills/unit-designer/SKILL.md +3 -1
  62. package/skills/doc-freshness-checker/SKILL.md +0 -140
  63. package/skills/implementation-planner/SKILL.md +0 -169
  64. package/skills/implementation-planner/references/document-structure.md +0 -116
  65. package/skills/implementation-planner/references/plan-template.md +0 -177
  66. package/skills/implementation-planner/references/workflow.md +0 -164
  67. package/skills/pointer-validator/SKILL.md +0 -105
@@ -5,24 +5,31 @@
5
5
  *
6
6
  * RunL3ValidatorsUseCase — H08-02: L3バリデータ実行
7
7
  */
8
- import { ValidatorId } from '../../domain/value-objects/validator-id.js';
9
- import { ValidationResult } from '../../domain/value-objects/validation-result.js';
10
- import type { ValidatorRegistry } from '../../domain/services/validator-registry.js';
11
- import { type ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
12
- import { ValidatorLanguageCapabilityService } from '../../domain/services/validator-language-capability-service.js';
13
- import type { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
14
- import type { ValidationResultContract } from '../dto/validation-result-contract.js';
15
- import type { RunL3ValidatorsInput } from '../dto/run-l3-validators-input.js';
16
- import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
17
- import type { AcCoveragePolicyPort } from '../../domain/ports/ac-coverage-policy-port.js';
18
- import type { AcBoundCoveragePolicyPort } from '../../domain/ports/ac-bound-coverage-policy-port.js';
19
- import type { SecurityPatternScannerPort } from '../../domain/ports/security-pattern-scanner-port.js';
20
- import type { PerformanceScannerPort } from '../../domain/ports/performance-scanner-port.js';
8
+
9
+ import type { AcBoundCoveragePolicyPort } from "../../domain/ports/ac-bound-coverage-policy-port.js";
10
+ import type { AcCoveragePolicyPort } from "../../domain/ports/ac-coverage-policy-port.js";
11
+ import type { InjectionScanPolicyPort } from "../../domain/ports/injection-scan-policy-port.js";
12
+ import type { PerformanceScannerPort } from "../../domain/ports/performance-scanner-port.js";
13
+ import type { SecurityPatternScannerPort } from "../../domain/ports/security-pattern-scanner-port.js";
14
+ import type { ValidatorConfigPort } from "../../domain/ports/validator-config-port.js";
15
+ import { InjectionPatternScanService } from "../../domain/services/injection-pattern-scan-service.js";
16
+ import {
17
+ ValidatorExecutionError,
18
+ type ValidatorExecutionService,
19
+ } from "../../domain/services/validator-execution-service.js";
20
+ import { ValidatorLanguageCapabilityService } from "../../domain/services/validator-language-capability-service.js";
21
+ import type { ValidatorRegistry } from "../../domain/services/validator-registry.js";
22
+ import type { HarnessErrorLike } from "../../domain/value-objects/validation-result.js";
23
+ import { ValidationResult } from "../../domain/value-objects/validation-result.js";
24
+ import { ValidatorId } from "../../domain/value-objects/validator-id.js";
25
+ import type { RunL3ValidatorsInput } from "../dto/run-l3-validators-input.js";
26
+ import type { ValidationResultContract } from "../dto/validation-result-contract.js";
27
+ import type { ValidationResultContractMapper } from "../mappers/validation-result-contract-mapper.js";
21
28
 
22
29
  export class CoverageReportNotFoundError extends Error {
23
30
  constructor(path: string) {
24
31
  super(`Coverage report not found: ${path}`);
25
- this.name = 'CoverageReportNotFoundError';
32
+ this.name = "CoverageReportNotFoundError";
26
33
  }
27
34
  }
28
35
 
@@ -33,9 +40,16 @@ export interface RunL3ValidatorsUseCaseDeps {
33
40
  contractMapper: ValidationResultContractMapper;
34
41
  acCoveragePolicyPort?: AcCoveragePolicyPort;
35
42
  acBoundCoveragePolicyPort?: AcBoundCoveragePolicyPort;
36
- coverageReportPort?: { getCoverage(): Promise<{ overallCoverage: number; perFileCoverage: readonly { filePath: string; coverage: number }[] }> };
43
+ coverageReportPort?: {
44
+ getCoverage(): Promise<{
45
+ overallCoverage: number;
46
+ perFileCoverage: readonly { filePath: string; coverage: number }[];
47
+ }>;
48
+ };
37
49
  securityScannerPort?: SecurityPatternScannerPort;
38
50
  performanceScannerPort?: PerformanceScannerPort;
51
+ /** WI-259 / ADR-030 §Decision.3.④: L3-006 (injection-scan, advisory) 用ポート。 */
52
+ injectionScanPolicyPort?: InjectionScanPolicyPort;
39
53
  /** L3-005 のスコープ対象 story-id(config layers.L3.acBoundStories 由来。既定 [])。 */
40
54
  acBoundStories?: readonly string[];
41
55
  }
@@ -47,11 +61,13 @@ export class RunL3ValidatorsUseCase {
47
61
  private readonly mapper: ValidationResultContractMapper;
48
62
  private readonly acCoveragePolicyPort?: AcCoveragePolicyPort;
49
63
  private readonly acBoundCoveragePolicyPort?: AcBoundCoveragePolicyPort;
50
- private readonly coverageReportPort?: RunL3ValidatorsUseCaseDeps['coverageReportPort'];
64
+ private readonly coverageReportPort?: RunL3ValidatorsUseCaseDeps["coverageReportPort"];
51
65
  private readonly securityScannerPort?: SecurityPatternScannerPort;
52
66
  private readonly performanceScannerPort?: PerformanceScannerPort;
67
+ private readonly injectionScanPolicyPort?: InjectionScanPolicyPort;
53
68
  private readonly acBoundStories: readonly string[];
54
69
  private readonly languageCapabilityService = new ValidatorLanguageCapabilityService();
70
+ private readonly injectionScanService = new InjectionPatternScanService();
55
71
 
56
72
  constructor(deps: RunL3ValidatorsUseCaseDeps) {
57
73
  this.registry = deps.validatorRegistry;
@@ -63,6 +79,7 @@ export class RunL3ValidatorsUseCase {
63
79
  this.coverageReportPort = deps.coverageReportPort;
64
80
  this.securityScannerPort = deps.securityScannerPort;
65
81
  this.performanceScannerPort = deps.performanceScannerPort;
82
+ this.injectionScanPolicyPort = deps.injectionScanPolicyPort;
66
83
  this.acBoundStories = deps.acBoundStories ?? [];
67
84
  }
68
85
 
@@ -71,16 +88,19 @@ export class RunL3ValidatorsUseCase {
71
88
  if (input.validatorIds && input.validatorIds.length > 0) {
72
89
  validatorIds = input.validatorIds.map((id) => ValidatorId.create(id));
73
90
  } else {
74
- validatorIds = this.registry.listByLayer('L3').map((d) => d.validatorId);
91
+ validatorIds = this.registry.listByLayer("L3").map((d) => d.validatorId);
75
92
  }
76
93
 
77
94
  const definitions = this.registry.select(validatorIds);
78
95
 
79
- let layerConfig;
96
+ let layerConfig: Awaited<ReturnType<ValidatorConfigPort["getLayerConfig"]>>;
80
97
  try {
81
- layerConfig = await this.configPort.getLayerConfig('L3');
98
+ layerConfig = await this.configPort.getLayerConfig("L3");
82
99
  } catch (err) {
83
- throw new ValidatorExecutionError(`Failed to get L3 LayerConfig: ${err instanceof Error ? err.message : String(err)}`, err);
100
+ throw new ValidatorExecutionError(
101
+ `Failed to get L3 LayerConfig: ${err instanceof Error ? err.message : String(err)}`,
102
+ err,
103
+ );
84
104
  }
85
105
 
86
106
  // LayerConfig.enabled === false の場合は空を返す
@@ -105,18 +125,17 @@ export class RunL3ValidatorsUseCase {
105
125
  // このブロックは例外を送出せず、L3-003 の per-validator 結果のみを差し替える。
106
126
  // これにより兄弟バリデータ(L3-001/002/004 および L2/L4 バッチ)は常に通常実行される。
107
127
  const l3003InScope =
108
- !unsupportedValidatorIds.has('L3-003') &&
109
- definitions.some((d) => d.validatorId.value === 'L3-003');
128
+ !unsupportedValidatorIds.has("L3-003") && definitions.some((d) => d.validatorId.value === "L3-003");
110
129
  if (this.coverageReportPort && l3003InScope) {
111
- const l3003Id = ValidatorId.create('L3-003');
112
- const threshold = layerConfig.getThreshold('coverageThreshold');
130
+ const l3003Id = ValidatorId.create("L3-003");
131
+ const threshold = layerConfig.getThreshold("coverageThreshold");
113
132
 
114
133
  if (threshold === null) {
115
134
  overrideMap.set(
116
- 'L3-003',
135
+ "L3-003",
117
136
  ValidationResult.skipWithReason(
118
137
  l3003Id,
119
- 'coverageThreshold が未設定のためカバレッジ判定をスキップ(カバレッジゲートはオプトイン)',
138
+ "coverageThreshold が未設定のためカバレッジ判定をスキップ(カバレッジゲートはオプトイン)",
120
139
  ),
121
140
  );
122
141
  } else {
@@ -124,13 +143,13 @@ export class RunL3ValidatorsUseCase {
124
143
  const coverageData = await this.coverageReportPort.getCoverage();
125
144
  if (coverageData.overallCoverage < threshold) {
126
145
  overrideMap.set(
127
- 'L3-003',
146
+ "L3-003",
128
147
  ValidationResult.fail(
129
148
  l3003Id,
130
149
  [
131
150
  {
132
- code: 'L3-003',
133
- severity: 'error',
151
+ code: "L3-003",
152
+ severity: "error",
134
153
  message: `カバレッジ不足: 現在値 ${coverageData.overallCoverage}%、不足 ${threshold - coverageData.overallCoverage}%`,
135
154
  suggestion: `テストカバレッジを ${threshold}% 以上に引き上げてください`,
136
155
  },
@@ -139,20 +158,20 @@ export class RunL3ValidatorsUseCase {
139
158
  ),
140
159
  );
141
160
  } else {
142
- overrideMap.set('L3-003', ValidationResult.pass(l3003Id, 0));
161
+ overrideMap.set("L3-003", ValidationResult.pass(l3003Id, 0));
143
162
  }
144
163
  } catch {
145
164
  // レポート不在などで取得失敗 → FAIL-CLOSED(例外は握りつぶし per-validator FAIL に変換)
146
165
  overrideMap.set(
147
- 'L3-003',
166
+ "L3-003",
148
167
  ValidationResult.fail(
149
168
  l3003Id,
150
169
  [
151
170
  {
152
- code: 'L3-003',
153
- severity: 'error',
171
+ code: "L3-003",
172
+ severity: "error",
154
173
  message: `coverageThreshold=${threshold}% が設定されていますがカバレッジレポートが見つかりません(テストをカバレッジ付きで実行してください)`,
155
- suggestion: 'vitest --coverage 等でカバレッジレポートを生成してから再実行してください',
174
+ suggestion: "vitest --coverage 等でカバレッジレポートを生成してから再実行してください",
156
175
  },
157
176
  ],
158
177
  0,
@@ -163,42 +182,35 @@ export class RunL3ValidatorsUseCase {
163
182
  }
164
183
 
165
184
  if (this.securityScannerPort) {
166
- const l3001Result = overrideMap.get('L3-001');
185
+ const l3001Result = overrideMap.get("L3-001");
167
186
  if (l3001Result && !l3001Result.skipped) {
168
187
  const scanResult = await this.securityScannerPort.scan(input.targetPaths);
169
188
  if (!scanResult.passed) {
170
- overrideMap.set('L3-001', ValidationResult.fail(ValidatorId.create('L3-001'), [...scanResult.findings], 0));
189
+ overrideMap.set("L3-001", ValidationResult.fail(ValidatorId.create("L3-001"), [...scanResult.findings], 0));
171
190
  }
172
191
  }
173
192
  }
174
193
 
175
194
  if (this.performanceScannerPort) {
176
- const l3002Result = overrideMap.get('L3-002');
195
+ const l3002Result = overrideMap.get("L3-002");
177
196
  if (l3002Result && !l3002Result.skipped) {
178
- const bundleSizeLimit = layerConfig.getThreshold('bundleSizeLimit');
197
+ const bundleSizeLimit = layerConfig.getThreshold("bundleSizeLimit");
179
198
  const thresholds: Record<string, number> = bundleSizeLimit !== null ? { bundleSizeLimit } : {};
180
199
  const scanResult = await this.performanceScannerPort.scan(input.targetPaths, thresholds);
181
200
  if (!scanResult.passed) {
182
- overrideMap.set('L3-002', ValidationResult.fail(ValidatorId.create('L3-002'), [...scanResult.findings], 0));
201
+ overrideMap.set("L3-002", ValidationResult.fail(ValidatorId.create("L3-002"), [...scanResult.findings], 0));
183
202
  }
184
203
  }
185
204
  }
186
205
 
187
206
  if (this.acCoveragePolicyPort) {
188
- const l3004Result = overrideMap.get('L3-004');
207
+ const l3004Result = overrideMap.get("L3-004");
189
208
  if (l3004Result && !l3004Result.skipped) {
190
209
  const policyResult = await this.acCoveragePolicyPort.checkCoverage({
191
210
  matrixFilePath: input.requirementMatrixPath,
192
211
  });
193
212
  if (!policyResult.passed) {
194
- overrideMap.set(
195
- 'L3-004',
196
- ValidationResult.fail(
197
- ValidatorId.create('L3-004'),
198
- [...policyResult.errors],
199
- 0,
200
- ),
201
- );
213
+ overrideMap.set("L3-004", ValidationResult.fail(ValidatorId.create("L3-004"), [...policyResult.errors], 0));
202
214
  }
203
215
  }
204
216
  }
@@ -206,21 +218,38 @@ export class RunL3ValidatorsUseCase {
206
218
  // L3-005: AC-bound coverage(fail-closed, default-OFF)。
207
219
  // override map に unskipped な L3-005 がある場合のみ policy を呼ぶ(L3-004 と同じ方式)。
208
220
  if (this.acBoundCoveragePolicyPort) {
209
- const l3005Result = overrideMap.get('L3-005');
221
+ const l3005Result = overrideMap.get("L3-005");
210
222
  if (l3005Result && !l3005Result.skipped) {
211
223
  const policyResult = await this.acBoundCoveragePolicyPort.checkAcBoundCoverage({
212
224
  matrixFilePath: input.requirementMatrixPath,
213
225
  acBoundStories: input.acBoundStories ?? this.acBoundStories,
214
226
  });
215
227
  if (!policyResult.passed) {
216
- overrideMap.set(
217
- 'L3-005',
218
- ValidationResult.fail(
219
- ValidatorId.create('L3-005'),
220
- [...policyResult.errors],
221
- 0,
222
- ),
223
- );
228
+ overrideMap.set("L3-005", ValidationResult.fail(ValidatorId.create("L3-005"), [...policyResult.errors], 0));
229
+ }
230
+ }
231
+ }
232
+
233
+ // WI-259 / ADR-030 §Decision.3.④: L3-006 advisory インジェクションスキャナ。
234
+ // 指示搭載ファイルの既知インジェクションパターンを検出し warning-only の finding として報告する。
235
+ // finding は必ず severity=warning のため ADR-017 集約規則(failOnWarning=false 既定)で overall PASS。
236
+ // blocking にしない(§4.(b): 「すり抜け=安全」の誤信頼を避ける)。default-OFF/skip 時は override しない。
237
+ if (this.injectionScanPolicyPort) {
238
+ const l3006Result = overrideMap.get("L3-006");
239
+ if (l3006Result && !l3006Result.skipped) {
240
+ const targets = await this.injectionScanPolicyPort.collect();
241
+ const report = this.injectionScanService.scan(targets);
242
+ if (report.hasFindings()) {
243
+ const errors: HarnessErrorLike[] = report.findings.map((finding) => ({
244
+ code: { value: "L3-006", toString: () => "L3-006" },
245
+ severity: { value: "warning", toString: () => "warning" },
246
+ message: `${finding.sourcePath}:${finding.lineNumber} [${finding.kind}] ${finding.message}`,
247
+ suggestion: finding.suggestion,
248
+ sourcePath: finding.sourcePath,
249
+ }));
250
+ overrideMap.set("L3-006", ValidationResult.fail(ValidatorId.create("L3-006"), errors, 0));
251
+ } else {
252
+ overrideMap.set("L3-006", ValidationResult.pass(ValidatorId.create("L3-006"), 0));
224
253
  }
225
254
  }
226
255
  }
@@ -232,6 +261,6 @@ export class RunL3ValidatorsUseCase {
232
261
  }
233
262
 
234
263
  private async getProjectLanguages(): Promise<readonly string[]> {
235
- return this.configPort.getProjectLanguages ? await this.configPort.getProjectLanguages() : ['typescript'];
264
+ return this.configPort.getProjectLanguages ? await this.configPort.getProjectLanguages() : ["typescript"];
236
265
  }
237
266
  }