phasegate 0.183.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 (100) 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 +17 -17
  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/biome-ast-engine/infrastructure/parsers/comment-density-parser.ts +51 -10
  14. package/scripts/harness/ci-governance/application/dto/pin-integrity-input.ts +8 -0
  15. package/scripts/harness/ci-governance/application/dto/pin-integrity-output.ts +9 -0
  16. package/scripts/harness/ci-governance/application/dto/verify-integrity-input.ts +7 -0
  17. package/scripts/harness/ci-governance/application/dto/verify-integrity-output.ts +10 -0
  18. package/scripts/harness/ci-governance/application/usecases/pin-integrity-usecase.ts +60 -0
  19. package/scripts/harness/ci-governance/application/usecases/verify-integrity-usecase.ts +46 -0
  20. package/scripts/harness/ci-governance/composition-root.ts +68 -65
  21. package/scripts/harness/ci-governance/domain/ports/integrity-manifest-repository-port.ts +14 -0
  22. package/scripts/harness/ci-governance/domain/ports/sha256-hasher-port.ts +10 -0
  23. package/scripts/harness/ci-governance/domain/services/integrity-checker.ts +42 -0
  24. package/scripts/harness/ci-governance/domain/value-objects/integrity-drift.ts +16 -0
  25. package/scripts/harness/ci-governance/domain/value-objects/integrity-manifest.ts +49 -0
  26. package/scripts/harness/ci-governance/domain/value-objects/integrity-target.ts +40 -0
  27. package/scripts/harness/ci-governance/infrastructure/adapters/adr-foundation-existence-adapter.ts +26 -2
  28. package/scripts/harness/ci-governance/infrastructure/adapters/file-system-sha256-hasher-adapter.ts +17 -0
  29. package/scripts/harness/ci-governance/infrastructure/adapters/harness-api-command-existence-adapter.ts +8 -1
  30. package/scripts/harness/ci-governance/infrastructure/adapters/integrity-manifest-json-repository-adapter.ts +83 -0
  31. package/scripts/harness/ci-governance/presentation/handlers/integrity-handler.ts +76 -0
  32. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +53 -28
  33. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +33 -8
  34. package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +90 -0
  35. package/scripts/harness/installation/application/bundled-skill-selection.ts +2 -5
  36. package/scripts/harness/main.ts +257 -105
  37. package/scripts/harness/phase-dependency-model/domain/ports/story-reflection-file-system-port.ts +2 -0
  38. package/scripts/harness/phase-dependency-model/domain/services/story-reflection-checker.ts +8 -0
  39. package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +137 -2
  40. package/scripts/harness/quick-mode/domain/services/quick-mode-judgment-engine.ts +44 -40
  41. package/scripts/harness/setup/skill-deployer.ts +8 -10
  42. package/scripts/harness/skill-quality/domain/services/skill-structure-validator.ts +13 -2
  43. package/scripts/harness/skill-quality/domain/types/skill-kind.ts +6 -0
  44. package/scripts/harness/skill-quality/domain/value-objects/skill-structure.ts +24 -8
  45. package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +82 -49
  46. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +87 -58
  47. package/scripts/harness/validator-system/composition-root.ts +141 -99
  48. package/scripts/harness/validator-system/domain/ports/coverage-attestation-gating-policy-port.ts +14 -0
  49. package/scripts/harness/validator-system/domain/ports/injection-scan-policy-port.ts +14 -0
  50. package/scripts/harness/validator-system/domain/services/coverage-attestation-gating-service.ts +56 -0
  51. package/scripts/harness/validator-system/domain/services/injection-pattern-scan-service.ts +118 -0
  52. package/scripts/harness/validator-system/domain/value-objects/coverage-gating-report.ts +67 -0
  53. package/scripts/harness/validator-system/domain/value-objects/injection-scan-report.ts +55 -0
  54. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +35 -31
  55. package/scripts/harness/validator-system/infrastructure/adapters/adr-foundation-reference-adapter.ts +13 -7
  56. package/scripts/harness/validator-system/infrastructure/adapters/file-system-coverage-attestation-gating-adapter.ts +87 -0
  57. package/scripts/harness/validator-system/infrastructure/adapters/file-system-injection-scan-adapter.ts +82 -0
  58. package/skills/README.md +1 -1
  59. package/skills/cascade-updater/SKILL.md +3 -3
  60. package/skills/codebase-mapper/SKILL.md +6 -6
  61. package/skills/codex-delegator/SKILL.md +4 -3
  62. package/skills/codex-delegator/references/prompt-patterns.md +3 -3
  63. package/skills/codex-delegator/references/review-dimensions.md +1 -1
  64. package/skills/consistency-checker/SKILL.md +1 -1
  65. 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
  66. package/skills/doc-health-checker/SKILL.md +148 -0
  67. package/skills/domain-designer/SKILL.md +4 -2
  68. package/skills/engineering-perspective/SKILL.md +1 -0
  69. package/skills/environment-designer/SKILL.md +8 -6
  70. package/skills/implementation-readiness-checker/SKILL.md +2 -1
  71. package/skills/it-test-designer/SKILL.md +10 -8
  72. package/skills/it-test-logic-designer/SKILL.md +11 -9
  73. package/skills/it-test-logic-designer/references/repository-test-patterns.md +8 -1
  74. package/skills/logical-designer/SKILL.md +5 -3
  75. package/skills/mock-designer/SKILL.md +10 -6
  76. package/skills/phasegate-config-doctor/SKILL.md +3 -2
  77. package/skills/phasegate-toolkit-guide/SKILL.md +1 -0
  78. package/skills/quick-implementor/SKILL.md +1 -1
  79. package/skills/release-publisher/SKILL.md +101 -0
  80. package/skills/scenario-test-designer/SKILL.md +27 -14
  81. package/skills/scenario-test-logic-designer/SKILL.md +10 -8
  82. package/skills/scenario-test-logic-designer/references/msw-patterns.md +3 -1
  83. package/skills/scenario-test-logic-designer/references/playwright-patterns.md +3 -1
  84. package/skills/skill-creator/SKILL.md +75 -332
  85. package/skills/story-implementor/SKILL.md +54 -0
  86. package/skills/story-mapper/SKILL.md +8 -4
  87. package/skills/story-writer/SKILL.md +14 -5
  88. package/skills/test-coverage-checker/SKILL.md +4 -6
  89. package/skills/uiux-designer/SKILL.md +4 -2
  90. package/skills/uiux-designer/references/uiux-design-template.md +4 -4
  91. package/skills/unit-designer/SKILL.md +11 -7
  92. package/skills/unit-test-designer/SKILL.md +25 -11
  93. package/skills/unit-test-logic-designer/SKILL.md +10 -8
  94. package/skills/unit-test-logic-designer/references/test-patterns.md +7 -1
  95. package/skills/doc-freshness-checker/SKILL.md +0 -140
  96. package/skills/implementation-planner/SKILL.md +0 -167
  97. package/skills/implementation-planner/references/document-structure.md +0 -116
  98. package/skills/implementation-planner/references/plan-template.md +0 -177
  99. package/skills/implementation-planner/references/workflow.md +0 -164
  100. package/skills/pointer-validator/SKILL.md +0 -104
@@ -5,12 +5,36 @@
5
5
  * AdrExistencePort実装
6
6
  */
7
7
 
8
+ import * as path from 'node:path';
8
9
  import type { AdrExistencePort } from '../../domain/ports/adr-existence-port.js';
9
10
 
10
11
  export class AdrFoundationExistenceAdapter implements AdrExistencePort {
11
- constructor(private readonly knownAdrIds: string[] = []) {}
12
+ private repositoryPromise: Promise<{
13
+ exists(id: { readonly value: string }): Promise<boolean>;
14
+ }> | null = null;
15
+
16
+ constructor(private readonly rootDir: string = process.cwd()) {}
12
17
 
13
18
  async exists(adrId: string): Promise<boolean> {
14
- return this.knownAdrIds.includes(adrId);
19
+ try {
20
+ const { AdrId } = await import('../../../adr-foundation/domain/value-objects/adr-id.js');
21
+ const id = AdrId.create(adrId);
22
+ const repository = await this.getRepository();
23
+ return repository.exists(id);
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ private async getRepository(): Promise<{
30
+ exists(id: { readonly value: string }): Promise<boolean>;
31
+ }> {
32
+ if (!this.repositoryPromise) {
33
+ this.repositoryPromise = (async () => {
34
+ const { createAdrFoundationModule } = await import('../../../adr-foundation/composition-root.js');
35
+ return createAdrFoundationModule(path.join(this.rootDir, 'docs', 'ADR')).adrRepository;
36
+ })();
37
+ }
38
+ return this.repositoryPromise;
15
39
  }
16
40
  }
@@ -0,0 +1,17 @@
1
+ // @unit ci-governance
2
+ // @layer infrastructure
3
+
4
+ import * as crypto from "node:crypto";
5
+ import * as fs from "node:fs/promises";
6
+ import * as path from "node:path";
7
+ import type { Sha256HasherPort } from "../../domain/ports/sha256-hasher-port.js";
8
+
9
+ export class FileSystemSha256HasherAdapter implements Sha256HasherPort {
10
+ constructor(private readonly baseDir: string) {}
11
+
12
+ async hashFile(relativePath: string): Promise<string> {
13
+ const absPath = path.isAbsolute(relativePath) ? relativePath : path.join(this.baseDir, relativePath);
14
+ const content = await fs.readFile(absPath);
15
+ return crypto.createHash("sha256").update(content).digest("hex");
16
+ }
17
+ }
@@ -1,12 +1,19 @@
1
1
  // @unit ci-governance
2
2
  // @layer infrastructure
3
+ // @work-item-id WI-250
3
4
 
5
+ import { KNOWN_HARNESS_COMMANDS } from '../../../harness-api/domain/value-objects/known-harness-commands.js';
4
6
  import type { CommandExistencePort } from '../../domain/ports/command-existence-port.js';
5
7
 
8
+ /**
9
+ * WI-250: 既知コマンドのデフォルトは harness-api domain の canonical 定数
10
+ * `KNOWN_HARNESS_COMMANDS` を配線する(infra ローカルの重複定義は持たない)。
11
+ * main.ts dispatch との乖離検出は harness-api 側の conformance テストが担う。
12
+ */
6
13
  export class HarnessApiCommandExistenceAdapter implements CommandExistencePort {
7
14
  private readonly knownCommands: Set<string>;
8
15
 
9
- constructor(knownCommands: string[] = []) {
16
+ constructor(knownCommands: string[] = [...KNOWN_HARNESS_COMMANDS]) {
10
17
  this.knownCommands = new Set(knownCommands);
11
18
  }
12
19
 
@@ -0,0 +1,83 @@
1
+ // @unit ci-governance
2
+ // @layer infrastructure
3
+
4
+ import * as fs from "node:fs/promises";
5
+ import * as path from "node:path";
6
+ import type { IntegrityManifestRepositoryPort } from "../../domain/ports/integrity-manifest-repository-port.js";
7
+ import { IntegrityManifest } from "../../domain/value-objects/integrity-manifest.js";
8
+
9
+ interface IntegrityJsonV1 {
10
+ readonly version: 1;
11
+ readonly algorithm: "sha256";
12
+ readonly files: Readonly<Record<string, string>>;
13
+ }
14
+
15
+ /**
16
+ * phasegate.integrity.json(ルート)の読み書きアダプタ。
17
+ * files は path 昇順キーで決定的に書き出す。
18
+ */
19
+ export class IntegrityManifestJsonRepositoryAdapter implements IntegrityManifestRepositoryPort {
20
+ private readonly filePath: string;
21
+
22
+ constructor(baseDir: string, relativePath = "phasegate.integrity.json") {
23
+ this.filePath = path.isAbsolute(relativePath) ? relativePath : path.join(baseDir, relativePath);
24
+ }
25
+
26
+ getPath(): string {
27
+ return this.filePath;
28
+ }
29
+
30
+ async exists(): Promise<boolean> {
31
+ try {
32
+ await fs.access(this.filePath);
33
+ return true;
34
+ } catch {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ async save(manifest: IntegrityManifest): Promise<string> {
40
+ const files: Record<string, string> = {};
41
+ for (const [p, digest] of manifest.sortedEntries()) {
42
+ files[p] = digest;
43
+ }
44
+ const data: IntegrityJsonV1 = {
45
+ version: 1,
46
+ algorithm: "sha256",
47
+ files,
48
+ };
49
+ await fs.mkdir(path.dirname(this.filePath), { recursive: true });
50
+ await fs.writeFile(this.filePath, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
51
+ return this.filePath;
52
+ }
53
+
54
+ async load(): Promise<IntegrityManifest | null> {
55
+ let content: string;
56
+ try {
57
+ content = await fs.readFile(this.filePath, "utf-8");
58
+ } catch (err) {
59
+ if ((err as NodeJS.ErrnoException).code === "ENOENT") return null;
60
+ throw err;
61
+ }
62
+
63
+ let parsed: IntegrityJsonV1;
64
+ try {
65
+ parsed = JSON.parse(content) as IntegrityJsonV1;
66
+ } catch (err) {
67
+ throw new Error(`Invalid integrity JSON at ${this.filePath}: ${String(err)}`);
68
+ }
69
+
70
+ if (
71
+ !parsed ||
72
+ parsed.version !== 1 ||
73
+ parsed.algorithm !== "sha256" ||
74
+ typeof parsed.files !== "object" ||
75
+ parsed.files === null
76
+ ) {
77
+ throw new Error(`Invalid integrity JSON schema at ${this.filePath}`);
78
+ }
79
+
80
+ const files = new Map<string, string>(Object.entries(parsed.files));
81
+ return IntegrityManifest.create({ files });
82
+ }
83
+ }
@@ -0,0 +1,76 @@
1
+ // @unit ci-governance
2
+ // @layer presentation
3
+
4
+ import type { PinIntegrityUseCase } from "../../application/usecases/pin-integrity-usecase.js";
5
+ import type { VerifyIntegrityUseCase } from "../../application/usecases/verify-integrity-usecase.js";
6
+ import type { IntegrityDriftKind } from "../../domain/value-objects/integrity-drift.js";
7
+
8
+ export interface IntegrityPinArgs {
9
+ readonly dryRun?: boolean;
10
+ readonly format?: "human" | "json";
11
+ }
12
+
13
+ export interface IntegrityVerifyArgs {
14
+ readonly format?: "human" | "json";
15
+ }
16
+
17
+ export interface IntegrityHandlerResult {
18
+ readonly exitCode: number;
19
+ readonly output: string;
20
+ }
21
+
22
+ const DRIFT_LABEL: Record<IntegrityDriftKind, string> = {
23
+ mismatch: "MISMATCH (digest 不一致)",
24
+ added: "ADDED (manifest 未登録)",
25
+ missing: "MISSING (実ファイル欠落)",
26
+ "manifest-absent": "MANIFEST-ABSENT (manifest 欠落)",
27
+ };
28
+
29
+ export class IntegrityHandler {
30
+ constructor(
31
+ private readonly pinUseCase: PinIntegrityUseCase,
32
+ private readonly verifyUseCase: VerifyIntegrityUseCase,
33
+ ) {}
34
+
35
+ async pin(args: IntegrityPinArgs): Promise<IntegrityHandlerResult> {
36
+ const format = args.format ?? "human";
37
+ const result = await this.pinUseCase.execute({ dryRun: args.dryRun });
38
+
39
+ if (format === "json") {
40
+ return { exitCode: 0, output: JSON.stringify(result, null, 2) };
41
+ }
42
+
43
+ const header = result.dryRun
44
+ ? `[dry run] integrity manifest を生成しました(保存先想定: ${result.savedPath})`
45
+ : `integrity manifest を保存しました: ${result.savedPath}`;
46
+ return {
47
+ exitCode: 0,
48
+ output: [header, `エントリ数: ${result.entryCount}`].join("\n"),
49
+ };
50
+ }
51
+
52
+ async verify(args: IntegrityVerifyArgs): Promise<IntegrityHandlerResult> {
53
+ const format = args.format ?? "human";
54
+ const result = await this.verifyUseCase.execute();
55
+ const exitCode = result.ok ? 0 : 2;
56
+
57
+ if (format === "json") {
58
+ return { exitCode, output: JSON.stringify(result, null, 2) };
59
+ }
60
+
61
+ if (result.ok) {
62
+ return {
63
+ exitCode: 0,
64
+ output: `integrity 照合 OK: drift はありません(${result.manifestPath})`,
65
+ };
66
+ }
67
+
68
+ const lines = [
69
+ `integrity drift を ${result.drifts.length} 件検出しました(${result.manifestPath}):`,
70
+ ...result.drifts.map((d) => `- [${DRIFT_LABEL[d.kind]}] ${d.path}`),
71
+ "",
72
+ "意図的な変更であれば `phasegate integrity:pin` で manifest を更新してください。",
73
+ ];
74
+ return { exitCode: 2, output: lines.join("\n") };
75
+ }
76
+ }
@@ -4,50 +4,70 @@
4
4
  * @work-item-id WI-133 / WI-156
5
5
  * @work-item-id WI-217
6
6
  * @work-item-id WI-212
7
+ * @work-item-id WI-258
8
+ * @work-item-id WI-259
7
9
  */
8
- import type { HarnessConfigV2 } from '../../domain/harness-config.js';
10
+ import type { HarnessConfigV2 } from "../../domain/harness-config.js";
9
11
 
10
12
  export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefined): object | undefined {
11
13
  if (!resolvedConfig) return undefined;
12
14
 
13
- const l3Validators = normalizeValidators(resolvedConfig.layers.L3.validators, {
14
- security: 'L3-001',
15
- performance: 'L3-002',
16
- coverage: 'L3-003',
17
- nyquist: 'L3-004',
18
- 'ac-bound-coverage': 'L3-005',
19
- }, /^L3-\d{3}$/);
20
- const l4Validators = normalizeValidators(resolvedConfig.layers.L4.validators, {
21
- 'drift-detect': 'L4-001',
22
- 'drift-detector': 'L4-001',
23
- 'consistency-check': 'L4-002',
24
- 'consistency-checker': 'L4-002',
25
- 'dead-code': 'L4-003',
26
- 'dead-code-detector': 'L4-003',
27
- 'doc-freshness': 'L4-004',
28
- 'doc-freshness-checker': 'L4-004',
29
- 'pointer-validation': 'L4-005',
30
- 'pointer-validator': 'L4-005',
31
- 'skill-catalog-drift': 'L4-006',
32
- }, /^L4-\d{3}$/);
15
+ const l3Validators = normalizeValidators(
16
+ resolvedConfig.layers.L3.validators,
17
+ {
18
+ security: "L3-001",
19
+ performance: "L3-002",
20
+ coverage: "L3-003",
21
+ nyquist: "L3-004",
22
+ "ac-bound-coverage": "L3-005",
23
+ "injection-scan": "L3-006",
24
+ },
25
+ /^L3-\d{3}$/,
26
+ );
27
+ const l4Validators = normalizeValidators(
28
+ resolvedConfig.layers.L4.validators,
29
+ {
30
+ "drift-detect": "L4-001",
31
+ "drift-detector": "L4-001",
32
+ "consistency-check": "L4-002",
33
+ "consistency-checker": "L4-002",
34
+ "dead-code": "L4-003",
35
+ "dead-code-detector": "L4-003",
36
+ "doc-freshness": "L4-004",
37
+ "doc-freshness-checker": "L4-004",
38
+ "pointer-validation": "L4-005",
39
+ "pointer-validator": "L4-005",
40
+ "skill-catalog-drift": "L4-006",
41
+ },
42
+ /^L4-\d{3}$/,
43
+ );
33
44
  const effectiveL4Validators = usesCustomDocumentRoots(resolvedConfig)
34
- ? includeValidator(l4Validators, 'L4-002')
45
+ ? includeValidator(l4Validators, "L4-002")
35
46
  : l4Validators;
36
47
 
37
48
  return {
38
49
  project: {
39
50
  preset: resolvedConfig.project.preset,
40
- languages: resolvedConfig.project.languages ?? ['typescript'],
51
+ languages: resolvedConfig.project.languages ?? ["typescript"],
41
52
  },
42
53
  paths: {
43
54
  designDocs: resolvedConfig.paths.designDocs,
44
55
  inceptionDocs: resolvedConfig.paths.inceptionDocs,
45
56
  },
46
57
  layers: {
47
- L2: { enabled: resolvedConfig.layers.L2.enabled, validators: ['L2-001', 'L2-002', 'L2-003', 'L2-013', 'L2-014', 'L2-015'] },
58
+ // WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating) default-ON でリストに含める。
59
+ L2: {
60
+ enabled: resolvedConfig.layers.L2.enabled,
61
+ validators: ["L2-001", "L2-002", "L2-003", "L2-013", "L2-014", "L2-015", "L2-016"],
62
+ },
48
63
  L3: {
49
64
  enabled: resolvedConfig.layers.L3.enabled,
50
- validators: l3Validators.length > 0 ? l3Validators : ['L3-001', 'L3-002', 'L3-003', 'L3-004'],
65
+ // WI-259 / ADR-030 §Decision.3.④: L3-006 (injection-scan) advisory default-ON。
66
+ // fallback 判定の後に force-include し、normalize 結果でも fallback でも常に含める(warning-only ゆえ安全)。
67
+ validators: includeValidator(
68
+ l3Validators.length > 0 ? l3Validators : ["L3-001", "L3-002", "L3-003", "L3-004"],
69
+ "L3-006",
70
+ ),
51
71
  coverageThreshold: resolvedConfig.layers.L3.coverageThreshold,
52
72
  requirementMatrixPath: resolvedConfig.layers.L3.requirementMatrixPath,
53
73
  // WI-227 / H16-03: L3-005 のスコープ(additive-safe。未設定は [])
@@ -55,7 +75,10 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
55
75
  },
56
76
  L4: {
57
77
  enabled: resolvedConfig.layers.L4.enabled,
58
- validators: effectiveL4Validators.length > 0 ? effectiveL4Validators : ['L4-001', 'L4-002', 'L4-003', 'L4-004', 'L4-005', 'L4-006'],
78
+ validators:
79
+ effectiveL4Validators.length > 0
80
+ ? effectiveL4Validators
81
+ : ["L4-001", "L4-002", "L4-003", "L4-004", "L4-005", "L4-006"],
59
82
  },
60
83
  },
61
84
  harnesses: {
@@ -70,8 +93,10 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
70
93
  }
71
94
 
72
95
  function usesCustomDocumentRoots(resolvedConfig: HarnessConfigV2): boolean {
73
- return resolvedConfig.paths.designDocs !== 'docs/product/construction'
74
- || resolvedConfig.paths.inceptionDocs !== 'docs/inception';
96
+ return (
97
+ resolvedConfig.paths.designDocs !== "docs/product/construction" ||
98
+ resolvedConfig.paths.inceptionDocs !== "docs/inception"
99
+ );
75
100
  }
76
101
 
77
102
  function includeValidator(validators: readonly string[], validatorId: string): readonly string[] {
@@ -2,7 +2,7 @@
2
2
  // @unit harness-api
3
3
  // ci-check-result.ts — CiCheckResult Value Object
4
4
 
5
- import type { HarnessError } from './harness-api-response.js';
5
+ import type { HarnessError } from "./harness-api-response.js";
6
6
 
7
7
  export interface ValidatorCheckItem {
8
8
  validatorId: string;
@@ -14,6 +14,30 @@ export interface ValidatorCheckItem {
14
14
  export interface CiCheckResultProps {
15
15
  validatorResults: readonly ValidatorCheckItem[];
16
16
  allPassed: boolean;
17
+ /** WI-260 / ADR-017: warning-only failure を fail 扱いにする opt-in(既定 false)。 */
18
+ failOnWarning?: boolean;
19
+ }
20
+
21
+ /**
22
+ * WI-260 / ADR-017: validator 1件が「実質 pass」か判定する severity-aware ルール。
23
+ * `validate` 経路の AggregateValidationResultsUseCase と同一の判定式を harness-api の
24
+ * domain VO 側に持たせ、ci-check と validate の集約挙動を一致させる(レイヤー越境回避のため
25
+ * usecase を直接 import せず判定ロジックを共有)。
26
+ *
27
+ * - skipped: 実質 pass
28
+ * - passed=true: 実質 pass
29
+ * - passed=false かつ error severity(!= warning)を含む: fail
30
+ * - passed=false かつ errors=[](severity 判定不能): 安全側に倒して fail
31
+ * - passed=false かつ warning のみ: failOnWarning=false(既定)で実質 pass、true で fail
32
+ */
33
+ function isEffectivelyPassed(item: ValidatorCheckItem, failOnWarning: boolean): boolean {
34
+ if (item.skipped || item.passed) return true;
35
+ const errors = item.errors ?? [];
36
+ const hasNonWarningError = errors.some((e) => e.severity !== "warning");
37
+ const hasWarnings = errors.some((e) => e.severity === "warning");
38
+ const isEmptyFail = errors.length === 0;
39
+ const hasFail = isEmptyFail || hasNonWarningError || (failOnWarning && hasWarnings);
40
+ return !hasFail;
17
41
  }
18
42
 
19
43
  export class CiCheckResult {
@@ -29,23 +53,24 @@ export class CiCheckResult {
29
53
  static create(props: CiCheckResultProps): CiCheckResult {
30
54
  // INV-5: validatorResults は 1件以上
31
55
  if (!props.validatorResults || props.validatorResults.length === 0) {
32
- throw new Error('EmptyValidatorResultsError: validatorResults must have at least one item (INV-5)');
56
+ throw new Error("EmptyValidatorResultsError: validatorResults must have at least one item (INV-5)");
33
57
  }
34
- // INV-6: allPassed === validatorResults.every(r => r.passed || r.skipped)
35
- const computedAllPassed = props.validatorResults.every((r) => r.passed || r.skipped);
58
+ // INV-6 (WI-260/ADR-017 更新): allPassed === validatorResults.every(実質pass)
59
+ const failOnWarning = props.failOnWarning ?? false;
60
+ const computedAllPassed = props.validatorResults.every((r) => isEffectivelyPassed(r, failOnWarning));
36
61
  if (props.allPassed !== computedAllPassed) {
37
62
  throw new Error(
38
- `HarnessApiDomainError: allPassed=${props.allPassed} does not match validatorResults state (computed: ${computedAllPassed})`
63
+ `HarnessApiDomainError: allPassed=${props.allPassed} does not match validatorResults state (computed: ${computedAllPassed})`,
39
64
  );
40
65
  }
41
66
  return new CiCheckResult(props.validatorResults, props.allPassed);
42
67
  }
43
68
 
44
- static fromResults(validatorResults: readonly ValidatorCheckItem[]): CiCheckResult {
69
+ static fromResults(validatorResults: readonly ValidatorCheckItem[], failOnWarning = false): CiCheckResult {
45
70
  if (!validatorResults || validatorResults.length === 0) {
46
- throw new Error('EmptyValidatorResultsError: validatorResults must have at least one item (INV-5)');
71
+ throw new Error("EmptyValidatorResultsError: validatorResults must have at least one item (INV-5)");
47
72
  }
48
- const allPassed = validatorResults.every((r) => r.passed || r.skipped);
73
+ const allPassed = validatorResults.every((r) => isEffectivelyPassed(r, failOnWarning));
49
74
  return new CiCheckResult(validatorResults, allPassed);
50
75
  }
51
76
 
@@ -0,0 +1,90 @@
1
+ // @unit harness-api
2
+ // @layer domain
3
+ // @work-item-id WI-250
4
+ // known-harness-commands.ts — CLI 実サーフェスの canonical 既知コマンド一覧
5
+ //
6
+ // main.ts の CLI dispatch(`switch (command)`)が受理する全トップレベルコマンド名の
7
+ // 単一ソース。`phasegate:` prefix 必須の CommandRegistry では表現できない
8
+ // 非 prefix コマンド(lint / init / baseline 等)を含む完全なサーフェスを表す。
9
+ //
10
+ // 不変条件(conformance テストで強制):
11
+ // - main.ts の `case "..."` ラベル集合と集合一致すること
12
+ // (__tests__/integration/harness-api/known-harness-commands-conformance.test.ts)
13
+ // - エントリは重複なくソート済みであること
14
+ //
15
+ // main.ts にコマンドを追加/削除した場合は、必ずこのリストも同期更新すること。
16
+
17
+ export const KNOWN_HARNESS_COMMANDS: readonly string[] = Object.freeze([
18
+ "baseline",
19
+ "bypass:audit",
20
+ "check-change-category",
21
+ "check-phase-gate",
22
+ "ci-check",
23
+ "ci:auto-refresh-agent-context",
24
+ "ci:check-repetition",
25
+ "ci:generate-template",
26
+ "ci:migrate-agents-md",
27
+ "commit-msg",
28
+ "complete-check",
29
+ "config:plan",
30
+ "delegate-sonnet",
31
+ "disable-feature",
32
+ "doctor",
33
+ "emit-agent-rules",
34
+ "enable-feature",
35
+ "hook",
36
+ "init",
37
+ "install",
38
+ "integrity:pin",
39
+ "integrity:verify",
40
+ "lint",
41
+ "list-adrs",
42
+ "list-errors",
43
+ "list-features",
44
+ "migrate",
45
+ "p2:check-agent-context",
46
+ "p2:check-freshness",
47
+ "p2:check-initial-creation",
48
+ "p2:generate-e2e-template",
49
+ "p2:validate-pointers",
50
+ "phasegate:attest",
51
+ "phasegate:check-phase",
52
+ "phasegate:check-ready",
53
+ "phasegate:ci-check",
54
+ "phasegate:complete-check",
55
+ "phasegate:detect-drift",
56
+ "phasegate:generate-matrix",
57
+ "phasegate:impact-analysis",
58
+ "phasegate:lint",
59
+ "phasegate:status",
60
+ "phasegate:verify-attestation",
61
+ "pre-commit",
62
+ "reconcile",
63
+ "refresh-claude-md",
64
+ "regression:analyze-migration",
65
+ "regression:configure-ci-gate",
66
+ "regression:migrate-v0-tests",
67
+ "regression:run-agent-guard",
68
+ "regression:run-gng-gate",
69
+ "regression:run-k-requirements",
70
+ "regression:run-k14-k15",
71
+ "render-errors",
72
+ "scaffold-design",
73
+ "scaffold-wi",
74
+ "session",
75
+ "setup:agent",
76
+ "skill:apply-cascade-update",
77
+ "skill:check-coverage",
78
+ "skill:collect-lessons",
79
+ "skill:execute-tdd-cycle",
80
+ "skill:validate-structure",
81
+ "skills",
82
+ "status",
83
+ "uninstall",
84
+ "update-skills",
85
+ "validate",
86
+ "validate-adr",
87
+ "validate-fix",
88
+ "validate-metadata",
89
+ "work-items:status",
90
+ ]);
@@ -8,17 +8,15 @@ const CORE_SKILLS = [
8
8
  "cascade-updater",
9
9
  "codebase-mapper",
10
10
  "consistency-checker",
11
- "doc-freshness-checker",
11
+ "doc-health-checker",
12
12
  "engineering-perspective",
13
13
  "implementation-readiness-checker",
14
- "pointer-validator",
15
14
  "test-coverage-checker",
16
15
  ] as const;
17
16
 
18
17
  const AIDLC_SKILLS = [
19
18
  "domain-designer",
20
19
  "environment-designer",
21
- "implementation-planner",
22
20
  "it-test-designer",
23
21
  "it-test-logic-designer",
24
22
  "logical-designer",
@@ -37,10 +35,9 @@ const AIDLC_SKILLS = [
37
35
  ] as const;
38
36
 
39
37
  const UTILITY_SKILLS = ["codex-delegator", "skill-creator"] as const;
40
- const GUIDANCE_SKILLS = ["phasegate-toolkit-guide", "phasegate-config-doctor"] as const;
38
+ const GUIDANCE_SKILLS = ["phasegate-toolkit-guide", "phasegate-config-doctor", "release-publisher"] as const;
41
39
 
42
40
  export function getBundledSkillsForSet(skillSet: SkillSet): string[] {
43
41
  if (skillSet === "core") return [...CORE_SKILLS];
44
42
  return [...CORE_SKILLS, ...AIDLC_SKILLS, ...UTILITY_SKILLS, ...GUIDANCE_SKILLS];
45
43
  }
46
-