phasegate 0.229.0 → 0.264.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 +73 -1
- package/README.ja.md +31 -1
- package/README.md +30 -0
- package/docs/ADR/031-world-model-ownership-and-corpus-lifecycle.md +155 -0
- package/docs/ADR/032-world-node-identity.md +198 -0
- package/docs/ADR/033-world-snapshot-canonicalization.md +246 -0
- package/docs/ADR/034-world-constraint-semantics.md +218 -0
- package/docs/ADR/035-world-adoption-baseline-and-waiver.md +341 -0
- package/docs/ADR/036-world-model-and-doc-freshness.md +169 -0
- package/docs/ADR/037-world-cli-and-output-contract.md +398 -0
- package/docs/contracts/attestation-v2.schema.json +110 -0
- package/docs/contracts/requirement-test-matrix.schema.json +15 -0
- package/docs/contracts/world-baseline.schema.json +35 -0
- package/docs/contracts/world-constraints.schema.json +56 -0
- package/docs/contracts/world-debts.schema.json +32 -0
- package/docs/contracts/world-obligation-report.schema.json +259 -0
- package/docs/contracts/world-waivers.schema.json +32 -0
- package/docs/guide/cli-reference.md +45 -0
- package/docs/guide/configuration.md +56 -0
- package/docs/templates/ci/aidlc-gate.yml +42 -2
- package/package.json +1 -1
- package/scripts/harness/agent-integration/application/dto/open-world-obligations-context-dto.ts +30 -0
- package/scripts/harness/agent-integration/application/ports/world-obligations-query-port.ts +30 -0
- package/scripts/harness/agent-integration/application/usecases/get-open-world-obligations-context-usecase.ts +66 -0
- package/scripts/harness/agent-integration/infrastructure/adapters/world-model-open-obligations-query-adapter.ts +58 -0
- package/scripts/harness/agent-integration/presentation/session-start-hook.ts +37 -1
- package/scripts/harness/agent-integration/presentation/world-obligations-session-context.ts +60 -0
- package/scripts/harness/attestation/application/dto/attestation-document.ts +17 -4
- package/scripts/harness/attestation/application/mappers/attestation-record-mapper.ts +55 -4
- package/scripts/harness/attestation/application/ports/sha256-capability.ts +25 -0
- package/scripts/harness/attestation/application/ports/world-snapshot-root-provider.ts +10 -0
- package/scripts/harness/attestation/application/usecases/produce-attestation-usecase.ts +33 -7
- package/scripts/harness/attestation/composition-root.ts +19 -4
- package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
- package/scripts/harness/attestation/index.ts +13 -2
- package/scripts/harness/attestation/infrastructure/adapters/node-crypto-content-hasher-adapter.ts +6 -6
- package/scripts/harness/attestation/infrastructure/adapters/node-crypto-sha256-capability.ts +19 -0
- package/scripts/harness/attestation/presentation/handlers/attest-handler.ts +5 -2
- package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +35 -8
- package/scripts/harness/config-foundation/application/mappers/world-model-config-mapper.ts +15 -0
- package/scripts/harness/config-foundation/domain/harness-config.ts +67 -87
- package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +77 -88
- package/scripts/harness/config-foundation/domain/value-objects/world-config.ts +198 -0
- package/scripts/harness/config-foundation/index.ts +14 -15
- package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +24 -0
- package/scripts/harness/config-foundation/infrastructure/presets/standard.json +24 -0
- package/scripts/harness/config-foundation/infrastructure/presets/strict.json +24 -0
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +83 -0
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +83 -0
- package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +18 -4
- package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +4 -1
- package/scripts/harness/integrations/pre-commit.ts +169 -27
- package/scripts/harness/main.ts +276 -126
- package/scripts/harness/nyquist-validation/application/dto/generate-matrix-output.ts +11 -0
- package/scripts/harness/nyquist-validation/application/usecases/check-ac-coverage-gate-usecase.ts +6 -0
- package/scripts/harness/nyquist-validation/application/usecases/generate-requirement-test-matrix-usecase.ts +8 -4
- package/scripts/harness/nyquist-validation/domain/entities/story-mapping.ts +29 -2
- package/scripts/harness/nyquist-validation/domain/services/ac-coverage-gate-policy.ts +28 -0
- package/scripts/harness/nyquist-validation/infrastructure/adapters/markdown-requirement-source-adapter.ts +71 -4
- package/scripts/harness/nyquist-validation/infrastructure/schema/matrix-schema-loader.ts +4 -0
- package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
- package/scripts/harness/traceability-model/application/dto/traceability-world-read-dto.ts +67 -0
- package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
- package/scripts/harness/traceability-model/application/facades/traceability-world-read-facade.ts +372 -0
- package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
- package/scripts/harness/traceability-model/application/ports/traceability-world-read-source-port.ts +61 -0
- package/scripts/harness/traceability-model/composition-root.ts +26 -5
- package/scripts/harness/traceability-model/index.ts +26 -6
- package/scripts/harness/traceability-model/infrastructure/adapters/file-system-traceability-world-read-adapter.ts +223 -0
- package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
- package/scripts/harness/traceability-model/infrastructure/parsers/story-catalog-parser.ts +86 -8
- package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +31 -0
- package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +34 -0
- package/scripts/harness/validator-system/composition-root.ts +21 -6
- package/scripts/harness/validator-system/domain/ports/world-constraint-admission-policy-port.ts +28 -0
- package/scripts/harness/validator-system/domain/ports/world-constraint-rederivation-policy-port.ts +11 -0
- package/scripts/harness/validator-system/domain/services/design-change-declaration-policy.ts +75 -0
- package/scripts/harness/validator-system/domain/services/world-constraint-admission-service.ts +78 -0
- package/scripts/harness/validator-system/domain/services/world-constraint-rederivation-service.ts +76 -0
- package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +4 -0
- package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +38 -16
- package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-admission-adapter.ts +56 -0
- package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-rederivation-adapter.ts +56 -0
- package/scripts/harness/world-model/application/dto/pinned-design-endpoint-dto.ts +19 -0
- package/scripts/harness/world-model/application/dto/world-inspection-dto.ts +43 -0
- package/scripts/harness/world-model/application/dto/world-obligation-report-dto.ts +54 -0
- package/scripts/harness/world-model/application/dto/world-resolved-config-input.ts +127 -0
- package/scripts/harness/world-model/application/dto/world-snapshot-root-dto.ts +8 -0
- package/scripts/harness/world-model/application/facades/pinned-design-endpoint-facade.ts +63 -0
- package/scripts/harness/world-model/application/facades/world-snapshot-root-facade.ts +19 -0
- package/scripts/harness/world-model/application/ports/obligation-report-writer-port.ts +7 -0
- package/scripts/harness/world-model/application/ports/world-control-declaration-repository-port.ts +57 -0
- package/scripts/harness/world-model/application/ports/world-fact-source-port.ts +17 -0
- package/scripts/harness/world-model/application/usecases/build-snapshot-use-case.ts +111 -0
- package/scripts/harness/world-model/application/usecases/derive-obligations-use-case.ts +155 -0
- package/scripts/harness/world-model/application/usecases/derive-world-obligations-use-case.ts +146 -0
- package/scripts/harness/world-model/application/usecases/inspect-world-use-case.ts +74 -0
- package/scripts/harness/world-model/application/usecases/pin-constraint-endpoint-use-case.ts +139 -0
- package/scripts/harness/world-model/composition-root.ts +247 -0
- package/scripts/harness/world-model/domain/entities/constraint-record.ts +148 -0
- package/scripts/harness/world-model/domain/entities/control-declarations.ts +274 -0
- package/scripts/harness/world-model/domain/entities/edge.ts +41 -0
- package/scripts/harness/world-model/domain/entities/extraction-diagnostic.ts +60 -0
- package/scripts/harness/world-model/domain/entities/snapshot.ts +75 -0
- package/scripts/harness/world-model/domain/entities/world-node.ts +210 -0
- package/scripts/harness/world-model/domain/ports/world-hashing-port.ts +8 -0
- package/scripts/harness/world-model/domain/services/canonical-json-serializer.ts +113 -0
- package/scripts/harness/world-model/domain/services/constraint-evaluator.ts +486 -0
- package/scripts/harness/world-model/domain/services/obligation-derivation-service.ts +199 -0
- package/scripts/harness/world-model/domain/services/policy-inputs-digest-deriver.ts +66 -0
- package/scripts/harness/world-model/domain/services/snapshot-root-deriver.ts +218 -0
- package/scripts/harness/world-model/domain/services/text-content-normalizer.ts +30 -0
- package/scripts/harness/world-model/domain/services/violation-fingerprint-deriver.ts +183 -0
- package/scripts/harness/world-model/domain/value-objects/artifact-kind.ts +58 -0
- package/scripts/harness/world-model/domain/value-objects/change-provenance.ts +137 -0
- package/scripts/harness/world-model/domain/value-objects/corpus-role.ts +57 -0
- package/scripts/harness/world-model/domain/value-objects/declared-key.ts +35 -0
- package/scripts/harness/world-model/domain/value-objects/evaluation-id.ts +41 -0
- package/scripts/harness/world-model/domain/value-objects/explicit-constraint-relation.ts +53 -0
- package/scripts/harness/world-model/domain/value-objects/explicit-node-alias.ts +30 -0
- package/scripts/harness/world-model/domain/value-objects/node-pin.ts +34 -0
- package/scripts/harness/world-model/domain/value-objects/path-key.ts +103 -0
- package/scripts/harness/world-model/domain/value-objects/sha256-digest.ts +39 -0
- package/scripts/harness/world-model/domain/value-objects/violation-fingerprint.ts +36 -0
- package/scripts/harness/world-model/domain/value-objects/wcr-rule-id.ts +59 -0
- package/scripts/harness/world-model/domain/value-objects/world-node-id.ts +222 -0
- package/scripts/harness/world-model/index.ts +33 -0
- package/scripts/harness/world-model/infrastructure/adapters/adr-fact-extractor.ts +27 -0
- package/scripts/harness/world-model/infrastructure/adapters/assembled-world-fact-source.ts +17 -0
- package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +323 -0
- package/scripts/harness/world-model/infrastructure/adapters/attestation-sha256-world-hashing-adapter.ts +15 -0
- package/scripts/harness/world-model/infrastructure/adapters/composite-design-fact-source.ts +23 -0
- package/scripts/harness/world-model/infrastructure/adapters/design-corpus-fact-extractor.ts +285 -0
- package/scripts/harness/world-model/infrastructure/adapters/design-fact-extraction.ts +63 -0
- package/scripts/harness/world-model/infrastructure/adapters/file-system-obligation-report-writer-adapter.ts +37 -0
- package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +332 -0
- package/scripts/harness/world-model/infrastructure/adapters/integrity-manifest-fact-extractor.ts +101 -0
- package/scripts/harness/world-model/infrastructure/adapters/json-fact-extractor-support.ts +151 -0
- package/scripts/harness/world-model/infrastructure/adapters/markdown-design-fact-extractor.ts +493 -0
- package/scripts/harness/world-model/infrastructure/adapters/matrix-fact-extractor.ts +283 -0
- package/scripts/harness/world-model/infrastructure/adapters/product-fact-extractor.ts +29 -0
- package/scripts/harness/world-model/infrastructure/adapters/proposal-fact-extractor.ts +29 -0
- package/scripts/harness/world-model/infrastructure/adapters/runtime-fact-extraction.ts +19 -0
- package/scripts/harness/world-model/infrastructure/adapters/source-metadata-fact-extractor.ts +22 -0
- package/scripts/harness/world-model/infrastructure/adapters/test-reference-source-fact-extractor.ts +22 -0
- package/scripts/harness/world-model/infrastructure/adapters/traceability-design-fact-adapter.ts +112 -0
- package/scripts/harness/world-model/infrastructure/adapters/traceability-world-read-facade-merger.ts +38 -0
- package/scripts/harness/world-model/infrastructure/adapters/type-script-source-fact-extractor.ts +236 -0
- package/scripts/harness/world-model/infrastructure/adapters/unit-fact-extractor.ts +71 -0
- package/scripts/harness/world-model/infrastructure/adapters/world-control-declaration-mapper.ts +383 -0
- package/scripts/harness/world-model/presentation/cli/world-command-support.ts +60 -0
- package/scripts/harness/world-model/presentation/cli/world-derive-command-handler.ts +109 -0
- package/scripts/harness/world-model/presentation/cli/world-inspect-command-handler.ts +194 -0
- package/scripts/harness/world-model/presentation/cli/world-pin-command-handler.ts +100 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// @unit nyquist-validation
|
|
3
3
|
// @work-item-id WI-125
|
|
4
4
|
// @work-item-id WI-131
|
|
5
|
+
// @work-item-id WI-292
|
|
5
6
|
|
|
6
7
|
// Intent coverage 系の型は domain 層(value-objects/intent-coverage)を正準とし、
|
|
7
8
|
// application 層はそれを参照・再エクスポートする(domain ← application の正しい依存方向)。
|
|
@@ -13,8 +14,14 @@ import type {
|
|
|
13
14
|
export interface RequirementSourceDto {
|
|
14
15
|
readonly storyId: string;
|
|
15
16
|
readonly acIds: readonly string[];
|
|
17
|
+
/** 省略された legacy Story は fail-closed の required として扱う。 */
|
|
18
|
+
readonly coverageStatus?: StoryCoverageStatus;
|
|
19
|
+
/** Git 管理された順方向遷移履歴。省略時は現在 status から導出する。 */
|
|
20
|
+
readonly coverageLifecycle?: readonly StoryCoverageStatus[];
|
|
16
21
|
}
|
|
17
22
|
|
|
23
|
+
export type StoryCoverageStatus = 'planned' | 'required';
|
|
24
|
+
|
|
18
25
|
/**
|
|
19
26
|
* HF2-05: @ac が story 外の AC を指した/複数 @story のため相対 AC が解決できなかった等の
|
|
20
27
|
* 「解決に失敗した @ac タグ」を advisory として記録する(error ではない)。
|
|
@@ -61,6 +68,10 @@ export interface MatrixAcMappingDto {
|
|
|
61
68
|
|
|
62
69
|
export interface MatrixStoryDto {
|
|
63
70
|
readonly storyId: string;
|
|
71
|
+
/** schema 1.0/1.1 の読み取りでは省略可。省略時は required。 */
|
|
72
|
+
readonly coverageStatus?: StoryCoverageStatus;
|
|
73
|
+
/** schema 1.0/1.1 の読み取りでは省略可。省略時は [required]。 */
|
|
74
|
+
readonly coverageLifecycle?: readonly StoryCoverageStatus[];
|
|
64
75
|
readonly storyMappings: readonly MatrixAcMappingDto[];
|
|
65
76
|
}
|
|
66
77
|
|
package/scripts/harness/nyquist-validation/application/usecases/check-ac-coverage-gate-usecase.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* H07-02: AcCoverageGatePolicy チェック
|
|
6
6
|
*/
|
|
7
|
+
// @work-item-id WI-292
|
|
7
8
|
import type { MatrixFilePort } from '../../domain/ports/matrix-file-port.js';
|
|
8
9
|
import type { AjvValidatorPort } from './validate-matrix-usecase.js';
|
|
9
10
|
import type { MatrixValidationService } from '../../domain/services/matrix-validation-service.js';
|
|
@@ -45,9 +46,14 @@ function buildMatrix(data: unknown): RequirementTestMatrix {
|
|
|
45
46
|
return AcMapping.create({ acId: String(acm.acId ?? ''), testReferences });
|
|
46
47
|
});
|
|
47
48
|
|
|
49
|
+
const coverageStatus = story.coverageStatus === 'planned' ? 'planned' : 'required';
|
|
48
50
|
return StoryMapping.create({
|
|
49
51
|
storyId: String(story.storyId ?? ''),
|
|
50
52
|
acMappings,
|
|
53
|
+
coverageStatus,
|
|
54
|
+
coverageLifecycle: Array.isArray(story.coverageLifecycle)
|
|
55
|
+
? story.coverageLifecycle.map((value) => String(value) as 'planned' | 'required')
|
|
56
|
+
: [coverageStatus],
|
|
51
57
|
});
|
|
52
58
|
});
|
|
53
59
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// @unit nyquist-validation
|
|
3
3
|
// @work-item-id WI-125
|
|
4
4
|
// @work-item-id WI-131
|
|
5
|
+
// @work-item-id WI-292
|
|
5
6
|
|
|
6
7
|
import type { RequirementIntentCoverageService } from '../../domain/services/requirement-intent-coverage-service.js';
|
|
7
8
|
import type {
|
|
@@ -175,6 +176,10 @@ export class GenerateRequirementTestMatrixUseCase {
|
|
|
175
176
|
}
|
|
176
177
|
return {
|
|
177
178
|
storyId: requirement.storyId,
|
|
179
|
+
coverageStatus: requirement.coverageStatus ?? 'required',
|
|
180
|
+
coverageLifecycle: Object.freeze([
|
|
181
|
+
...(requirement.coverageLifecycle ?? [requirement.coverageStatus ?? 'required']),
|
|
182
|
+
]),
|
|
178
183
|
storyMappings: Object.freeze(storyMappings),
|
|
179
184
|
};
|
|
180
185
|
});
|
|
@@ -185,10 +190,9 @@ export class GenerateRequirementTestMatrixUseCase {
|
|
|
185
190
|
};
|
|
186
191
|
|
|
187
192
|
const matrix: RequirementTestMatrixDto = {
|
|
188
|
-
//
|
|
189
|
-
// 1.1
|
|
190
|
-
|
|
191
|
-
version: '1.1',
|
|
193
|
+
// WI-292: Story coverage status/lifecycle を owner-derived field として追加する。
|
|
194
|
+
// schema 1.0/1.1 の読み取りは required へ正規化して後方互換を維持する。
|
|
195
|
+
version: '1.2',
|
|
192
196
|
generatedAt: this.now().toISOString(),
|
|
193
197
|
stories: Object.freeze(stories),
|
|
194
198
|
};
|
|
@@ -4,25 +4,46 @@
|
|
|
4
4
|
*
|
|
5
5
|
* ストーリー単位のAC→テスト参照マッピングエンティティ
|
|
6
6
|
*/
|
|
7
|
+
// @work-item-id WI-292
|
|
7
8
|
import type { AcMapping, RawAcMapping } from '../value-objects/ac-mapping.js';
|
|
8
9
|
|
|
10
|
+
export type StoryCoverageStatus = 'planned' | 'required';
|
|
11
|
+
|
|
9
12
|
export interface StoryMappingCreateProps {
|
|
10
13
|
readonly storyId: string;
|
|
11
14
|
readonly acMappings: readonly AcMapping[];
|
|
15
|
+
readonly coverageStatus?: StoryCoverageStatus;
|
|
16
|
+
readonly coverageLifecycle?: readonly StoryCoverageStatus[];
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
export class StoryMapping {
|
|
15
20
|
readonly storyId: string;
|
|
16
21
|
readonly acMappings: readonly AcMapping[];
|
|
22
|
+
readonly coverageStatus: StoryCoverageStatus;
|
|
23
|
+
readonly coverageLifecycle: readonly StoryCoverageStatus[];
|
|
17
24
|
|
|
18
|
-
private constructor(
|
|
25
|
+
private constructor(
|
|
26
|
+
storyId: string,
|
|
27
|
+
acMappings: readonly AcMapping[],
|
|
28
|
+
coverageStatus: StoryCoverageStatus,
|
|
29
|
+
coverageLifecycle: readonly StoryCoverageStatus[],
|
|
30
|
+
) {
|
|
19
31
|
this.storyId = storyId;
|
|
20
32
|
this.acMappings = acMappings;
|
|
33
|
+
this.coverageStatus = coverageStatus;
|
|
34
|
+
this.coverageLifecycle = coverageLifecycle;
|
|
21
35
|
Object.freeze(this);
|
|
22
36
|
}
|
|
23
37
|
|
|
24
38
|
static create(props: StoryMappingCreateProps): StoryMapping {
|
|
25
|
-
|
|
39
|
+
const coverageStatus = props.coverageStatus ?? 'required';
|
|
40
|
+
const coverageLifecycle = props.coverageLifecycle ?? [coverageStatus];
|
|
41
|
+
return new StoryMapping(
|
|
42
|
+
props.storyId,
|
|
43
|
+
Object.freeze([...props.acMappings]),
|
|
44
|
+
coverageStatus,
|
|
45
|
+
Object.freeze([...coverageLifecycle]),
|
|
46
|
+
);
|
|
26
47
|
}
|
|
27
48
|
|
|
28
49
|
findAcMapping(acId: string): AcMapping | null {
|
|
@@ -35,6 +56,10 @@ export class StoryMapping {
|
|
|
35
56
|
);
|
|
36
57
|
}
|
|
37
58
|
|
|
59
|
+
testReferenceCount(): number {
|
|
60
|
+
return this.acMappings.reduce((total, mapping) => total + mapping.testReferences.length, 0);
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
equals(other: StoryMapping): boolean {
|
|
39
64
|
return this.storyId === other.storyId;
|
|
40
65
|
}
|
|
@@ -43,4 +68,6 @@ export class StoryMapping {
|
|
|
43
68
|
export interface RawStoryMapping {
|
|
44
69
|
readonly storyId: string;
|
|
45
70
|
readonly acMappings: readonly RawAcMapping[];
|
|
71
|
+
readonly coverageStatus?: StoryCoverageStatus;
|
|
72
|
+
readonly coverageLifecycle?: readonly StoryCoverageStatus[];
|
|
46
73
|
}
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* AC網羅ゲート判定ポリシー
|
|
6
6
|
* validator-system の L3-004 が実行主体として呼び出す公開ポリシー
|
|
7
7
|
*/
|
|
8
|
+
// @work-item-id WI-292
|
|
8
9
|
import type { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
10
|
+
import type { StoryMapping, StoryCoverageStatus } from '../entities/story-mapping.js';
|
|
9
11
|
|
|
10
12
|
export interface NyquistHarnessError {
|
|
11
13
|
readonly code: string;
|
|
@@ -23,6 +25,24 @@ export class AcCoverageGatePolicy {
|
|
|
23
25
|
const errors: NyquistHarnessError[] = [];
|
|
24
26
|
|
|
25
27
|
for (const sm of matrix.getAllStoryMappings()) {
|
|
28
|
+
if (!this.hasValidCoverageLifecycle(sm)) {
|
|
29
|
+
errors.push({
|
|
30
|
+
code: 'L3-004',
|
|
31
|
+
severity: 'error',
|
|
32
|
+
message: `Invalid coverage lifecycle: ${sm.storyId} (${sm.coverageLifecycle.join(' -> ')}; status=${sm.coverageStatus})`,
|
|
33
|
+
});
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (sm.coverageStatus === 'planned') {
|
|
37
|
+
if (sm.testReferenceCount() > 0) {
|
|
38
|
+
errors.push({
|
|
39
|
+
code: 'L3-004',
|
|
40
|
+
severity: 'error',
|
|
41
|
+
message: `Planned Story has test references; transition coverage status to required: ${sm.storyId}`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
26
46
|
for (const acId of sm.uncoveredAcIds()) {
|
|
27
47
|
errors.push({
|
|
28
48
|
code: 'L3-004',
|
|
@@ -37,4 +57,12 @@ export class AcCoverageGatePolicy {
|
|
|
37
57
|
}
|
|
38
58
|
return { passed: false, errors: Object.freeze(errors) };
|
|
39
59
|
}
|
|
60
|
+
|
|
61
|
+
private hasValidCoverageLifecycle(story: StoryMapping): boolean {
|
|
62
|
+
const lifecycle: readonly StoryCoverageStatus[] = story.coverageLifecycle;
|
|
63
|
+
const validSequence =
|
|
64
|
+
(lifecycle.length === 1 && (lifecycle[0] === 'planned' || lifecycle[0] === 'required'))
|
|
65
|
+
|| (lifecycle.length === 2 && lifecycle[0] === 'planned' && lifecycle[1] === 'required');
|
|
66
|
+
return validSequence && lifecycle[lifecycle.length - 1] === story.coverageStatus;
|
|
67
|
+
}
|
|
40
68
|
}
|
|
@@ -1,38 +1,105 @@
|
|
|
1
1
|
// @layer infrastructure
|
|
2
2
|
// @unit nyquist-validation
|
|
3
3
|
// @work-item-id WI-125
|
|
4
|
+
// @work-item-id WI-292
|
|
4
5
|
|
|
5
6
|
import { readFile } from 'node:fs/promises';
|
|
6
7
|
import type { RequirementSourcePort } from '../../application/usecases/generate-requirement-test-matrix-usecase.js';
|
|
7
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
RequirementSourceDto,
|
|
10
|
+
StoryCoverageStatus,
|
|
11
|
+
} from '../../application/dto/generate-matrix-output.js';
|
|
8
12
|
|
|
9
13
|
// StoryId は HXX-XX 形式に加え Phase 2 拡張 Epic の HF\d+-XX 形式も許容する
|
|
10
14
|
// (traceability-model の StoryId 正規表現と整合)。旧 /H\d{2}-\d{2}/ は HF2-01 を取りこぼしていた。
|
|
11
15
|
const STORY_HEADING = /^###\s+(H(?:F\d+|\d{2})-\d{2}):/;
|
|
16
|
+
const SECTION_HEADING = /^#{1,3}\s+/;
|
|
12
17
|
const AC_ITEM = /^\s*-\s+\[[ xX]\]\s+(AC-[1-9][0-9]*):/;
|
|
18
|
+
const COVERAGE_STATUS = /^\*\*Coverage status\*\*:\s*(\S+)\s*$/;
|
|
19
|
+
const COVERAGE_LIFECYCLE = /^\*\*Coverage lifecycle\*\*:\s*(.+?)\s*$/;
|
|
20
|
+
|
|
21
|
+
interface PendingStory {
|
|
22
|
+
readonly storyId: string;
|
|
23
|
+
readonly acIds: string[];
|
|
24
|
+
coverageStatus?: string;
|
|
25
|
+
coverageLifecycle?: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isCoverageStatus = (value: string): value is StoryCoverageStatus =>
|
|
29
|
+
value === 'planned' || value === 'required';
|
|
30
|
+
|
|
31
|
+
const isValidLifecycle = (values: readonly StoryCoverageStatus[]): boolean =>
|
|
32
|
+
(values.length === 1 && (values[0] === 'planned' || values[0] === 'required'))
|
|
33
|
+
|| (values.length === 2 && values[0] === 'planned' && values[1] === 'required');
|
|
34
|
+
|
|
35
|
+
function completeStory(story: PendingStory): RequirementSourceDto {
|
|
36
|
+
const rawStatus = story.coverageStatus ?? 'required';
|
|
37
|
+
if (!isCoverageStatus(rawStatus)) {
|
|
38
|
+
throw new Error(`Invalid coverage lifecycle for ${story.storyId}: unknown status ${rawStatus}`);
|
|
39
|
+
}
|
|
40
|
+
const rawLifecycle = story.coverageLifecycle ?? [rawStatus];
|
|
41
|
+
if (!rawLifecycle.every(isCoverageStatus)) {
|
|
42
|
+
throw new Error(`Invalid coverage lifecycle for ${story.storyId}: unknown lifecycle value`);
|
|
43
|
+
}
|
|
44
|
+
const lifecycle: readonly StoryCoverageStatus[] = Object.freeze([...rawLifecycle]);
|
|
45
|
+
if (!isValidLifecycle(lifecycle) || lifecycle[lifecycle.length - 1] !== rawStatus) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Invalid coverage lifecycle for ${story.storyId}: ${lifecycle.join(' -> ')} does not end at ${rawStatus}`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
storyId: story.storyId,
|
|
52
|
+
acIds: Object.freeze([...new Set(story.acIds)]),
|
|
53
|
+
coverageStatus: rawStatus,
|
|
54
|
+
coverageLifecycle: lifecycle,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
13
57
|
|
|
14
58
|
export class MarkdownRequirementSourceAdapter implements RequirementSourcePort {
|
|
15
59
|
async readRequirements(sourcePath: string): Promise<readonly RequirementSourceDto[]> {
|
|
16
60
|
const content = await readFile(sourcePath, 'utf-8');
|
|
17
61
|
const results: RequirementSourceDto[] = [];
|
|
18
|
-
let current:
|
|
62
|
+
let current: PendingStory | null = null;
|
|
19
63
|
|
|
20
64
|
for (const line of content.split(/\r?\n/)) {
|
|
21
65
|
const storyMatch = line.match(STORY_HEADING);
|
|
22
66
|
if (storyMatch) {
|
|
23
67
|
if (current) {
|
|
24
|
-
results.push(
|
|
68
|
+
results.push(completeStory(current));
|
|
25
69
|
}
|
|
26
70
|
current = { storyId: storyMatch[1], acIds: [] };
|
|
27
71
|
continue;
|
|
28
72
|
}
|
|
73
|
+
if (current && SECTION_HEADING.test(line)) {
|
|
74
|
+
results.push(completeStory(current));
|
|
75
|
+
current = null;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const statusMatch = line.match(COVERAGE_STATUS);
|
|
79
|
+
if (current && statusMatch) {
|
|
80
|
+
if (current.coverageStatus !== undefined) {
|
|
81
|
+
throw new Error(`Invalid coverage lifecycle for ${current.storyId}: duplicate status`);
|
|
82
|
+
}
|
|
83
|
+
current.coverageStatus = statusMatch[1];
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const lifecycleMatch = line.match(COVERAGE_LIFECYCLE);
|
|
87
|
+
if (current && lifecycleMatch) {
|
|
88
|
+
if (current.coverageLifecycle !== undefined) {
|
|
89
|
+
throw new Error(`Invalid coverage lifecycle for ${current.storyId}: duplicate lifecycle`);
|
|
90
|
+
}
|
|
91
|
+
current.coverageLifecycle = Object.freeze(
|
|
92
|
+
lifecycleMatch[1].split(/\s*->\s*/).map((value) => value.trim()),
|
|
93
|
+
);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
29
96
|
const acMatch = line.match(AC_ITEM);
|
|
30
97
|
if (current && acMatch) {
|
|
31
98
|
current.acIds.push(acMatch[1]);
|
|
32
99
|
}
|
|
33
100
|
}
|
|
34
101
|
if (current) {
|
|
35
|
-
results.push(
|
|
102
|
+
results.push(completeStory(current));
|
|
36
103
|
}
|
|
37
104
|
return Object.freeze(results.filter((result) => result.acIds.length > 0));
|
|
38
105
|
}
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
* @layer infrastructure
|
|
3
3
|
* @unit nyquist-validation
|
|
4
4
|
* @work-item-id WI-222
|
|
5
|
+
* @work-item-id WI-292
|
|
5
6
|
*
|
|
6
7
|
* requirement-test-matrix.schema.json ローダー(シングルトンキャッシュ付き)
|
|
7
8
|
*
|
|
8
9
|
* HF2-05 (schema 1.1): testReferences に optional な `binding` enum("ac"|"file")を追加。
|
|
9
10
|
* 1.1 は追加フィールドが optional かつ additionalProperties:false を満たすため、
|
|
10
11
|
* `binding` を持たない 1.0 マトリクスも引き続き検証を通過する(後方互換)。
|
|
12
|
+
*
|
|
13
|
+
* WI-292 (schema 1.2): Story に optional な coverageStatus / coverageLifecycle を追加。
|
|
14
|
+
* 省略された 1.0/1.1 Story は application 層で required / [required] へ正規化する。
|
|
11
15
|
*/
|
|
12
16
|
import { readFile } from 'node:fs/promises';
|
|
13
17
|
import { resolve, join } from 'node:path';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer application
|
|
3
|
+
// @work-item-id WI-305
|
|
4
|
+
|
|
5
|
+
export type DesignFragmentCorpusRole = "product" | "inception";
|
|
6
|
+
export type DesignFragmentChangeKind = "added" | "modified" | "deleted";
|
|
7
|
+
|
|
8
|
+
export interface ChangedDesignFragmentDto {
|
|
9
|
+
readonly corpusRole: DesignFragmentCorpusRole;
|
|
10
|
+
readonly declaredKey: string;
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly changeKind: DesignFragmentChangeKind;
|
|
13
|
+
readonly workItemIds: readonly string[];
|
|
14
|
+
readonly reflectionTargets: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface DesignChangeReadDiagnosticDto {
|
|
18
|
+
readonly code: string;
|
|
19
|
+
readonly path: string | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type DesignChangeReadResultDto =
|
|
23
|
+
| {
|
|
24
|
+
readonly state: "available";
|
|
25
|
+
readonly fragments: readonly ChangedDesignFragmentDto[];
|
|
26
|
+
readonly diagnostics: readonly DesignChangeReadDiagnosticDto[];
|
|
27
|
+
}
|
|
28
|
+
| {
|
|
29
|
+
readonly state: "unavailable";
|
|
30
|
+
readonly diagnostics: readonly DesignChangeReadDiagnosticDto[];
|
|
31
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer application
|
|
3
|
+
// @work-item-id WI-288
|
|
4
|
+
|
|
5
|
+
export const TRACEABILITY_WORLD_READ_SCHEMA_VERSION = "phasegate-traceability-world-read/v1" as const;
|
|
6
|
+
|
|
7
|
+
export type TraceabilityTestType = "unit" | "it" | "scenario";
|
|
8
|
+
|
|
9
|
+
export interface TraceabilityUnitDto {
|
|
10
|
+
readonly unitId: string;
|
|
11
|
+
readonly definitionPath: string;
|
|
12
|
+
readonly constructionRoot: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TraceabilityStoryDto {
|
|
16
|
+
readonly storyId: string;
|
|
17
|
+
readonly legacyIds: readonly string[];
|
|
18
|
+
readonly sourcePath: string;
|
|
19
|
+
readonly line: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TraceabilityAcceptanceCriterionDto {
|
|
23
|
+
readonly storyId: string;
|
|
24
|
+
readonly acId: string;
|
|
25
|
+
readonly sourcePath: string;
|
|
26
|
+
readonly line: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface TraceabilityWorkItemDto {
|
|
30
|
+
readonly workItemId: string;
|
|
31
|
+
readonly legacyIds: readonly string[];
|
|
32
|
+
readonly type: string;
|
|
33
|
+
readonly severity: string | null;
|
|
34
|
+
readonly status: string | null;
|
|
35
|
+
readonly affects: readonly string[];
|
|
36
|
+
readonly descriptionPath: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface TraceabilityTestReferenceDto {
|
|
40
|
+
readonly storyId: string;
|
|
41
|
+
readonly acId: string;
|
|
42
|
+
readonly binding: "file";
|
|
43
|
+
readonly testType: TraceabilityTestType;
|
|
44
|
+
readonly filePath: string;
|
|
45
|
+
readonly testName: null;
|
|
46
|
+
readonly provenance: readonly {
|
|
47
|
+
readonly sourcePath: string;
|
|
48
|
+
readonly line: number;
|
|
49
|
+
}[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface TraceabilityReadDiagnosticDto {
|
|
53
|
+
readonly code: string;
|
|
54
|
+
readonly subjectId: string | null;
|
|
55
|
+
readonly sourcePaths: readonly string[];
|
|
56
|
+
readonly message: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface TraceabilityWorldReadDto {
|
|
60
|
+
readonly schemaVersion: typeof TRACEABILITY_WORLD_READ_SCHEMA_VERSION;
|
|
61
|
+
readonly units: readonly TraceabilityUnitDto[];
|
|
62
|
+
readonly stories: readonly TraceabilityStoryDto[];
|
|
63
|
+
readonly acceptanceCriteria: readonly TraceabilityAcceptanceCriterionDto[];
|
|
64
|
+
readonly workItems: readonly TraceabilityWorkItemDto[];
|
|
65
|
+
readonly testReferences: readonly TraceabilityTestReferenceDto[];
|
|
66
|
+
readonly diagnostics: readonly TraceabilityReadDiagnosticDto[];
|
|
67
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer application
|
|
3
|
+
// @work-item-id WI-305
|
|
4
|
+
|
|
5
|
+
import type { DesignChangeReadResultDto } from "../dto/changed-design-fragment-dto.js";
|
|
6
|
+
import type { StagedDesignChangeSourcePort } from "../ports/staged-design-change-source-port.js";
|
|
7
|
+
|
|
8
|
+
export class DesignChangeReadFacade {
|
|
9
|
+
constructor(private readonly source: StagedDesignChangeSourcePort) {}
|
|
10
|
+
|
|
11
|
+
observe(stagedFiles: readonly string[]): Promise<DesignChangeReadResultDto> {
|
|
12
|
+
return this.source.observe(stagedFiles);
|
|
13
|
+
}
|
|
14
|
+
}
|