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.
Files changed (154) hide show
  1. package/CHANGELOG.md +73 -1
  2. package/README.ja.md +31 -1
  3. package/README.md +30 -0
  4. package/docs/ADR/031-world-model-ownership-and-corpus-lifecycle.md +155 -0
  5. package/docs/ADR/032-world-node-identity.md +198 -0
  6. package/docs/ADR/033-world-snapshot-canonicalization.md +246 -0
  7. package/docs/ADR/034-world-constraint-semantics.md +218 -0
  8. package/docs/ADR/035-world-adoption-baseline-and-waiver.md +341 -0
  9. package/docs/ADR/036-world-model-and-doc-freshness.md +169 -0
  10. package/docs/ADR/037-world-cli-and-output-contract.md +398 -0
  11. package/docs/contracts/attestation-v2.schema.json +110 -0
  12. package/docs/contracts/requirement-test-matrix.schema.json +15 -0
  13. package/docs/contracts/world-baseline.schema.json +35 -0
  14. package/docs/contracts/world-constraints.schema.json +56 -0
  15. package/docs/contracts/world-debts.schema.json +32 -0
  16. package/docs/contracts/world-obligation-report.schema.json +259 -0
  17. package/docs/contracts/world-waivers.schema.json +32 -0
  18. package/docs/guide/cli-reference.md +45 -0
  19. package/docs/guide/configuration.md +56 -0
  20. package/docs/templates/ci/aidlc-gate.yml +42 -2
  21. package/package.json +1 -1
  22. package/scripts/harness/agent-integration/application/dto/open-world-obligations-context-dto.ts +30 -0
  23. package/scripts/harness/agent-integration/application/ports/world-obligations-query-port.ts +30 -0
  24. package/scripts/harness/agent-integration/application/usecases/get-open-world-obligations-context-usecase.ts +66 -0
  25. package/scripts/harness/agent-integration/infrastructure/adapters/world-model-open-obligations-query-adapter.ts +58 -0
  26. package/scripts/harness/agent-integration/presentation/session-start-hook.ts +37 -1
  27. package/scripts/harness/agent-integration/presentation/world-obligations-session-context.ts +60 -0
  28. package/scripts/harness/attestation/application/dto/attestation-document.ts +17 -4
  29. package/scripts/harness/attestation/application/mappers/attestation-record-mapper.ts +55 -4
  30. package/scripts/harness/attestation/application/ports/sha256-capability.ts +25 -0
  31. package/scripts/harness/attestation/application/ports/world-snapshot-root-provider.ts +10 -0
  32. package/scripts/harness/attestation/application/usecases/produce-attestation-usecase.ts +33 -7
  33. package/scripts/harness/attestation/composition-root.ts +19 -4
  34. package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
  35. package/scripts/harness/attestation/index.ts +13 -2
  36. package/scripts/harness/attestation/infrastructure/adapters/node-crypto-content-hasher-adapter.ts +6 -6
  37. package/scripts/harness/attestation/infrastructure/adapters/node-crypto-sha256-capability.ts +19 -0
  38. package/scripts/harness/attestation/presentation/handlers/attest-handler.ts +5 -2
  39. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +35 -8
  40. package/scripts/harness/config-foundation/application/mappers/world-model-config-mapper.ts +15 -0
  41. package/scripts/harness/config-foundation/domain/harness-config.ts +67 -87
  42. package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +77 -88
  43. package/scripts/harness/config-foundation/domain/value-objects/world-config.ts +198 -0
  44. package/scripts/harness/config-foundation/index.ts +14 -15
  45. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +24 -0
  46. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +24 -0
  47. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +24 -0
  48. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +83 -0
  49. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +83 -0
  50. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +18 -4
  51. package/scripts/harness/harness-api/domain/value-objects/known-harness-commands.ts +4 -1
  52. package/scripts/harness/integrations/pre-commit.ts +169 -27
  53. package/scripts/harness/main.ts +276 -126
  54. package/scripts/harness/nyquist-validation/application/dto/generate-matrix-output.ts +11 -0
  55. package/scripts/harness/nyquist-validation/application/usecases/check-ac-coverage-gate-usecase.ts +6 -0
  56. package/scripts/harness/nyquist-validation/application/usecases/generate-requirement-test-matrix-usecase.ts +8 -4
  57. package/scripts/harness/nyquist-validation/domain/entities/story-mapping.ts +29 -2
  58. package/scripts/harness/nyquist-validation/domain/services/ac-coverage-gate-policy.ts +28 -0
  59. package/scripts/harness/nyquist-validation/infrastructure/adapters/markdown-requirement-source-adapter.ts +71 -4
  60. package/scripts/harness/nyquist-validation/infrastructure/schema/matrix-schema-loader.ts +4 -0
  61. package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
  62. package/scripts/harness/traceability-model/application/dto/traceability-world-read-dto.ts +67 -0
  63. package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
  64. package/scripts/harness/traceability-model/application/facades/traceability-world-read-facade.ts +372 -0
  65. package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
  66. package/scripts/harness/traceability-model/application/ports/traceability-world-read-source-port.ts +61 -0
  67. package/scripts/harness/traceability-model/composition-root.ts +26 -5
  68. package/scripts/harness/traceability-model/index.ts +26 -6
  69. package/scripts/harness/traceability-model/infrastructure/adapters/file-system-traceability-world-read-adapter.ts +223 -0
  70. package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
  71. package/scripts/harness/traceability-model/infrastructure/parsers/story-catalog-parser.ts +86 -8
  72. package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +31 -0
  73. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +34 -0
  74. package/scripts/harness/validator-system/composition-root.ts +21 -6
  75. package/scripts/harness/validator-system/domain/ports/world-constraint-admission-policy-port.ts +28 -0
  76. package/scripts/harness/validator-system/domain/ports/world-constraint-rederivation-policy-port.ts +11 -0
  77. package/scripts/harness/validator-system/domain/services/design-change-declaration-policy.ts +75 -0
  78. package/scripts/harness/validator-system/domain/services/world-constraint-admission-service.ts +78 -0
  79. package/scripts/harness/validator-system/domain/services/world-constraint-rederivation-service.ts +76 -0
  80. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +4 -0
  81. package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +38 -16
  82. package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-admission-adapter.ts +56 -0
  83. package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-rederivation-adapter.ts +56 -0
  84. package/scripts/harness/world-model/application/dto/pinned-design-endpoint-dto.ts +19 -0
  85. package/scripts/harness/world-model/application/dto/world-inspection-dto.ts +43 -0
  86. package/scripts/harness/world-model/application/dto/world-obligation-report-dto.ts +54 -0
  87. package/scripts/harness/world-model/application/dto/world-resolved-config-input.ts +127 -0
  88. package/scripts/harness/world-model/application/dto/world-snapshot-root-dto.ts +8 -0
  89. package/scripts/harness/world-model/application/facades/pinned-design-endpoint-facade.ts +63 -0
  90. package/scripts/harness/world-model/application/facades/world-snapshot-root-facade.ts +19 -0
  91. package/scripts/harness/world-model/application/ports/obligation-report-writer-port.ts +7 -0
  92. package/scripts/harness/world-model/application/ports/world-control-declaration-repository-port.ts +57 -0
  93. package/scripts/harness/world-model/application/ports/world-fact-source-port.ts +17 -0
  94. package/scripts/harness/world-model/application/usecases/build-snapshot-use-case.ts +111 -0
  95. package/scripts/harness/world-model/application/usecases/derive-obligations-use-case.ts +155 -0
  96. package/scripts/harness/world-model/application/usecases/derive-world-obligations-use-case.ts +146 -0
  97. package/scripts/harness/world-model/application/usecases/inspect-world-use-case.ts +74 -0
  98. package/scripts/harness/world-model/application/usecases/pin-constraint-endpoint-use-case.ts +139 -0
  99. package/scripts/harness/world-model/composition-root.ts +247 -0
  100. package/scripts/harness/world-model/domain/entities/constraint-record.ts +148 -0
  101. package/scripts/harness/world-model/domain/entities/control-declarations.ts +274 -0
  102. package/scripts/harness/world-model/domain/entities/edge.ts +41 -0
  103. package/scripts/harness/world-model/domain/entities/extraction-diagnostic.ts +60 -0
  104. package/scripts/harness/world-model/domain/entities/snapshot.ts +75 -0
  105. package/scripts/harness/world-model/domain/entities/world-node.ts +210 -0
  106. package/scripts/harness/world-model/domain/ports/world-hashing-port.ts +8 -0
  107. package/scripts/harness/world-model/domain/services/canonical-json-serializer.ts +113 -0
  108. package/scripts/harness/world-model/domain/services/constraint-evaluator.ts +486 -0
  109. package/scripts/harness/world-model/domain/services/obligation-derivation-service.ts +199 -0
  110. package/scripts/harness/world-model/domain/services/policy-inputs-digest-deriver.ts +66 -0
  111. package/scripts/harness/world-model/domain/services/snapshot-root-deriver.ts +218 -0
  112. package/scripts/harness/world-model/domain/services/text-content-normalizer.ts +30 -0
  113. package/scripts/harness/world-model/domain/services/violation-fingerprint-deriver.ts +183 -0
  114. package/scripts/harness/world-model/domain/value-objects/artifact-kind.ts +58 -0
  115. package/scripts/harness/world-model/domain/value-objects/change-provenance.ts +137 -0
  116. package/scripts/harness/world-model/domain/value-objects/corpus-role.ts +57 -0
  117. package/scripts/harness/world-model/domain/value-objects/declared-key.ts +35 -0
  118. package/scripts/harness/world-model/domain/value-objects/evaluation-id.ts +41 -0
  119. package/scripts/harness/world-model/domain/value-objects/explicit-constraint-relation.ts +53 -0
  120. package/scripts/harness/world-model/domain/value-objects/explicit-node-alias.ts +30 -0
  121. package/scripts/harness/world-model/domain/value-objects/node-pin.ts +34 -0
  122. package/scripts/harness/world-model/domain/value-objects/path-key.ts +103 -0
  123. package/scripts/harness/world-model/domain/value-objects/sha256-digest.ts +39 -0
  124. package/scripts/harness/world-model/domain/value-objects/violation-fingerprint.ts +36 -0
  125. package/scripts/harness/world-model/domain/value-objects/wcr-rule-id.ts +59 -0
  126. package/scripts/harness/world-model/domain/value-objects/world-node-id.ts +222 -0
  127. package/scripts/harness/world-model/index.ts +33 -0
  128. package/scripts/harness/world-model/infrastructure/adapters/adr-fact-extractor.ts +27 -0
  129. package/scripts/harness/world-model/infrastructure/adapters/assembled-world-fact-source.ts +17 -0
  130. package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +323 -0
  131. package/scripts/harness/world-model/infrastructure/adapters/attestation-sha256-world-hashing-adapter.ts +15 -0
  132. package/scripts/harness/world-model/infrastructure/adapters/composite-design-fact-source.ts +23 -0
  133. package/scripts/harness/world-model/infrastructure/adapters/design-corpus-fact-extractor.ts +285 -0
  134. package/scripts/harness/world-model/infrastructure/adapters/design-fact-extraction.ts +63 -0
  135. package/scripts/harness/world-model/infrastructure/adapters/file-system-obligation-report-writer-adapter.ts +37 -0
  136. package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +332 -0
  137. package/scripts/harness/world-model/infrastructure/adapters/integrity-manifest-fact-extractor.ts +101 -0
  138. package/scripts/harness/world-model/infrastructure/adapters/json-fact-extractor-support.ts +151 -0
  139. package/scripts/harness/world-model/infrastructure/adapters/markdown-design-fact-extractor.ts +493 -0
  140. package/scripts/harness/world-model/infrastructure/adapters/matrix-fact-extractor.ts +283 -0
  141. package/scripts/harness/world-model/infrastructure/adapters/product-fact-extractor.ts +29 -0
  142. package/scripts/harness/world-model/infrastructure/adapters/proposal-fact-extractor.ts +29 -0
  143. package/scripts/harness/world-model/infrastructure/adapters/runtime-fact-extraction.ts +19 -0
  144. package/scripts/harness/world-model/infrastructure/adapters/source-metadata-fact-extractor.ts +22 -0
  145. package/scripts/harness/world-model/infrastructure/adapters/test-reference-source-fact-extractor.ts +22 -0
  146. package/scripts/harness/world-model/infrastructure/adapters/traceability-design-fact-adapter.ts +112 -0
  147. package/scripts/harness/world-model/infrastructure/adapters/traceability-world-read-facade-merger.ts +38 -0
  148. package/scripts/harness/world-model/infrastructure/adapters/type-script-source-fact-extractor.ts +236 -0
  149. package/scripts/harness/world-model/infrastructure/adapters/unit-fact-extractor.ts +71 -0
  150. package/scripts/harness/world-model/infrastructure/adapters/world-control-declaration-mapper.ts +383 -0
  151. package/scripts/harness/world-model/presentation/cli/world-command-support.ts +60 -0
  152. package/scripts/harness/world-model/presentation/cli/world-derive-command-handler.ts +109 -0
  153. package/scripts/harness/world-model/presentation/cli/world-inspect-command-handler.ts +194 -0
  154. package/scripts/harness/world-model/presentation/cli/world-pin-command-handler.ts +100 -0
@@ -0,0 +1,43 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-291
4
+
5
+ export type WorldJsonValue = null | boolean | number | string | readonly WorldJsonValue[] | WorldJsonObject;
6
+
7
+ export interface WorldJsonObject {
8
+ readonly [key: string]: WorldJsonValue;
9
+ }
10
+
11
+ export interface WorldInventoryCountDto {
12
+ readonly value: string;
13
+ readonly count: number;
14
+ }
15
+
16
+ export interface WorldExtractionDiagnosticDto extends WorldJsonObject {
17
+ readonly code: string;
18
+ readonly line: number | null;
19
+ readonly nodeId: string | null;
20
+ readonly pathKey: string | null;
21
+ readonly payload: WorldJsonObject;
22
+ }
23
+
24
+ export interface WorldInspectionDto {
25
+ readonly snapshotId: string;
26
+ readonly schemaVersion: string;
27
+ readonly extractorVersion: string;
28
+ readonly corpusRoot: string;
29
+ readonly summary: {
30
+ readonly nodeCount: number;
31
+ readonly edgeCount: number;
32
+ readonly diagnosticCount: number;
33
+ readonly hardDiagnosticCount: number;
34
+ };
35
+ readonly inventory: {
36
+ readonly nodeTypes: readonly WorldInventoryCountDto[];
37
+ readonly corpusRoles: readonly WorldInventoryCountDto[];
38
+ readonly artifactKinds: readonly WorldInventoryCountDto[];
39
+ };
40
+ readonly nodes: readonly WorldJsonObject[];
41
+ readonly edges: readonly WorldJsonObject[];
42
+ readonly diagnostics: readonly WorldExtractionDiagnosticDto[];
43
+ }
@@ -0,0 +1,54 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-295
4
+
5
+ import type { CanonicalJsonObject } from "../../domain/services/canonical-json-serializer.js";
6
+
7
+ export type StructuralObligationClassification = "adopted-legacy" | "new-structural" | "invalid-declaration" | "waived";
8
+
9
+ export interface StructuralObligationDto {
10
+ readonly violationFingerprint: string;
11
+ readonly ruleId: string;
12
+ readonly constraintId: string | null;
13
+ readonly factType: string | null;
14
+ readonly subject: CanonicalJsonObject;
15
+ readonly claimantPin: CanonicalJsonObject | null;
16
+ readonly premisePin: CanonicalJsonObject | null;
17
+ readonly expected: CanonicalJsonObject;
18
+ readonly observed: CanonicalJsonObject;
19
+ readonly classification: StructuralObligationClassification;
20
+ readonly waiver: CanonicalJsonObject | null;
21
+ }
22
+
23
+ export interface RepaidBaselineEntryDto {
24
+ readonly violationFingerprint: string;
25
+ readonly ruleId: string;
26
+ readonly constraintId: string | null;
27
+ readonly classification: "repaid";
28
+ readonly disposition: "cleanup-required";
29
+ }
30
+
31
+ export interface PolicyDiagnosticDto {
32
+ readonly code: string;
33
+ readonly subjectId: string | null;
34
+ readonly details: CanonicalJsonObject;
35
+ }
36
+
37
+ export interface ObligationReportSummaryDto {
38
+ readonly structuralObligations: number;
39
+ readonly repaidBaselineEntries: number;
40
+ readonly declaredSemanticDebts: number;
41
+ readonly policyDiagnostics: number;
42
+ }
43
+
44
+ export interface WorldObligationReportDto {
45
+ readonly schemaVersion: "phasegate-world-obligation-report/v1";
46
+ readonly evaluationId: string;
47
+ readonly rulesetVersion: string;
48
+ readonly policyInputsDigest: string;
49
+ readonly structuralObligations: readonly StructuralObligationDto[];
50
+ readonly repaidBaselineEntries: readonly RepaidBaselineEntryDto[];
51
+ readonly declaredSemanticDebts: readonly CanonicalJsonObject[];
52
+ readonly policyDiagnostics: readonly PolicyDiagnosticDto[];
53
+ readonly summary: ObligationReportSummaryDto;
54
+ }
@@ -0,0 +1,127 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-291, WI-300
4
+
5
+ import { PathKey } from "../../domain/value-objects/path-key.js";
6
+
7
+ export interface WorldResolvedConfigInput {
8
+ readonly enabled?: boolean;
9
+ readonly corpus?: {
10
+ readonly productRoots?: readonly string[];
11
+ readonly inceptionRoots?: readonly string[];
12
+ readonly adrRoots?: readonly string[];
13
+ readonly sourceRoots?: readonly string[];
14
+ readonly include?: readonly string[];
15
+ readonly exclude?: readonly string[];
16
+ };
17
+ readonly inputs?: {
18
+ readonly matrixPath?: string;
19
+ readonly attestationPath?: string;
20
+ readonly integrityManifestPath?: string;
21
+ };
22
+ readonly declarations?: {
23
+ readonly constraintsPath?: string;
24
+ readonly baselinePath?: string;
25
+ readonly waiversPath?: string;
26
+ readonly debtsPath?: string;
27
+ };
28
+ readonly output?: { readonly obligationReportPath?: string };
29
+ readonly sessionStart?: {
30
+ readonly enabled?: boolean;
31
+ readonly maxItems?: number;
32
+ readonly maxChars?: number;
33
+ };
34
+ readonly designDocsRoot?: string;
35
+ readonly inceptionRoot?: string;
36
+ readonly requirementMatrixPath?: string;
37
+ }
38
+
39
+ export interface WorldCorpusConfig {
40
+ readonly enabled: boolean;
41
+ readonly productScopes: readonly {
42
+ readonly productRoot: string;
43
+ readonly designDocsRoot: string;
44
+ readonly unitRoot: string;
45
+ }[];
46
+ readonly inceptionRoots: readonly string[];
47
+ readonly adrRoots: readonly string[];
48
+ readonly sourceRoots: readonly string[];
49
+ readonly include: readonly string[];
50
+ readonly exclude: readonly string[];
51
+ readonly matrixPath: string;
52
+ readonly attestationPath: string;
53
+ readonly integrityManifestPath: string;
54
+ readonly constraintsPath: string;
55
+ readonly baselinePath: string;
56
+ readonly waiversPath: string;
57
+ readonly debtsPath: string;
58
+ readonly obligationReportPath: string;
59
+ readonly sessionStart: { readonly enabled: boolean; readonly maxItems: number; readonly maxChars: number };
60
+ }
61
+
62
+ const validatePath = (value: string): string => PathKey.create(value).toString();
63
+ const validatePaths = (values: readonly string[]): readonly string[] => Object.freeze(values.map(validatePath));
64
+
65
+ const deriveProductRoot = (designDocsRoot: string): string => {
66
+ const normalized = designDocsRoot.replace(/\/+$/, "");
67
+ return normalized.endsWith("/construction") ? normalized.slice(0, -"/construction".length) : normalized;
68
+ };
69
+
70
+ const resolveProductRoots = (input?: WorldResolvedConfigInput): readonly string[] => {
71
+ if (input?.corpus?.productRoots !== undefined) return validatePaths(input.corpus.productRoots);
72
+ if (input?.designDocsRoot === undefined) return Object.freeze(["docs/product"]);
73
+ const productRoot = validatePath(deriveProductRoot(input.designDocsRoot));
74
+ return Object.freeze(productRoot === "docs/product" ? [productRoot] : ["docs/product", productRoot]);
75
+ };
76
+
77
+ const assertLimit = (name: string, value: number, maximum: number): number => {
78
+ if (!Number.isInteger(value) || value < 1 || value > maximum) {
79
+ throw new Error(`${name} must be an integer between 1 and ${maximum}`);
80
+ }
81
+ return value;
82
+ };
83
+
84
+ export const resolveWorldCorpusConfig = (input?: WorldResolvedConfigInput): WorldCorpusConfig => {
85
+ const productRoots = resolveProductRoots(input);
86
+ const inceptionRoots = validatePaths(input?.corpus?.inceptionRoots ?? [input?.inceptionRoot ?? "docs/inception"]);
87
+ const adrRoots = validatePaths(input?.corpus?.adrRoots ?? ["docs/ADR"]);
88
+ const sourceRoots = validatePaths(input?.corpus?.sourceRoots ?? ["scripts/harness"]);
89
+ if ([productRoots, inceptionRoots, adrRoots, sourceRoots].some((roots) => roots.length === 0)) {
90
+ throw new Error("World corpus roots must not be empty");
91
+ }
92
+ const include = Object.freeze([...(input?.corpus?.include ?? ["**/*"])]);
93
+ const exclude = Object.freeze([...(input?.corpus?.exclude ?? [])]);
94
+ if (include.length === 0 || [...include, ...exclude].some((pattern) => pattern.length === 0)) {
95
+ throw new Error("World corpus selection patterns must not be empty");
96
+ }
97
+ return Object.freeze({
98
+ enabled: input?.enabled ?? false,
99
+ productScopes: Object.freeze(
100
+ productRoots.map((productRoot) => ({
101
+ productRoot,
102
+ designDocsRoot: validatePath(`${productRoot}/construction`),
103
+ unitRoot: validatePath(`${productRoot}/units`),
104
+ })),
105
+ ),
106
+ inceptionRoots,
107
+ adrRoots,
108
+ sourceRoots,
109
+ include,
110
+ exclude,
111
+ matrixPath: validatePath(
112
+ input?.inputs?.matrixPath ?? input?.requirementMatrixPath ?? ".harness/requirement-test-matrix.json",
113
+ ),
114
+ attestationPath: validatePath(input?.inputs?.attestationPath ?? ".harness/attestation.json"),
115
+ integrityManifestPath: validatePath(input?.inputs?.integrityManifestPath ?? "phasegate.integrity.json"),
116
+ constraintsPath: validatePath(input?.declarations?.constraintsPath ?? "phasegate.world-constraints.json"),
117
+ baselinePath: validatePath(input?.declarations?.baselinePath ?? "phasegate.world-baseline.json"),
118
+ waiversPath: validatePath(input?.declarations?.waiversPath ?? "phasegate.world-waivers.json"),
119
+ debtsPath: validatePath(input?.declarations?.debtsPath ?? "phasegate.world-debts.json"),
120
+ obligationReportPath: validatePath(input?.output?.obligationReportPath ?? ".harness/world-obligations.json"),
121
+ sessionStart: Object.freeze({
122
+ enabled: input?.sessionStart?.enabled ?? true,
123
+ maxItems: assertLimit("world.sessionStart.maxItems", input?.sessionStart?.maxItems ?? 5, 20),
124
+ maxChars: assertLimit("world.sessionStart.maxChars", input?.sessionStart?.maxChars ?? 2000, 8000),
125
+ }),
126
+ });
127
+ };
@@ -0,0 +1,8 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-306
4
+
5
+ export interface WorldSnapshotRootDto {
6
+ readonly schemaVersion: "phasegate-world-snapshot-root/v1";
7
+ readonly worldSnapshotRoot: string;
8
+ }
@@ -0,0 +1,63 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-305
4
+
5
+ import type { PinnedDesignEndpointDto, PinnedDesignEndpointReadResultDto } from "../dto/pinned-design-endpoint-dto.js";
6
+ import type { ConstraintDeclarationRepositoryPort } from "../ports/world-control-declaration-repository-port.js";
7
+
8
+ const EXPLICIT_FRAGMENT_ID = /^pgw:v1:fragment:(product|inception):(.+)$/;
9
+ const compare = (left: string, right: string): number => (left < right ? -1 : left > right ? 1 : 0);
10
+
11
+ export class PinnedDesignEndpointFacade {
12
+ constructor(private readonly repository: ConstraintDeclarationRepositoryPort) {}
13
+
14
+ async read(): Promise<PinnedDesignEndpointReadResultDto> {
15
+ const result = await this.repository.load();
16
+ if (result.state === "invalid") {
17
+ return Object.freeze({
18
+ state: "unavailable",
19
+ diagnosticCodes: Object.freeze([...new Set(result.diagnostics.map((item) => item.code))].sort(compare)),
20
+ });
21
+ }
22
+ if (result.value.malformedDeclarations.length > 0 || result.value.diagnostics.length > 0) {
23
+ return Object.freeze({
24
+ state: "unavailable",
25
+ diagnosticCodes: Object.freeze(
26
+ [
27
+ ...(result.value.malformedDeclarations.length > 0 ? ["malformed-constraint-declaration"] : []),
28
+ ...result.value.diagnostics.map((item) => item.code),
29
+ ].sort(compare),
30
+ ),
31
+ });
32
+ }
33
+ const endpoints: PinnedDesignEndpointDto[] = [];
34
+ for (const record of result.value.records) {
35
+ for (const endpoint of ["claimant", "premise"] as const) {
36
+ const nodeId = record[endpoint].nodeId.toString();
37
+ const match = EXPLICIT_FRAGMENT_ID.exec(nodeId);
38
+ if (!match) continue;
39
+ endpoints.push(
40
+ Object.freeze({
41
+ constraintId: record.constraintId.toString(),
42
+ endpoint,
43
+ nodeId,
44
+ corpusRole: match[1] as "product" | "inception",
45
+ declaredKey: match[2],
46
+ }),
47
+ );
48
+ }
49
+ }
50
+ endpoints.sort(
51
+ (left, right) =>
52
+ compare(left.corpusRole, right.corpusRole) ||
53
+ compare(left.declaredKey, right.declaredKey) ||
54
+ compare(left.constraintId, right.constraintId) ||
55
+ compare(left.endpoint, right.endpoint),
56
+ );
57
+ return Object.freeze({
58
+ state: "available",
59
+ endpoints: Object.freeze(endpoints),
60
+ diagnosticCodes: Object.freeze([]),
61
+ });
62
+ }
63
+ }
@@ -0,0 +1,19 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-306
4
+
5
+ import type { WorldSnapshotRootDto } from "../dto/world-snapshot-root-dto.js";
6
+ import type { BuildSnapshotContract } from "../usecases/build-snapshot-use-case.js";
7
+
8
+ /** World domain型を公開せずcurrent corpusRootだけを返すpublic read facade。 */
9
+ export class WorldSnapshotRootFacade {
10
+ constructor(private readonly buildSnapshot: BuildSnapshotContract) {}
11
+
12
+ async read(): Promise<WorldSnapshotRootDto> {
13
+ const snapshot = await this.buildSnapshot.execute();
14
+ return {
15
+ schemaVersion: "phasegate-world-snapshot-root/v1",
16
+ worldSnapshotRoot: snapshot.corpusRoot.toString(),
17
+ };
18
+ }
19
+ }
@@ -0,0 +1,7 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-295, WI-296
4
+
5
+ export interface ObligationReportWriterPort {
6
+ write(bytes: Uint8Array, reportPath?: string): Promise<void>;
7
+ }
@@ -0,0 +1,57 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-294
4
+
5
+ import type { ConstraintRecord, MalformedConstraintDeclaration } from "../../domain/entities/constraint-record.js";
6
+ import type {
7
+ AdoptionBaseline,
8
+ SemanticDebtDeclaration,
9
+ WorldWaiver,
10
+ } from "../../domain/entities/control-declarations.js";
11
+ import type { ExplicitConstraintRelation } from "../../domain/value-objects/explicit-constraint-relation.js";
12
+ import type { ExplicitNodeAlias } from "../../domain/value-objects/explicit-node-alias.js";
13
+
14
+ export interface WorldControlDiagnosticDto {
15
+ readonly code: string;
16
+ readonly path: string;
17
+ readonly locator: string | null;
18
+ readonly message: string;
19
+ }
20
+
21
+ export interface ConstraintDeclarationSet {
22
+ readonly schemaVersion: "phasegate-world-constraints/v1";
23
+ readonly records: readonly ConstraintRecord[];
24
+ readonly malformedDeclarations: readonly MalformedConstraintDeclaration[];
25
+ readonly aliases: readonly ExplicitNodeAlias[];
26
+ readonly relations: readonly ExplicitConstraintRelation[];
27
+ readonly diagnostics: readonly WorldControlDiagnosticDto[];
28
+ }
29
+
30
+ export type WorldControlReadResult<T> =
31
+ | { readonly state: "absent"; readonly value: T; readonly diagnostics: readonly WorldControlDiagnosticDto[] }
32
+ | { readonly state: "loaded"; readonly value: T; readonly diagnostics: readonly WorldControlDiagnosticDto[] }
33
+ | { readonly state: "invalid"; readonly diagnostics: readonly WorldControlDiagnosticDto[] };
34
+
35
+ export type WorldControlReplaceResult =
36
+ | { readonly state: "written"; readonly path: string }
37
+ | { readonly state: "invalid"; readonly diagnostics: readonly WorldControlDiagnosticDto[] };
38
+
39
+ export interface ConstraintDeclarationRepositoryPort {
40
+ load(): Promise<WorldControlReadResult<ConstraintDeclarationSet>>;
41
+ replaceAtomically(document: unknown): Promise<WorldControlReplaceResult>;
42
+ }
43
+
44
+ export interface AdoptionBaselineRepositoryPort {
45
+ load(): Promise<WorldControlReadResult<AdoptionBaseline | null>>;
46
+ replaceAtomically(document: unknown): Promise<WorldControlReplaceResult>;
47
+ }
48
+
49
+ export interface WaiverDeclarationRepositoryPort {
50
+ load(): Promise<WorldControlReadResult<readonly WorldWaiver[]>>;
51
+ replaceAtomically(document: unknown): Promise<WorldControlReplaceResult>;
52
+ }
53
+
54
+ export interface SemanticDebtRepositoryPort {
55
+ load(): Promise<WorldControlReadResult<readonly SemanticDebtDeclaration[]>>;
56
+ replaceAtomically(document: unknown): Promise<WorldControlReplaceResult>;
57
+ }
@@ -0,0 +1,17 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-291
4
+
5
+ import type { Edge } from "../../domain/entities/edge.js";
6
+ import type { ExtractionDiagnostic } from "../../domain/entities/extraction-diagnostic.js";
7
+ import type { WorldNode } from "../../domain/entities/world-node.js";
8
+
9
+ export interface WorldFactBatch {
10
+ readonly nodes: readonly WorldNode[];
11
+ readonly edges: readonly Edge[];
12
+ readonly diagnostics: readonly ExtractionDiagnostic[];
13
+ }
14
+
15
+ export interface WorldFactSourcePort {
16
+ extract(): Promise<readonly WorldFactBatch[]>;
17
+ }
@@ -0,0 +1,111 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-291
4
+
5
+ import type { Edge } from "../../domain/entities/edge.js";
6
+ import { ExtractionDiagnostic } from "../../domain/entities/extraction-diagnostic.js";
7
+ import type { Snapshot } from "../../domain/entities/snapshot.js";
8
+ import type { WorldNode } from "../../domain/entities/world-node.js";
9
+ import type { CanonicalJsonSerializer } from "../../domain/services/canonical-json-serializer.js";
10
+ import type { SnapshotRootDeriver } from "../../domain/services/snapshot-root-deriver.js";
11
+ import type { Sha256Digest } from "../../domain/value-objects/sha256-digest.js";
12
+ import type { WorldFactSourcePort } from "../ports/world-fact-source-port.js";
13
+
14
+ export interface BuildSnapshotContract {
15
+ execute(): Promise<Snapshot>;
16
+ }
17
+
18
+ export interface BuildSnapshotUseCaseDeps {
19
+ readonly factSource: WorldFactSourcePort;
20
+ readonly rootDeriver: SnapshotRootDeriver;
21
+ readonly serializer: CanonicalJsonSerializer;
22
+ readonly schemaVersion: string;
23
+ readonly extractorVersion: string;
24
+ readonly corpusConfigDigest: Sha256Digest;
25
+ }
26
+
27
+ const compareStrings = (left: string, right: string): number => (left < right ? -1 : left > right ? 1 : 0);
28
+
29
+ export class BuildSnapshotUseCase implements BuildSnapshotContract {
30
+ constructor(private readonly deps: BuildSnapshotUseCaseDeps) {}
31
+
32
+ async execute(): Promise<Snapshot> {
33
+ const batches = await this.deps.factSource.extract();
34
+ const diagnostics = batches.flatMap((batch) => batch.diagnostics);
35
+ const nodes = this.admitNodes(
36
+ batches.flatMap((batch) => batch.nodes),
37
+ diagnostics,
38
+ );
39
+ const edges = this.admitEdges(
40
+ batches.flatMap((batch) => batch.edges),
41
+ new Set(nodes.map((node) => node.id.toString())),
42
+ diagnostics,
43
+ );
44
+ return this.deps.rootDeriver.buildSnapshot({
45
+ schemaVersion: this.deps.schemaVersion,
46
+ extractorVersion: this.deps.extractorVersion,
47
+ corpusConfigDigest: this.deps.corpusConfigDigest,
48
+ nodes,
49
+ edges,
50
+ extractionDiagnostics: diagnostics,
51
+ });
52
+ }
53
+
54
+ private admitNodes(candidates: readonly WorldNode[], diagnostics: ExtractionDiagnostic[]): readonly WorldNode[] {
55
+ const grouped = new Map<string, WorldNode[]>();
56
+ for (const candidate of candidates) {
57
+ const key = candidate.id.toString();
58
+ grouped.set(key, [...(grouped.get(key) ?? []), candidate]);
59
+ }
60
+ const admitted: WorldNode[] = [];
61
+ for (const [nodeId, entries] of [...grouped.entries()].sort(([left], [right]) => compareStrings(left, right))) {
62
+ if (entries.length === 1) {
63
+ admitted.push(entries[0]);
64
+ continue;
65
+ }
66
+ diagnostics.push(
67
+ ExtractionDiagnostic.create({
68
+ code: "duplicate-node-id",
69
+ nodeId: entries[0].id,
70
+ payload: {
71
+ candidates: entries.length,
72
+ candidateFacts: entries
73
+ .map((entry) => this.deps.serializer.stringify(entry.toCanonicalValue()))
74
+ .sort(compareStrings),
75
+ nodeId,
76
+ },
77
+ }),
78
+ );
79
+ }
80
+ return admitted;
81
+ }
82
+
83
+ private admitEdges(
84
+ candidates: readonly Edge[],
85
+ nodeIds: ReadonlySet<string>,
86
+ diagnostics: ExtractionDiagnostic[],
87
+ ): readonly Edge[] {
88
+ const unique = new Map<string, Edge>();
89
+ for (const edge of candidates) {
90
+ const key = this.deps.serializer.stringify(edge.toCanonicalValue());
91
+ if (!unique.has(key)) unique.set(key, edge);
92
+ }
93
+ const admitted: Edge[] = [];
94
+ for (const [edgeKey, edge] of [...unique.entries()].sort(([left], [right]) => compareStrings(left, right))) {
95
+ const missingEndpoints = [edge.from.toString(), edge.to.toString()]
96
+ .filter((endpoint) => !nodeIds.has(endpoint))
97
+ .sort(compareStrings);
98
+ if (missingEndpoints.length === 0) {
99
+ admitted.push(edge);
100
+ continue;
101
+ }
102
+ diagnostics.push(
103
+ ExtractionDiagnostic.create({
104
+ code: "missing-edge-endpoint",
105
+ payload: { edge: edgeKey, missingEndpoints },
106
+ }),
107
+ );
108
+ }
109
+ return admitted;
110
+ }
111
+ }
@@ -0,0 +1,155 @@
1
+ // @unit world-model
2
+ // @layer application
3
+ // @work-item-id WI-295, WI-296
4
+
5
+ import type { CanonicalJsonSerializer } from "../../domain/services/canonical-json-serializer.js";
6
+ import type { ConstraintFindingDto } from "../../domain/services/constraint-evaluator.js";
7
+ import type { ObligationDerivationService } from "../../domain/services/obligation-derivation-service.js";
8
+ import type {
9
+ PolicyInputsDigestDerivation,
10
+ PolicyInputsDigestDeriver,
11
+ } from "../../domain/services/policy-inputs-digest-deriver.js";
12
+ import type { SnapshotRootDeriver } from "../../domain/services/snapshot-root-deriver.js";
13
+ import type { Sha256Digest } from "../../domain/value-objects/sha256-digest.js";
14
+ import type { WorldObligationReportDto } from "../dto/world-obligation-report-dto.js";
15
+ import type { ObligationReportWriterPort } from "../ports/obligation-report-writer-port.js";
16
+ import type {
17
+ AdoptionBaselineRepositoryPort,
18
+ SemanticDebtRepositoryPort,
19
+ WaiverDeclarationRepositoryPort,
20
+ WorldControlDiagnosticDto,
21
+ WorldControlReadResult,
22
+ } from "../ports/world-control-declaration-repository-port.js";
23
+
24
+ export interface DeriveObligationsInput {
25
+ readonly rulesetVersion: string;
26
+ readonly findings: readonly ConstraintFindingDto[];
27
+ readonly corpusRoot: Sha256Digest;
28
+ readonly constraintRoot: Sha256Digest;
29
+ readonly evaluationConfigDigest: Sha256Digest;
30
+ readonly policyAsOfDate: string | null;
31
+ readonly writeReport: boolean;
32
+ readonly reportPath?: string;
33
+ }
34
+
35
+ export type ReportPersistenceResult =
36
+ | { readonly state: "not-requested" }
37
+ | { readonly state: "written" }
38
+ | { readonly state: "failed"; readonly message: string };
39
+
40
+ export type DeriveObligationsResult =
41
+ | {
42
+ readonly status: "derived";
43
+ readonly report: WorldObligationReportDto;
44
+ readonly canonicalBytes: Uint8Array;
45
+ readonly persistence: ReportPersistenceResult;
46
+ }
47
+ | {
48
+ readonly status: "invalid-policy-input";
49
+ readonly diagnostics: readonly WorldControlDiagnosticDto[];
50
+ };
51
+
52
+ interface Dependencies {
53
+ readonly baselineRepository: AdoptionBaselineRepositoryPort;
54
+ readonly waiverRepository: WaiverDeclarationRepositoryPort;
55
+ readonly semanticDebtRepository: SemanticDebtRepositoryPort;
56
+ readonly policyInputsDigestDeriver: PolicyInputsDigestDeriver;
57
+ readonly evaluationIdDeriver: SnapshotRootDeriver;
58
+ readonly obligationDerivationService: ObligationDerivationService;
59
+ readonly serializer: CanonicalJsonSerializer;
60
+ readonly writer: ObligationReportWriterPort;
61
+ }
62
+
63
+ const compareStrings = (left: string, right: string): number => (left < right ? -1 : left > right ? 1 : 0);
64
+
65
+ const diagnosticsOf = <T>(result: WorldControlReadResult<T>): readonly WorldControlDiagnosticDto[] =>
66
+ result.state === "invalid" ? result.diagnostics : [];
67
+
68
+ export class DeriveObligationsUseCase {
69
+ constructor(private readonly dependencies: Dependencies) {}
70
+
71
+ async execute(input: DeriveObligationsInput): Promise<DeriveObligationsResult> {
72
+ const [baselineResult, waiverResult, debtResult] = await Promise.all([
73
+ this.dependencies.baselineRepository.load(),
74
+ this.dependencies.waiverRepository.load(),
75
+ this.dependencies.semanticDebtRepository.load(),
76
+ ]);
77
+ const diagnostics = [
78
+ ...diagnosticsOf(baselineResult),
79
+ ...diagnosticsOf(waiverResult),
80
+ ...diagnosticsOf(debtResult),
81
+ ].sort(
82
+ (left, right) =>
83
+ compareStrings(left.code, right.code) ||
84
+ compareStrings(left.path, right.path) ||
85
+ compareStrings(left.locator ?? "", right.locator ?? ""),
86
+ );
87
+ if (baselineResult.state === "invalid" || waiverResult.state === "invalid" || debtResult.state === "invalid") {
88
+ return Object.freeze({
89
+ status: "invalid-policy-input",
90
+ diagnostics: Object.freeze(diagnostics),
91
+ });
92
+ }
93
+
94
+ let policy: PolicyInputsDigestDerivation;
95
+ try {
96
+ policy = this.dependencies.policyInputsDigestDeriver.derive({
97
+ baseline: baselineResult.value,
98
+ waivers: waiverResult.value,
99
+ semanticDebts: debtResult.value,
100
+ policyAsOfDate: input.policyAsOfDate,
101
+ });
102
+ } catch (error) {
103
+ return Object.freeze({
104
+ status: "invalid-policy-input",
105
+ diagnostics: Object.freeze([
106
+ {
107
+ code: "invalid-policy-as-of-date",
108
+ path: "world.policyAsOfDate",
109
+ locator: null,
110
+ message: error instanceof Error ? error.message : String(error),
111
+ },
112
+ ]),
113
+ });
114
+ }
115
+ const evaluation = this.dependencies.evaluationIdDeriver.deriveEvaluationId({
116
+ schemaVersion: "phasegate-world-evaluation/v1",
117
+ rulesetVersion: input.rulesetVersion,
118
+ corpusRoot: input.corpusRoot,
119
+ constraintRoot: input.constraintRoot,
120
+ evaluationConfigDigest: input.evaluationConfigDigest,
121
+ policyInputsDigest: policy.digest,
122
+ });
123
+ const report: WorldObligationReportDto = this.dependencies.obligationDerivationService.derive({
124
+ evaluationId: evaluation.evaluationId,
125
+ rulesetVersion: input.rulesetVersion,
126
+ policyInputsDigest: policy.digest,
127
+ findings: input.findings,
128
+ baseline: baselineResult.value,
129
+ waivers: waiverResult.value,
130
+ semanticDebts: debtResult.value,
131
+ policyAsOfDate: policy.resolvedPolicyAsOfDate,
132
+ });
133
+ const canonicalBytes = this.dependencies.serializer.serialize(report);
134
+ let persistence: ReportPersistenceResult = Object.freeze({
135
+ state: "not-requested",
136
+ });
137
+ if (input.writeReport) {
138
+ try {
139
+ await this.dependencies.writer.write(canonicalBytes, input.reportPath);
140
+ persistence = Object.freeze({ state: "written" });
141
+ } catch (error) {
142
+ persistence = Object.freeze({
143
+ state: "failed",
144
+ message: error instanceof Error ? error.message : String(error),
145
+ });
146
+ }
147
+ }
148
+ return Object.freeze({
149
+ status: "derived",
150
+ report,
151
+ canonicalBytes,
152
+ persistence,
153
+ });
154
+ }
155
+ }