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
@@ -0,0 +1,55 @@
1
+ // @unit validator-system
2
+ // @layer domain
3
+ // @work-item-id WI-259
4
+
5
+ /**
6
+ * WI-259 / ADR-030 §Decision.3.④ — advisory インジェクションスキャナ(L3-006)用ドメインモデル。
7
+ *
8
+ * 指示搭載ファイルに対する既知インジェクションパターンの検出結果を表す value-object 群。
9
+ * 全 finding は severity='warning'(advisory)。error / violation は構造上生成しない(§4.(b))。
10
+ */
11
+
12
+ /** 検出種別。 */
13
+ export type InjectionFindingKind =
14
+ | "instruction-override"
15
+ | "invisible-unicode"
16
+ | "base64-blob"
17
+ | "html-comment-instruction";
18
+
19
+ /** 1 走査対象ファイル(infra が解決)。 */
20
+ export interface InjectionScanTarget {
21
+ /** project-relative パス(報告用)。 */
22
+ readonly path: string;
23
+ readonly content: string;
24
+ }
25
+
26
+ /** 1 件の検出。severity は常に 'warning'。 */
27
+ export interface InjectionFinding {
28
+ readonly kind: InjectionFindingKind;
29
+ readonly severity: "warning";
30
+ readonly sourcePath: string;
31
+ /** 1 起点の行番号。 */
32
+ readonly lineNumber: number;
33
+ readonly message: string;
34
+ readonly suggestion: string;
35
+ }
36
+
37
+ /**
38
+ * スキャン判定レポート。findings はすべて warning(advisory)。
39
+ */
40
+ export class InjectionScanReport {
41
+ readonly findings: readonly InjectionFinding[];
42
+
43
+ private constructor(findings: readonly InjectionFinding[]) {
44
+ this.findings = Object.freeze([...findings]);
45
+ Object.freeze(this);
46
+ }
47
+
48
+ static create(findings: readonly InjectionFinding[]): InjectionScanReport {
49
+ return new InjectionScanReport(findings);
50
+ }
51
+
52
+ hasFindings(): boolean {
53
+ return this.findings.length > 0;
54
+ }
55
+ }
@@ -11,13 +11,15 @@
11
11
  * WI-156 で L4-006 を追加
12
12
  * WI-222 (HF2-05) で L4-007(ac-level-traceability, default-OFF advisory)を追加
13
13
  * WI-227 (H16-03) で L3-005(ac-bound-coverage, default-OFF fail-closed)を追加
14
+ * WI-258 (ADR-030 §Decision.3.②) で L2-016(coverage-attestation-gating, fail-closed)を追加
15
+ * WI-259 (ADR-030 §Decision.3.④) で L3-006(injection-scan, advisory warning-only)を追加
14
16
  */
15
17
 
16
18
  export class InvalidValidatorIdError extends Error {
17
19
  readonly invalidValue: string;
18
20
  constructor(raw: string) {
19
21
  super(`Invalid validator ID: "${raw}". Must be one of the registered valid IDs.`);
20
- this.name = 'InvalidValidatorIdError';
22
+ this.name = "InvalidValidatorIdError";
21
23
  this.invalidValue = raw;
22
24
  }
23
25
  }
@@ -26,38 +28,40 @@ const VALIDATOR_ID_PATTERN = /^L[0-4]-\d{3}$/;
26
28
 
27
29
  /** バリデータID -> バリデータ名のマップ */
28
30
  const VALIDATOR_NAME_MAP: Record<string, string> = {
29
- 'L1-017': 'it-test-mock-detection',
30
- 'L1-018': 'stub-comment-detection',
31
- 'L2-001': 'phase-gate',
32
- 'L2-002': 'metadata',
33
- 'L2-003': 'test-quality',
34
- 'L2-013': 'cli-e2e-test-existence',
35
- 'L2-014': 'work-item-status-staleness',
36
- 'L2-015': 'contract-traceability-coverage',
37
- 'L3-001': 'security',
38
- 'L3-002': 'performance',
39
- 'L3-003': 'coverage',
40
- 'L3-004': 'nyquist',
41
- 'L3-005': 'ac-bound-coverage',
42
- 'L4-001': 'drift-detect',
43
- 'L4-002': 'consistency-check',
44
- 'L4-003': 'dead-code',
45
- 'L4-004': 'doc-freshness',
46
- 'L4-005': 'pointer-validation',
47
- 'L4-006': 'skill-catalog-drift',
48
- 'L4-007': 'ac-level-traceability',
31
+ "L1-017": "it-test-mock-detection",
32
+ "L1-018": "stub-comment-detection",
33
+ "L2-001": "phase-gate",
34
+ "L2-002": "metadata",
35
+ "L2-003": "test-quality",
36
+ "L2-013": "cli-e2e-test-existence",
37
+ "L2-014": "work-item-status-staleness",
38
+ "L2-015": "contract-traceability-coverage",
39
+ "L2-016": "coverage-attestation-gating",
40
+ "L3-001": "security",
41
+ "L3-002": "performance",
42
+ "L3-003": "coverage",
43
+ "L3-004": "nyquist",
44
+ "L3-005": "ac-bound-coverage",
45
+ "L3-006": "injection-scan",
46
+ "L4-001": "drift-detect",
47
+ "L4-002": "consistency-check",
48
+ "L4-003": "dead-code",
49
+ "L4-004": "doc-freshness",
50
+ "L4-005": "pointer-validation",
51
+ "L4-006": "skill-catalog-drift",
52
+ "L4-007": "ac-level-traceability",
49
53
  };
50
54
 
51
55
  /** バリデータ名 -> バリデータID の逆引きマップ */
52
56
  const NAME_TO_ID_MAP: Record<string, string> = {
53
57
  ...Object.fromEntries(Object.entries(VALIDATOR_NAME_MAP).map(([id, name]) => [name, id])),
54
- 'drift-detector': 'L4-001',
55
- 'consistency-checker': 'L4-002',
56
- 'dead-code-detector': 'L4-003',
57
- 'doc-freshness-checker': 'L4-004',
58
- 'pointer-validator': 'L4-005',
59
- 'skill-catalog-drift': 'L4-006',
60
- 'ac-level-traceability': 'L4-007',
58
+ "drift-detector": "L4-001",
59
+ "consistency-checker": "L4-002",
60
+ "dead-code-detector": "L4-003",
61
+ "doc-freshness-checker": "L4-004",
62
+ "pointer-validator": "L4-005",
63
+ "skill-catalog-drift": "L4-006",
64
+ "ac-level-traceability": "L4-007",
61
65
  };
62
66
 
63
67
  /** 有効なValidatorID集合 */
@@ -65,12 +69,12 @@ const VALID_IDS = new Set(Object.keys(VALIDATOR_NAME_MAP));
65
69
 
66
70
  export class ValidatorId {
67
71
  readonly value: string;
68
- readonly layer: 'L0' | 'L1' | 'L2' | 'L3' | 'L4';
72
+ readonly layer: "L0" | "L1" | "L2" | "L3" | "L4";
69
73
  readonly sequence: string;
70
74
 
71
75
  private constructor(value: string) {
72
76
  this.value = value;
73
- this.layer = value.substring(0, 2) as 'L0' | 'L1' | 'L2' | 'L3' | 'L4';
77
+ this.layer = value.substring(0, 2) as "L0" | "L1" | "L2" | "L3" | "L4";
74
78
  this.sequence = value.substring(3);
75
79
  Object.freeze(this);
76
80
  }
@@ -93,7 +97,7 @@ export class ValidatorId {
93
97
  return new ValidatorId(id);
94
98
  }
95
99
 
96
- getLayer(): 'L0' | 'L1' | 'L2' | 'L3' | 'L4' {
100
+ getLayer(): "L0" | "L1" | "L2" | "L3" | "L4" {
97
101
  return this.layer;
98
102
  }
99
103
 
@@ -4,9 +4,12 @@
4
4
  *
5
5
  * AdrFoundationReferenceAdapter — AdrReferencePort実装
6
6
  */
7
- import type { AdrReferencePort, AdrMetadata } from '../../domain/ports/adr-reference-port.js';
7
+ import * as path from "node:path";
8
+ import type { AdrMetadata, AdrReferencePort } from "../../domain/ports/adr-reference-port.js";
8
9
 
9
10
  export class AdrFoundationReferenceAdapter implements AdrReferencePort {
11
+ constructor(private readonly rootDir: string = process.cwd()) {}
12
+
10
13
  async exists(adrRef: string): Promise<boolean> {
11
14
  try {
12
15
  const adr = await this.findAdr(adrRef);
@@ -35,19 +38,22 @@ export class AdrFoundationReferenceAdapter implements AdrReferencePort {
35
38
  }
36
39
 
37
40
  private async findAdr(adrRef: string): Promise<{
38
- readonly getFrontmatter: () => { readonly title: string; readonly status: { readonly value: AdrMetadata['status'] } };
41
+ readonly getFrontmatter: () => {
42
+ readonly title: string;
43
+ readonly status: { readonly value: AdrMetadata["status"] };
44
+ };
39
45
  readonly toAdrRef: () => string;
40
46
  } | null> {
41
- const { createAdrFoundationModule } = await import('../../../adr-foundation/composition-root.js');
42
- const { AdrId } = await import('../../../adr-foundation/domain/value-objects/adr-id.js');
43
- const mod = createAdrFoundationModule(process.cwd());
47
+ const { createAdrFoundationModule } = await import("../../../adr-foundation/composition-root.js");
48
+ const { AdrId } = await import("../../../adr-foundation/domain/value-objects/adr-id.js");
49
+ const mod = createAdrFoundationModule(path.join(this.rootDir, "docs", "ADR"));
44
50
  const repository = mod.adrRepository;
45
51
 
46
- if ('findById' in repository && typeof repository.findById === 'function') {
52
+ if ("findById" in repository && typeof repository.findById === "function") {
47
53
  return repository.findById(AdrId.create(adrRef));
48
54
  }
49
55
 
50
- if ('findAll' in repository && typeof repository.findAll === 'function') {
56
+ if ("findAll" in repository && typeof repository.findAll === "function") {
51
57
  const adrs = await repository.findAll();
52
58
  return adrs.find((adr) => adr.toAdrRef() === adrRef) ?? null;
53
59
  }
@@ -0,0 +1,87 @@
1
+ // @unit validator-system
2
+ // @layer infrastructure
3
+ // @work-item-id WI-258
4
+
5
+ import { readdir, readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ import type { CoverageAttestationGatingPolicyPort } from "../../domain/ports/coverage-attestation-gating-policy-port.js";
8
+ import type { CoverageClaim, CoverageReportGatingModel } from "../../domain/value-objects/coverage-gating-report.js";
9
+
10
+ const COVERAGE_REPORT_FILE = "coverage_report.md";
11
+ const CONSTRUCTION_REL = join("docs", "product", "construction");
12
+ const LEGACY_MARKER = /<!--\s*@coverage-gating:\s*ungated-legacy\s*-->/;
13
+ const ATTESTATION_REF = /<!--\s*@attestation\b/;
14
+ const CHECKMARK = "✅"; // ✅
15
+ const COMMENT_LINE = /^\s*<!--/;
16
+
17
+ /**
18
+ * WI-258 / ADR-030 §Decision.3.② — coverage-attestation-gating (L2-016) の走査アダプタ。
19
+ *
20
+ * `docs/product/construction/*​/coverage_report.md` を cwd 起点で走査し(targetPaths 非依存の
21
+ * corpus 走査。L2-014 と同様に自前でファイル探索する)、各ファイルを CoverageReportGatingModel 化する。
22
+ *
23
+ * - legacy マーカー: `<!-- @coverage-gating: ungated-legacy -->` の有無。
24
+ * - ✅ claim: `✅` を含む行。同一行に `<!-- @attestation ... -->` があるか、
25
+ * 直前の連続コメント行に `@attestation` があれば hasAttestationRef=true。
26
+ */
27
+ export class FileSystemCoverageAttestationGatingAdapter implements CoverageAttestationGatingPolicyPort {
28
+ constructor(private readonly projectRoot: string) {}
29
+
30
+ async collect(): Promise<readonly CoverageReportGatingModel[]> {
31
+ const constructionRoot = join(this.projectRoot, CONSTRUCTION_REL);
32
+ let unitDirs: string[];
33
+ try {
34
+ const entries = await readdir(constructionRoot, { withFileTypes: true });
35
+ unitDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
36
+ } catch {
37
+ return Object.freeze([]);
38
+ }
39
+
40
+ const models: CoverageReportGatingModel[] = [];
41
+ for (const unitDir of unitDirs) {
42
+ const filePath = join(constructionRoot, unitDir, COVERAGE_REPORT_FILE);
43
+ let content: string;
44
+ try {
45
+ content = await readFile(filePath, "utf-8");
46
+ } catch {
47
+ continue;
48
+ }
49
+ // path は project-relative で報告する(メッセージの可搬性のため)。
50
+ const relPath = `${CONSTRUCTION_REL.replace(/\\/g, "/")}/${unitDir}/${COVERAGE_REPORT_FILE}`;
51
+ models.push(this.parse(relPath, content));
52
+ }
53
+ return Object.freeze(models);
54
+ }
55
+
56
+ private parse(path: string, content: string): CoverageReportGatingModel {
57
+ const lines = content.split(/\r?\n/);
58
+ const hasLegacyMarker = lines.some((line) => LEGACY_MARKER.test(line));
59
+
60
+ const claims: CoverageClaim[] = [];
61
+ for (let i = 0; i < lines.length; i++) {
62
+ const line = lines[i];
63
+ if (!line.includes(CHECKMARK)) continue;
64
+ claims.push({
65
+ lineNumber: i + 1,
66
+ hasAttestationRef: this.hasAttestationRef(lines, i),
67
+ });
68
+ }
69
+
70
+ return { path, hasLegacyMarker, claims };
71
+ }
72
+
73
+ /**
74
+ * ✅ 行 index について attestation 参照があるか判定する。
75
+ * (1) 同一行にコメント参照、または
76
+ * (2) 直前の連続するコメント行のいずれかに `@attestation` 参照がある。
77
+ */
78
+ private hasAttestationRef(lines: readonly string[], index: number): boolean {
79
+ if (ATTESTATION_REF.test(lines[index])) return true;
80
+ for (let j = index - 1; j >= 0; j--) {
81
+ const prev = lines[j];
82
+ if (!COMMENT_LINE.test(prev)) break;
83
+ if (ATTESTATION_REF.test(prev)) return true;
84
+ }
85
+ return false;
86
+ }
87
+ }
@@ -0,0 +1,82 @@
1
+ // @unit validator-system
2
+ // @layer infrastructure
3
+ // @work-item-id WI-259
4
+
5
+ import { readdir, readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ import type { InjectionScanPolicyPort } from "../../domain/ports/injection-scan-policy-port.js";
8
+ import type { InjectionScanTarget } from "../../domain/value-objects/injection-scan-report.js";
9
+
10
+ const SKILLS_DIR = "skills";
11
+ const SKILL_FILE = "SKILL.md";
12
+ const AGENT_CONTEXT_REL = join("docs", "templates", "agent-context");
13
+
14
+ /** 固定パスの指示搭載ファイル(cwd 相対)。存在しなければ skip。 */
15
+ const FIXED_FILES: readonly string[] = ["CLAUDE.md", "AGENTS.md", join(".claude", "settings.json")];
16
+
17
+ /**
18
+ * WI-259 / ADR-030 §Decision.3.④ — advisory インジェクションスキャナ(L3-006)の走査アダプタ。
19
+ *
20
+ * 指示搭載ファイル群を cwd 起点で列挙・読み込みして InjectionScanTarget[] を返す
21
+ * (targetPaths 非依存の corpus 走査。L2-016 と同様に自前でファイル探索する):
22
+ * - `skills/*​/SKILL.md`(readdir)
23
+ * - `CLAUDE.md` / `AGENTS.md` / `.claude/settings.json`(固定パス)
24
+ * - `docs/templates/agent-context/*.md`(readdir)
25
+ *
26
+ * 不在ファイルは黙って skip する。path は project-relative(posix 区切り)で報告する。
27
+ */
28
+ export class FileSystemInjectionScanAdapter implements InjectionScanPolicyPort {
29
+ constructor(private readonly projectRoot: string) {}
30
+
31
+ async collect(): Promise<readonly InjectionScanTarget[]> {
32
+ const targets: InjectionScanTarget[] = [];
33
+
34
+ // skills/*/SKILL.md
35
+ const skillsRoot = join(this.projectRoot, SKILLS_DIR);
36
+ let skillDirs: string[] = [];
37
+ try {
38
+ const entries = await readdir(skillsRoot, { withFileTypes: true });
39
+ skillDirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
40
+ } catch {
41
+ skillDirs = [];
42
+ }
43
+ for (const dir of skillDirs) {
44
+ const relPath = `${SKILLS_DIR}/${dir}/${SKILL_FILE}`;
45
+ const target = await this.readTarget(join(skillsRoot, dir, SKILL_FILE), relPath);
46
+ if (target) targets.push(target);
47
+ }
48
+
49
+ // docs/templates/agent-context/*.md
50
+ const agentContextRoot = join(this.projectRoot, AGENT_CONTEXT_REL);
51
+ let agentContextFiles: string[] = [];
52
+ try {
53
+ const entries = await readdir(agentContextRoot, { withFileTypes: true });
54
+ agentContextFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name);
55
+ } catch {
56
+ agentContextFiles = [];
57
+ }
58
+ for (const name of agentContextFiles) {
59
+ const relPath = `${AGENT_CONTEXT_REL.replace(/\\/g, "/")}/${name}`;
60
+ const target = await this.readTarget(join(agentContextRoot, name), relPath);
61
+ if (target) targets.push(target);
62
+ }
63
+
64
+ // 固定パス
65
+ for (const rel of FIXED_FILES) {
66
+ const posixRel = rel.replace(/\\/g, "/");
67
+ const target = await this.readTarget(join(this.projectRoot, rel), posixRel);
68
+ if (target) targets.push(target);
69
+ }
70
+
71
+ return Object.freeze(targets);
72
+ }
73
+
74
+ private async readTarget(absPath: string, relPath: string): Promise<InjectionScanTarget | null> {
75
+ try {
76
+ const content = await readFile(absPath, "utf-8");
77
+ return { path: relPath, content };
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
82
+ }
package/skills/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Skills ディレクトリ
2
2
 
3
- このディレクトリには、AIエージェントの共有スキル定義が含まれています。現在の配布対象は 30 skills です。公開一覧は `docs/guide/skills-overview.md`、setup lifecycle の管理対象は `docs/guide/setup-artifacts.md` を正とします。<!-- @work-item-id WI-154 -->
3
+ このディレクトリには、AIエージェントの共有スキル定義が含まれています。現在の配布対象は 29 skills です。公開一覧は `docs/guide/skills-overview.md`、setup lifecycle の管理対象は `docs/guide/setup-artifacts.md` を正とします。<!-- @work-item-id WI-154 -->
4
4
 
5
5
  ## ディレクトリ構成と同期
6
6
 
@@ -12,7 +12,7 @@ languages: [typescript]
12
12
 
13
13
  ## storyReflection ゲート通過の標準手段
14
14
 
15
- `phaseDependencies.storyReflection`(ADR-013)は、`docs/inception/{unit}/{storyId}/` 配下の US/issue 設計が `docs/product/construction/{unit}/` の累積設計文書に反映されていない場合、`src/{unit}/*` および `scripts/harness/{unit}/*` への Write/Edit(Bash 迂回経由の書き込みも含む)を pre-tool-use hook でブロックする。
15
+ `phaseDependencies.storyReflection`(ADR-013)は、`docs/inception/{unit}/{storyId}/` 配下の US/issue 設計が `docs/product/construction/{unit}/` の累積設計文書に反映されていない場合、`src/{unit}/*`(phasegate 自リポジトリ(dogfood)では `scripts/harness/{unit}/*`)への Write/Edit(Bash 迂回経由の書き込みも含む)を pre-tool-use hook でブロックする。
16
16
 
17
17
  **cascade-updater はこの storyReflection ゲートを通過する標準手段である。**
18
18
 
@@ -21,7 +21,7 @@ languages: [typescript]
21
21
  - `minimal` プリセットでは storyReflection が無効化されるためゲート連動しないが、cascade-updater による設計整合性の維持は推奨される
22
22
  - Quick Mode (`relaxedGates: ["phase-gate"]`) 時は storyReflection も緩和されるため、cascade-updater 実行の必須性は緩まる(ただし品質維持のため実行は推奨)
23
23
 
24
- 詳細は ADR-013 および `docs/guide/configuration.md` の storyReflection セクションを参照。
24
+ 詳細は ADR-013 および `docs/guide/configuration.md` の storyReflection セクションを参照(consumer プロジェクトでは `node_modules/phasegate/docs/ADR/...` / `node_modules/phasegate/docs/guide/...`、phasegate 自リポジトリでは `docs/...` を参照する)。
25
25
 
26
26
  ## 前提条件チェック
27
27
 
@@ -120,7 +120,7 @@ languages: [typescript]
120
120
  ## Phase 3: レビュー(Opus review)
121
121
 
122
122
  ### 実行主体
123
- メインセッション(Opus 4.6)が実行する。Sonnetへの再委任は行わない。
123
+ メインセッション(model-routing.md の Architect ロール)が実行する。Sonnetへの再委任は行わない。
124
124
 
125
125
  ### レビュー手順
126
126
  1. Sonnetが出力したファイルを読み込む
@@ -111,7 +111,7 @@ Unit間依存グラフを深さ優先探索でサイクル検出する。
111
111
 
112
112
  | Unit | ファイル数 | レイヤー分布 |
113
113
  |------|----------|-----------|
114
- | harness-error | 12 | domain:4, app:4, infra:2, pres:2 |
114
+ | unit-a | 12 | domain:4, app:4, infra:2, pres:2 |
115
115
  | ...
116
116
 
117
117
  ---
@@ -119,11 +119,11 @@ Unit間依存グラフを深さ優先探索でサイクル検出する。
119
119
  ## Unit 間依存グラフ
120
120
 
121
121
  ```
122
- harness-api
123
- └── depends on: biome-ast-engine, validator-system, ...
122
+ unit-a
123
+ └── depends on: unit-b, unit-c, ...
124
124
 
125
- validator-system
126
- └── depends on: harness-error, config-foundation
125
+ unit-c
126
+ └── depends on: unit-d, unit-e
127
127
  ```
128
128
 
129
129
  ---
@@ -161,4 +161,4 @@ validator-system
161
161
  |--------------|------|
162
162
  | `npx phasegate lint` | L1 archgateルールの全体スキャン |
163
163
  | `consistency-checker` | マップ生成後の設計文書整合性確認 |
164
- | `doc-freshness-checker` | マップと設計文書の鮮度を合わせて確認 |
164
+ | `doc-health-checker` | マップと設計文書の鮮度・ポインタ有効性を合わせて確認 |
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: codex-delegator
3
+ kind: advisory
3
4
  description: |
4
5
  codex CLI(gpt-5.4)にタスクをLocal実行で並列委任し、Claude Codeがマネージャー/レビュワーとして品質管理する。
5
6
  対象: 設計計画、設計文書、テスト設計、コード実装など全タスクタイプ。
@@ -22,15 +23,15 @@ codex CLI(gpt-5.4)にタスクをLocal実行で並列委任し、2段階レ
22
23
 
23
24
  ## 前提条件
24
25
 
25
- - codex CLI v0.111.0+(`codex exec "<prompt>" --full-auto`)
26
+ - **codex CLI が必須** — codex CLI v0.111.0+(`codex exec "<prompt>" --full-auto`)がインストールされていること。未インストールの環境では本スキルはスキップし、Claude Code が直接実装に切り替える
26
27
  - モデル: `gpt-5.4`(ChatGPTアカウントでは派生モデル不可)
27
- - プロジェクト規約: `docs/principles/testing-rules.md`, `docs/principles/architecture-philosophy.md`
28
+ - プロジェクト規約: `docs/principles/testing-rules.md`, `docs/principles/architecture-philosophy.md`(consumer プロジェクトでは `node_modules/phasegate/docs/principles/...`、phasegate 自リポジトリでは `docs/principles/...` を参照する)
28
29
  - 設計文書が揃っていることが前提(ドメインモデル、論理設計、テストケース設計等)
29
30
 
30
31
  ## 核心原則
31
32
 
32
33
  1. **codexに判断させない**: 何を・どのファイルに・どのパターンで作るかはClaude Codeが決定する。codexは具体的指示の実行者
33
- 2. **設計文書との突合がレビューの主軸**: `pnpm test` グリーンだけでは不十分。設計文書のケースID・期待値との一致を検証する
34
+ 2. **設計文書との突合がレビューの主軸**: プロジェクトのテストコマンド(`npm test` 等、pnpm/yarn は例)のグリーンだけでは不十分。設計文書のケースID・期待値との一致を検証する
34
35
  3. **早期フォールバック**: codexが2回失敗したらClaude Codeが直接実装に切り替える
35
36
  4. **Local実行のみ**: codex cloud / @codex review は使用しない。全タスクを `codex exec --full-auto` で実行する
36
37
  5. **レビューはdiffベース**: 生成物の全文Readではなく、`git diff` の差分をレビュー入力とする。コンテキストウィンドウを節約し、変更点に集中する
@@ -6,11 +6,11 @@
6
6
 
7
7
  ## 共通コンテキスト層
8
8
 
9
- 全タスクタイプで以下をプロンプト冒頭に含める:
9
+ 全タスクタイプで以下をプロンプト冒頭に含める。アーキテクチャ行は固定値ではなく、対象プロジェクトの `phasegate.config.json` の `architecture.preset` と `layers`(層と依存方向)から導出すること:
10
10
 
11
11
  ```
12
- プロジェクト: Phasegate
13
- アーキテクチャ: ヘキサゴナル + DDD(domain → port → usecase → controller
12
+ プロジェクト: {プロジェクト名}
13
+ アーキテクチャ: {architecture.preset から導出(例: preset "hexagonal" なら「ヘキサゴナル + DDD(domain → port → usecase → controller)」、preset "clean" なら「クリーンアーキテクチャ(domain → application → infrastructure/presentation)」)}
14
14
  ```
15
15
 
16
16
  ---
@@ -20,7 +20,7 @@ grep・diff・テスト実行で自動検証する。判断不要。
20
20
  | ID | 次元 | 検証方法 | 重大度 |
21
21
  |----|------|---------|--------|
22
22
  | C1 | スコープ遵守 | `git diff --name-only` と指示ファイルリストの差分比較 | BLOCK |
23
- | C2 | 既存破壊なし | `pnpm test` 実行(既存テスト全パス確認) | BLOCK |
23
+ | C2 | 既存破壊なし | プロジェクトのテストコマンド(`npm test` 等、pnpm/yarn は例)実行(既存テスト全パス確認) | BLOCK |
24
24
  | C3 | 命名一貫性 | grep: 日本語テスト名、`actual`変数、target/context/describe/it構造 | BLOCK |
25
25
 
26
26
  ### Tier 1: タスクタイプ別追加
@@ -123,7 +123,7 @@ AIDLCプロセスの全レイヤー設計文書を横断的に検証し、矛盾
123
123
  ## Phase 3: レビュー(Opus review)
124
124
 
125
125
  ### 実行主体
126
- メインセッション(Opus 4.6)が実行する。Sonnetへの再委任は行わない。
126
+ メインセッション(model-routing.md の Architect ロール)が実行する。Sonnetへの再委任は行わない。
127
127
 
128
128
  ### レビュー手順
129
129
  1. Sonnetが出力したファイルを読み込む
@@ -50,7 +50,7 @@
50
50
 
51
51
  ```
52
52
  # ストーリーID抽出(マークダウンテーブルから)
53
- # {storyIdPattern} はプロジェクトのストーリーID正規表現(例: US-[0-9]+)
53
+ # {storyIdPattern} はプロジェクトのストーリーID正規表現(phasegate 既定は H[F0-9][0-9]*-[0-9]{2})
54
54
  grep -oE '{storyIdPattern}' {userStoriesPath}
55
55
 
56
56
  # Unit内のストーリー参照抽出