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.
- package/CHANGELOG.md +20 -0
- package/README.ja.md +52 -15
- package/README.md +39 -11
- package/docs/ADR/030-injection-threat-model-and-trust-root.md +145 -0
- package/docs/guide/hooks-integration.md +50 -1
- package/docs/guide/installation.md +1 -1
- package/docs/guide/quick-vs-full-mode.md +1 -1
- package/docs/guide/skills-overview.md +17 -17
- package/package.json +1 -1
- package/scripts/harness/agent-integration/presentation/phasegate-status-context.ts +131 -63
- package/scripts/harness/agent-integration/presentation/session-start-hook.ts +31 -4
- package/scripts/harness/agent-integration/presentation/spotlight.ts +65 -0
- package/scripts/harness/biome-ast-engine/infrastructure/parsers/comment-density-parser.ts +51 -10
- package/scripts/harness/ci-governance/application/dto/pin-integrity-input.ts +8 -0
- package/scripts/harness/ci-governance/application/dto/pin-integrity-output.ts +9 -0
- package/scripts/harness/ci-governance/application/dto/verify-integrity-input.ts +7 -0
- package/scripts/harness/ci-governance/application/dto/verify-integrity-output.ts +10 -0
- package/scripts/harness/ci-governance/application/usecases/pin-integrity-usecase.ts +60 -0
- package/scripts/harness/ci-governance/application/usecases/verify-integrity-usecase.ts +46 -0
- package/scripts/harness/ci-governance/composition-root.ts +68 -65
- package/scripts/harness/ci-governance/domain/ports/integrity-manifest-repository-port.ts +14 -0
- package/scripts/harness/ci-governance/domain/ports/sha256-hasher-port.ts +10 -0
- package/scripts/harness/ci-governance/domain/services/integrity-checker.ts +42 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-drift.ts +16 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-manifest.ts +49 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-target.ts +40 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/adr-foundation-existence-adapter.ts +26 -2
- package/scripts/harness/ci-governance/infrastructure/adapters/file-system-sha256-hasher-adapter.ts +17 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/harness-api-command-existence-adapter.ts +8 -1
- package/scripts/harness/ci-governance/infrastructure/adapters/integrity-manifest-json-repository-adapter.ts +83 -0
- package/scripts/harness/ci-governance/presentation/handlers/integrity-handler.ts +76 -0
- package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +53 -28
- package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +33 -8
- package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +90 -0
- package/scripts/harness/installation/application/bundled-skill-selection.ts +2 -5
- package/scripts/harness/main.ts +257 -105
- package/scripts/harness/phase-dependency-model/domain/ports/story-reflection-file-system-port.ts +2 -0
- package/scripts/harness/phase-dependency-model/domain/services/story-reflection-checker.ts +8 -0
- package/scripts/harness/phase-dependency-model/infrastructure/filesystem/file-system-story-reflection-adapter.ts +137 -2
- package/scripts/harness/quick-mode/domain/services/quick-mode-judgment-engine.ts +44 -40
- package/scripts/harness/setup/skill-deployer.ts +8 -10
- package/scripts/harness/skill-quality/domain/services/skill-structure-validator.ts +13 -2
- package/scripts/harness/skill-quality/domain/types/skill-kind.ts +6 -0
- package/scripts/harness/skill-quality/domain/value-objects/skill-structure.ts +24 -8
- package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +82 -49
- package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +87 -58
- package/scripts/harness/validator-system/composition-root.ts +141 -99
- package/scripts/harness/validator-system/domain/ports/coverage-attestation-gating-policy-port.ts +14 -0
- package/scripts/harness/validator-system/domain/ports/injection-scan-policy-port.ts +14 -0
- package/scripts/harness/validator-system/domain/services/coverage-attestation-gating-service.ts +56 -0
- package/scripts/harness/validator-system/domain/services/injection-pattern-scan-service.ts +118 -0
- package/scripts/harness/validator-system/domain/value-objects/coverage-gating-report.ts +67 -0
- package/scripts/harness/validator-system/domain/value-objects/injection-scan-report.ts +55 -0
- package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +35 -31
- package/scripts/harness/validator-system/infrastructure/adapters/adr-foundation-reference-adapter.ts +13 -7
- package/scripts/harness/validator-system/infrastructure/adapters/file-system-coverage-attestation-gating-adapter.ts +87 -0
- package/scripts/harness/validator-system/infrastructure/adapters/file-system-injection-scan-adapter.ts +82 -0
- package/skills/README.md +1 -1
- package/skills/cascade-updater/SKILL.md +3 -3
- package/skills/codebase-mapper/SKILL.md +6 -6
- package/skills/codex-delegator/SKILL.md +4 -3
- package/skills/codex-delegator/references/prompt-patterns.md +3 -3
- package/skills/codex-delegator/references/review-dimensions.md +1 -1
- package/skills/consistency-checker/SKILL.md +1 -1
- 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
- package/skills/doc-health-checker/SKILL.md +148 -0
- package/skills/domain-designer/SKILL.md +4 -2
- package/skills/engineering-perspective/SKILL.md +1 -0
- package/skills/environment-designer/SKILL.md +8 -6
- package/skills/implementation-readiness-checker/SKILL.md +2 -1
- package/skills/it-test-designer/SKILL.md +10 -8
- package/skills/it-test-logic-designer/SKILL.md +11 -9
- package/skills/it-test-logic-designer/references/repository-test-patterns.md +8 -1
- package/skills/logical-designer/SKILL.md +5 -3
- package/skills/mock-designer/SKILL.md +10 -6
- package/skills/phasegate-config-doctor/SKILL.md +3 -2
- package/skills/phasegate-toolkit-guide/SKILL.md +1 -0
- package/skills/quick-implementor/SKILL.md +1 -1
- package/skills/release-publisher/SKILL.md +101 -0
- package/skills/scenario-test-designer/SKILL.md +27 -14
- package/skills/scenario-test-logic-designer/SKILL.md +10 -8
- package/skills/scenario-test-logic-designer/references/msw-patterns.md +3 -1
- package/skills/scenario-test-logic-designer/references/playwright-patterns.md +3 -1
- package/skills/skill-creator/SKILL.md +75 -332
- package/skills/story-implementor/SKILL.md +54 -0
- package/skills/story-mapper/SKILL.md +8 -4
- package/skills/story-writer/SKILL.md +14 -5
- package/skills/test-coverage-checker/SKILL.md +4 -6
- package/skills/uiux-designer/SKILL.md +4 -2
- package/skills/uiux-designer/references/uiux-design-template.md +4 -4
- package/skills/unit-designer/SKILL.md +11 -7
- package/skills/unit-test-designer/SKILL.md +25 -11
- package/skills/unit-test-logic-designer/SKILL.md +10 -8
- package/skills/unit-test-logic-designer/references/test-patterns.md +7 -1
- package/skills/doc-freshness-checker/SKILL.md +0 -140
- package/skills/implementation-planner/SKILL.md +0 -167
- package/skills/implementation-planner/references/document-structure.md +0 -116
- package/skills/implementation-planner/references/plan-template.md +0 -177
- package/skills/implementation-planner/references/workflow.md +0 -164
- 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 =
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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:
|
|
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
|
|
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():
|
|
100
|
+
getLayer(): "L0" | "L1" | "L2" | "L3" | "L4" {
|
|
97
101
|
return this.layer;
|
|
98
102
|
}
|
|
99
103
|
|
package/scripts/harness/validator-system/infrastructure/adapters/adr-foundation-reference-adapter.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
*
|
|
5
5
|
* AdrFoundationReferenceAdapter — AdrReferencePort実装
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
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: () => {
|
|
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(
|
|
42
|
-
const { AdrId } = await import(
|
|
43
|
-
const mod = createAdrFoundationModule(
|
|
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 (
|
|
52
|
+
if ("findById" in repository && typeof repository.findById === "function") {
|
|
47
53
|
return repository.findById(AdrId.create(adrRef));
|
|
48
54
|
}
|
|
49
55
|
|
|
50
|
-
if (
|
|
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エージェントの共有スキル定義が含まれています。現在の配布対象は
|
|
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}
|
|
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
|
-
メインセッション(
|
|
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
|
-
|
|
|
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
|
-
|
|
123
|
-
└── depends on:
|
|
122
|
+
unit-a
|
|
123
|
+
└── depends on: unit-b, unit-c, ...
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
└── depends on:
|
|
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-
|
|
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. **設計文書との突合がレビューの主軸**:
|
|
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
|
-
プロジェクト:
|
|
13
|
-
アーキテクチャ:
|
|
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 | 既存破壊なし |
|
|
23
|
+
| C2 | 既存破壊なし | プロジェクトのテストコマンド(`npm test` 等、pnpm/yarn は例)実行(既存テスト全パス確認) | BLOCK |
|
|
24
24
|
| C3 | 命名一貫性 | grep: 日本語テスト名、`actual`変数、target/context/describe/it構造 | BLOCK |
|
|
25
25
|
|
|
26
26
|
### Tier 1: タスクタイプ別追加
|