phasegate 0.254.0 → 0.283.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 (82) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.ja.md +6 -3
  3. package/README.md +6 -3
  4. package/docs/contracts/attestation-v2.schema.json +110 -0
  5. package/docs/guide/cli-reference.md +12 -1
  6. package/docs/guide/configuration.md +56 -0
  7. package/docs/guide/installation.md +1 -1
  8. package/docs/templates/ci/aidlc-gate.yml +60 -2
  9. package/package.json +2 -2
  10. package/scripts/harness/agent-integration/application/dto/open-world-obligations-context-dto.ts +30 -0
  11. package/scripts/harness/agent-integration/application/ports/world-obligations-query-port.ts +30 -0
  12. package/scripts/harness/agent-integration/application/usecases/get-open-world-obligations-context-usecase.ts +66 -0
  13. package/scripts/harness/agent-integration/infrastructure/adapters/harness-config-config-query-adapter.ts +30 -27
  14. package/scripts/harness/agent-integration/infrastructure/adapters/world-model-open-obligations-query-adapter.ts +58 -0
  15. package/scripts/harness/agent-integration/presentation/post-tool-use-hook.ts +29 -16
  16. package/scripts/harness/agent-integration/presentation/session-start-hook.ts +37 -1
  17. package/scripts/harness/agent-integration/presentation/stop-hook.ts +35 -26
  18. package/scripts/harness/agent-integration/presentation/world-obligations-session-context.ts +60 -0
  19. package/scripts/harness/attestation/application/dto/attestation-document.ts +17 -4
  20. package/scripts/harness/attestation/application/mappers/attestation-record-mapper.ts +55 -4
  21. package/scripts/harness/attestation/application/ports/world-snapshot-root-provider.ts +10 -0
  22. package/scripts/harness/attestation/application/usecases/produce-attestation-usecase.ts +33 -7
  23. package/scripts/harness/attestation/composition-root.ts +5 -0
  24. package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
  25. package/scripts/harness/attestation/index.ts +7 -1
  26. package/scripts/harness/attestation/presentation/handlers/attest-handler.ts +5 -2
  27. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +40 -9
  28. package/scripts/harness/config-foundation/application/mappers/world-model-config-mapper.ts +15 -0
  29. package/scripts/harness/config-foundation/domain/harness-config.ts +70 -87
  30. package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +80 -88
  31. package/scripts/harness/config-foundation/domain/value-objects/project-config.ts +34 -18
  32. package/scripts/harness/config-foundation/domain/value-objects/world-config.ts +198 -0
  33. package/scripts/harness/config-foundation/index.ts +14 -15
  34. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +24 -0
  35. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +24 -0
  36. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +24 -0
  37. package/scripts/harness/config-foundation/infrastructure/repositories/file-system-config-repository.ts +27 -18
  38. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +84 -8
  39. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +84 -8
  40. package/scripts/harness/harness-api/domain/ports/config-query-port.ts +11 -1
  41. package/scripts/harness/harness-api/domain/services/command-dispatch-service.ts +125 -86
  42. package/scripts/harness/harness-api/domain/services/status-derivation-service.ts +31 -21
  43. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +18 -4
  44. package/scripts/harness/harness-api/domain/value-objects/harness-status-summary.ts +23 -8
  45. package/scripts/harness/harness-api/infrastructure/adapters/biome-ast-engine-lint-adapter.ts +4 -4
  46. package/scripts/harness/harness-api/infrastructure/adapters/harness-config-query-adapter.ts +79 -34
  47. package/scripts/harness/installation/application/usecases/run-install.ts +199 -51
  48. package/scripts/harness/installation/application/usecases/run-reconcile.ts +277 -69
  49. package/scripts/harness/installation/domain/deployment-manifest.ts +43 -0
  50. package/scripts/harness/integrations/pre-commit.ts +169 -27
  51. package/scripts/harness/main.ts +200 -136
  52. package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
  53. package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
  54. package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
  55. package/scripts/harness/traceability-model/composition-root.ts +5 -0
  56. package/scripts/harness/traceability-model/index.ts +9 -0
  57. package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
  58. package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +31 -0
  59. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +57 -6
  60. package/scripts/harness/validator-system/composition-root.ts +25 -7
  61. package/scripts/harness/validator-system/domain/ports/ac-coverage-policy-port.ts +10 -1
  62. package/scripts/harness/validator-system/domain/ports/world-constraint-admission-policy-port.ts +28 -0
  63. package/scripts/harness/validator-system/domain/ports/world-constraint-rederivation-policy-port.ts +11 -0
  64. package/scripts/harness/validator-system/domain/services/design-change-declaration-policy.ts +75 -0
  65. package/scripts/harness/validator-system/domain/services/world-constraint-admission-service.ts +78 -0
  66. package/scripts/harness/validator-system/domain/services/world-constraint-rederivation-service.ts +76 -0
  67. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +4 -0
  68. package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +126 -18
  69. package/scripts/harness/validator-system/infrastructure/adapters/nyquist-ac-coverage-policy-adapter.ts +49 -20
  70. package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-admission-adapter.ts +56 -0
  71. package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-rederivation-adapter.ts +56 -0
  72. package/scripts/harness/world-model/application/dto/pinned-design-endpoint-dto.ts +19 -0
  73. package/scripts/harness/world-model/application/dto/world-resolved-config-input.ts +92 -27
  74. package/scripts/harness/world-model/application/dto/world-snapshot-root-dto.ts +8 -0
  75. package/scripts/harness/world-model/application/facades/pinned-design-endpoint-facade.ts +63 -0
  76. package/scripts/harness/world-model/application/facades/world-snapshot-root-facade.ts +19 -0
  77. package/scripts/harness/world-model/application/usecases/derive-world-obligations-use-case.ts +3 -1
  78. package/scripts/harness/world-model/composition-root.ts +62 -33
  79. package/scripts/harness/world-model/index.ts +11 -0
  80. package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +48 -13
  81. package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +6 -4
  82. package/scripts/harness/world-model/presentation/cli/world-derive-command-handler.ts +6 -2
@@ -1,5 +1,6 @@
1
1
  // @unit attestation
2
2
  // @layer application
3
+ // @work-item-id WI-306
3
4
 
4
5
  import {
5
6
  AttestationRecord,
@@ -44,15 +45,20 @@ function requireBoolean(v: unknown, field: string): boolean {
44
45
  return v;
45
46
  }
46
47
 
48
+ function rejectUnknownFields(value: Record<string, unknown>, allowed: readonly string[], field: string): void {
49
+ const unsupported = Object.keys(value).filter((key) => !allowed.includes(key));
50
+ if (unsupported.length > 0) {
51
+ throw new MalformedAttestationError(`${field} contains unsupported fields: ${unsupported.sort().join(", ")}`);
52
+ }
53
+ }
54
+
47
55
  /**
48
56
  * AttestationRecord(domain)↔ AttestationDocument(application DTO)の双方向変換。
49
57
  */
50
58
  export class AttestationRecordMapper {
51
59
  /** 集約を plain object へ射影(VO をプリミティブ展開)。 */
52
60
  toDocument(record: AttestationRecord): AttestationDocument {
53
- return {
54
- schemaVersion: record.schemaVersion as "phasegate-attestation/v1",
55
- predicateType: record.predicateType,
61
+ const common = {
56
62
  subject: {
57
63
  command: record.subject.command,
58
64
  gateResult: record.subject.gateResult,
@@ -63,7 +69,7 @@ export class AttestationRecordMapper {
63
69
  })),
64
70
  },
65
71
  inputs: {
66
- digestAlgorithm: "sha256",
72
+ digestAlgorithm: "sha256" as const,
67
73
  sources: record.inputs.sources.map((s) => ({ path: s.path, digest: s.digest.value })),
68
74
  inputDigest: record.inputs.inputDigest.value,
69
75
  },
@@ -89,6 +95,19 @@ export class AttestationRecordMapper {
89
95
  value: record.signature.value,
90
96
  },
91
97
  };
98
+ if (record.worldSnapshotRoot !== null) {
99
+ return {
100
+ ...common,
101
+ schemaVersion: "phasegate-attestation/v2",
102
+ predicateType: "https://phasegate.dev/attestation/gate-run/v2",
103
+ worldSnapshotRoot: record.worldSnapshotRoot.value,
104
+ };
105
+ }
106
+ return {
107
+ ...common,
108
+ schemaVersion: "phasegate-attestation/v1",
109
+ predicateType: "https://phasegate.dev/attestation/gate-run/v1",
110
+ };
92
111
  }
93
112
 
94
113
  /**
@@ -102,6 +121,37 @@ export class AttestationRecordMapper {
102
121
 
103
122
  const schemaVersion = requireString(doc.schemaVersion, "schemaVersion");
104
123
  const predicateType = requireString(doc.predicateType, "predicateType");
124
+ let worldSnapshotRoot: Digest | undefined;
125
+ if (schemaVersion === "phasegate-attestation/v1") {
126
+ if (predicateType !== "https://phasegate.dev/attestation/gate-run/v1") {
127
+ throw new MalformedAttestationError("v1 predicateType does not match schemaVersion");
128
+ }
129
+ if (doc.worldSnapshotRoot !== undefined) {
130
+ throw new MalformedAttestationError("v1 must not contain worldSnapshotRoot");
131
+ }
132
+ } else if (schemaVersion === "phasegate-attestation/v2") {
133
+ if (predicateType !== "https://phasegate.dev/attestation/gate-run/v2") {
134
+ throw new MalformedAttestationError("v2 predicateType does not match schemaVersion");
135
+ }
136
+ worldSnapshotRoot = this.toDigest(doc.worldSnapshotRoot, "worldSnapshotRoot");
137
+ rejectUnknownFields(
138
+ doc,
139
+ [
140
+ "schemaVersion",
141
+ "predicateType",
142
+ "subject",
143
+ "inputs",
144
+ "granularity",
145
+ "acBoundScope",
146
+ "worldSnapshotRoot",
147
+ "metadata",
148
+ "signature",
149
+ ],
150
+ "v2 attestation",
151
+ );
152
+ } else {
153
+ throw new MalformedAttestationError(`unsupported schemaVersion: ${schemaVersion}`);
154
+ }
105
155
 
106
156
  const subject = doc.subject;
107
157
  if (!isObject(subject)) {
@@ -185,6 +235,7 @@ export class AttestationRecordMapper {
185
235
  },
186
236
  signature: this.toSignatureBlock(mode, attestationDigest, signature),
187
237
  acBoundScope,
238
+ ...(worldSnapshotRoot === undefined ? {} : { worldSnapshotRoot }),
188
239
  };
189
240
 
190
241
  // verify 用の再構築: INV-1/INV-3 は verify usecase が機械的チェックとして検出するため
@@ -0,0 +1,10 @@
1
+ // @unit attestation
2
+ // @layer application
3
+ // @work-item-id WI-306
4
+
5
+ /**
6
+ * attestationが所有するconsumer port。providerのWorld domain型を公開しない。
7
+ */
8
+ export interface WorldSnapshotRootProvider {
9
+ getWorldSnapshotRoot(): Promise<string>;
10
+ }
@@ -1,23 +1,28 @@
1
1
  // @unit attestation
2
2
  // @layer application
3
+ // @work-item-id WI-306
3
4
 
4
5
  import { AttestationRecord, type GateResult, type SourceEntry } from "../../domain/entities/attestation-record.js";
5
6
  import type { ContentHasherPort } from "../../domain/ports/content-hasher-port.js";
6
- import type { GranularityDerivationService } from "../../domain/services/granularity-derivation-service.js";
7
7
  import type { AcBoundScopeService } from "../../domain/services/ac-bound-scope-service.js";
8
+ import type { GranularityDerivationService } from "../../domain/services/granularity-derivation-service.js";
9
+ import { Digest } from "../../domain/value-objects/digest.js";
8
10
  import { SignatureBlock } from "../../domain/value-objects/signature-block.js";
9
11
  import { ValidatorOutcome } from "../../domain/value-objects/validator-outcome.js";
10
12
  import type { AttestationDocument } from "../dto/attestation-document.js";
11
13
  import type { ProduceAttestationInput } from "../dto/produce-attestation-input.js";
12
14
  import type { AttestationRecordMapper } from "../mappers/attestation-record-mapper.js";
15
+ import type { AcBoundAllowlistPort } from "../ports/ac-bound-allowlist-port.js";
13
16
  import type { AttestationRepositoryPort } from "../ports/attestation-repository-port.js";
14
17
  import type { GateResultSourcePort } from "../ports/gate-result-source-port.js";
15
- import type { SourceDigesterPort } from "../ports/source-digester-port.js";
16
18
  import type { MatrixSourcePort } from "../ports/matrix-source-port.js";
17
- import type { AcBoundAllowlistPort } from "../ports/ac-bound-allowlist-port.js";
19
+ import type { SourceDigesterPort } from "../ports/source-digester-port.js";
20
+ import type { WorldSnapshotRootProvider } from "../ports/world-snapshot-root-provider.js";
18
21
 
19
- const SCHEMA_VERSION = "phasegate-attestation/v1";
20
- const PREDICATE_TYPE = "https://phasegate.dev/attestation/gate-run/v1";
22
+ const V1_SCHEMA_VERSION = "phasegate-attestation/v1";
23
+ const V1_PREDICATE_TYPE = "https://phasegate.dev/attestation/gate-run/v1";
24
+ const V2_SCHEMA_VERSION = "phasegate-attestation/v2";
25
+ const V2_PREDICATE_TYPE = "https://phasegate.dev/attestation/gate-run/v2";
21
26
  const DEFAULT_INPUT_SOURCES: readonly string[] = Object.freeze([
22
27
  "phasegate.config.json",
23
28
  ".harness/requirement-test-matrix.json",
@@ -46,11 +51,14 @@ export interface ProduceAttestationDeps {
46
51
  readonly acBoundScopeService?: AcBoundScopeService;
47
52
  /** H16-03: matrix 供給元パス(inputSourcePaths のうち matrix にあたるもの。既定は 2 番目の source)。 */
48
53
  readonly matrixFilePath?: string;
54
+ /** WI-306: 配線時はv2、未配線時は既存v1を生成する。 */
55
+ readonly worldSnapshotRootProvider?: WorldSnapshotRootProvider;
49
56
  }
50
57
 
51
58
  export interface ProduceAttestationResult {
52
59
  readonly document: AttestationDocument | null;
53
60
  readonly exitCode: 0 | 1 | 2;
61
+ readonly error?: string;
54
62
  }
55
63
 
56
64
  /**
@@ -77,6 +85,20 @@ export class ProduceAttestationUseCase {
77
85
  return { document: null, exitCode: 1 };
78
86
  }
79
87
 
88
+ // 3b. World root providerはv2 opt-in。失敗や不正digestをv1へdowngradeしない。
89
+ let worldSnapshotRoot: Digest | undefined;
90
+ if (this.deps.worldSnapshotRootProvider) {
91
+ try {
92
+ worldSnapshotRoot = Digest.create(await this.deps.worldSnapshotRootProvider.getWorldSnapshotRoot());
93
+ } catch (error) {
94
+ return {
95
+ document: null,
96
+ exitCode: 2,
97
+ error: `cannot obtain worldSnapshotRoot: ${error instanceof Error ? error.message : String(error)}`,
98
+ };
99
+ }
100
+ }
101
+
80
102
  // 4. inputs.sources 構築(config / matrix の sha256 + git commit SHA)と inputDigest 算出
81
103
  const sources = await this.buildSources();
82
104
  const preInputRecord = this.assembleRecord({
@@ -88,6 +110,7 @@ export class ProduceAttestationUseCase {
88
110
  producer: `phasegate-attestation/${this.deps.pkgVersion}`,
89
111
  gitCommit: null,
90
112
  acBoundScope: [],
113
+ worldSnapshotRoot,
91
114
  });
92
115
  const inputDigest = preInputRecord.computeInputDigest(this.deps.hasher);
93
116
 
@@ -110,6 +133,7 @@ export class ProduceAttestationUseCase {
110
133
  producer: `phasegate-attestation/${this.deps.pkgVersion}`,
111
134
  gitCommit,
112
135
  acBoundScope,
136
+ worldSnapshotRoot,
113
137
  });
114
138
  const sealed = record.seal(this.deps.hasher);
115
139
 
@@ -130,11 +154,12 @@ export class ProduceAttestationUseCase {
130
154
  producer: string;
131
155
  gitCommit: string | null;
132
156
  acBoundScope: readonly string[];
157
+ worldSnapshotRoot?: Digest;
133
158
  }): AttestationRecord {
134
159
  const granularity = this.deps.granularityService.derive(args.validatorSet);
135
160
  return AttestationRecord.create({
136
- schemaVersion: SCHEMA_VERSION,
137
- predicateType: PREDICATE_TYPE,
161
+ schemaVersion: args.worldSnapshotRoot ? V2_SCHEMA_VERSION : V1_SCHEMA_VERSION,
162
+ predicateType: args.worldSnapshotRoot ? V2_PREDICATE_TYPE : V1_PREDICATE_TYPE,
138
163
  subject: {
139
164
  command: "phasegate:ci-check",
140
165
  gateResult: args.gateResult,
@@ -154,6 +179,7 @@ export class ProduceAttestationUseCase {
154
179
  // 仮の unsigned-poc block(seal 前)。seal が正しい digest で置換する。
155
180
  signature: SignatureBlock.unsignedPoc(args.inputDigest),
156
181
  acBoundScope: args.acBoundScope,
182
+ ...(args.worldSnapshotRoot ? { worldSnapshotRoot: args.worldSnapshotRoot } : {}),
157
183
  });
158
184
  }
159
185
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @layer infrastructure
3
3
  * @unit attestation
4
+ * @work-item-id WI-306
4
5
  *
5
6
  * Composition Root — attestation Unit の依存性組み立て。
6
7
  * createAttestationModule() は adapters + usecases + handlers を組み立て、
@@ -11,6 +12,7 @@ import { execFile } from "node:child_process";
11
12
  import { promisify } from "node:util";
12
13
  import { AttestationRecordMapper } from "./application/mappers/attestation-record-mapper.js";
13
14
  import type { Sha256Capability } from "./application/ports/sha256-capability.js";
15
+ import type { WorldSnapshotRootProvider } from "./application/ports/world-snapshot-root-provider.js";
14
16
  import { ProduceAttestationUseCase } from "./application/usecases/produce-attestation-usecase.js";
15
17
  import { VerifyAttestationUseCase } from "./application/usecases/verify-attestation-usecase.js";
16
18
  import { AcBoundScopeService } from "./domain/services/ac-bound-scope-service.js";
@@ -41,6 +43,8 @@ export interface AttestationModuleOptions {
41
43
  readonly mainTsPath?: string;
42
44
  /** metadata.producedAt 用クロックのオーバーライド(テスト用)。 */
43
45
  readonly clock?: () => Date;
46
+ /** WI-306: 配線時はv2 recordへplain World corpus rootを注入する。 */
47
+ readonly worldSnapshotRootProvider?: WorldSnapshotRootProvider;
44
48
  }
45
49
 
46
50
  /**
@@ -87,6 +91,7 @@ export function createAttestationModule(rootDir: string, options?: AttestationMo
87
91
  matrixSource,
88
92
  allowlist,
89
93
  acBoundScopeService,
94
+ worldSnapshotRootProvider: options?.worldSnapshotRootProvider,
90
95
  });
91
96
  const verifyUseCase = new VerifyAttestationUseCase({
92
97
  repository,
@@ -1,5 +1,6 @@
1
1
  // @unit attestation
2
2
  // @layer domain
3
+ // @work-item-id WI-306
3
4
 
4
5
  import type { ContentHasherPort } from "../ports/content-hasher-port.js";
5
6
  import { GranularityDerivationService } from "../services/granularity-derivation-service.js";
@@ -47,6 +48,8 @@ export interface AttestationRecordProps {
47
48
  * 省略時は [] として扱う(additive-safe)。
48
49
  */
49
50
  readonly acBoundScope?: readonly string[];
51
+ /** v2だけが持つ実行時World corpus root。 */
52
+ readonly worldSnapshotRoot?: Digest;
50
53
  }
51
54
 
52
55
  /**
@@ -94,6 +97,7 @@ export class AttestationRecord {
94
97
  readonly metadata: MetadataSection;
95
98
  readonly signature: SignatureBlock;
96
99
  readonly acBoundScope: readonly string[];
100
+ readonly worldSnapshotRoot: Digest | null;
97
101
 
98
102
  private constructor(props: AttestationRecordProps) {
99
103
  this.schemaVersion = props.schemaVersion;
@@ -104,10 +108,12 @@ export class AttestationRecord {
104
108
  this.metadata = props.metadata;
105
109
  this.signature = props.signature;
106
110
  this.acBoundScope = Object.freeze([...(props.acBoundScope ?? [])]);
111
+ this.worldSnapshotRoot = props.worldSnapshotRoot ?? null;
107
112
  Object.freeze(this);
108
113
  }
109
114
 
110
115
  static create(props: AttestationRecordProps): AttestationRecord {
116
+ AttestationRecord.assertVersionContract(props);
111
117
  // INV-1: gateResult == "pass" iff validatorSet.every(passed || skipped)
112
118
  const allGreen = props.subject.validatorSet.every((o) => o.isGreen());
113
119
  const expectedGateResult: GateResult = allGreen ? "pass" : "fail";
@@ -149,6 +155,22 @@ export class AttestationRecord {
149
155
  return new AttestationRecord(props);
150
156
  }
151
157
 
158
+ private static assertVersionContract(props: AttestationRecordProps): void {
159
+ const v1 =
160
+ props.schemaVersion === "phasegate-attestation/v1" &&
161
+ props.predicateType === "https://phasegate.dev/attestation/gate-run/v1" &&
162
+ props.worldSnapshotRoot === undefined;
163
+ const v2 =
164
+ props.schemaVersion === "phasegate-attestation/v2" &&
165
+ props.predicateType === "https://phasegate.dev/attestation/gate-run/v2" &&
166
+ props.worldSnapshotRoot !== undefined;
167
+ if (!v1 && !v2) {
168
+ throw new AttestationInvariantError(
169
+ "version contract violated: schema, predicate, and worldSnapshotRoot disagree",
170
+ );
171
+ }
172
+ }
173
+
152
174
  gateResult(): GateResult {
153
175
  return this.subject.gateResult;
154
176
  }
@@ -165,10 +187,9 @@ export class AttestationRecord {
165
187
 
166
188
  /**
167
189
  * §1.4.1 step1-3: signature ブロック全体と volatile metadata(producedAt/gitCommit)を
168
- * 除去した plain object を返す(producer は決定論的なので残す)。
169
190
  */
170
191
  toCanonicalPayload(): Record<string, unknown> {
171
- return {
192
+ const payload: Record<string, unknown> = {
172
193
  schemaVersion: this.schemaVersion,
173
194
  predicateType: this.predicateType,
174
195
  subject: {
@@ -199,6 +220,10 @@ export class AttestationRecord {
199
220
  producer: this.metadata.producer,
200
221
  },
201
222
  };
223
+ if (this.worldSnapshotRoot !== null) {
224
+ payload.worldSnapshotRoot = this.worldSnapshotRoot.value;
225
+ }
226
+ return payload;
202
227
  }
203
228
 
204
229
  /**
@@ -222,6 +247,7 @@ export class AttestationRecord {
222
247
  metadata: this.metadata,
223
248
  signature: SignatureBlock.unsignedPoc(digest),
224
249
  acBoundScope: this.acBoundScope,
250
+ ...(this.worldSnapshotRoot === null ? {} : { worldSnapshotRoot: this.worldSnapshotRoot }),
225
251
  });
226
252
  }
227
253
 
@@ -247,6 +273,15 @@ export class AttestationRecord {
247
273
  if (!this.granularity.traceability.equals(other.granularity.traceability)) return false;
248
274
  if (this.acBoundScope.length !== other.acBoundScope.length) return false;
249
275
  if (!this.acBoundScope.every((s, i) => s === other.acBoundScope[i])) return false;
276
+ if (this.worldSnapshotRoot === null && other.worldSnapshotRoot !== null) return false;
277
+ if (this.worldSnapshotRoot !== null && other.worldSnapshotRoot === null) return false;
278
+ if (
279
+ this.worldSnapshotRoot !== null &&
280
+ other.worldSnapshotRoot !== null &&
281
+ !this.worldSnapshotRoot.equals(other.worldSnapshotRoot)
282
+ ) {
283
+ return false;
284
+ }
250
285
  if (!this.signature.equals(other.signature)) return false;
251
286
  return true;
252
287
  }
@@ -1,15 +1,21 @@
1
1
  // @layer infrastructure
2
2
  // @unit attestation
3
+ // @work-item-id WI-306
3
4
  // index.ts — attestation Unit の公開バレルエクスポート
4
5
 
5
6
  // Public DTO types
6
- export type { AttestationDocument } from "./application/dto/attestation-document.js";
7
+ export type {
8
+ AttestationDocument,
9
+ AttestationDocumentV1,
10
+ AttestationDocumentV2,
11
+ } from "./application/dto/attestation-document.js";
7
12
  export type { VerifyAttestationOutput } from "./application/dto/verify-attestation-output.js";
8
13
  export {
9
14
  hashUtf8,
10
15
  type Sha256Capability,
11
16
  type Sha256DigestString,
12
17
  } from "./application/ports/sha256-capability.js";
18
+ export type { WorldSnapshotRootProvider } from "./application/ports/world-snapshot-root-provider.js";
13
19
  export type { AttestationModule, AttestationModuleOptions } from "./composition-root.js";
14
20
  // Composition Root
15
21
  export { createAttestationModule, createSha256Capability } from "./composition-root.js";
@@ -1,5 +1,6 @@
1
1
  // @unit attestation
2
2
  // @layer presentation
3
+ // @work-item-id WI-306
3
4
 
4
5
  import type { ProduceAttestationInput } from "../../application/dto/produce-attestation-input.js";
5
6
  import type { ProduceAttestationUseCase } from "../../application/usecases/produce-attestation-usecase.js";
@@ -46,8 +47,10 @@ export class AttestHandler {
46
47
  const result = await this.useCase.execute(input);
47
48
 
48
49
  if (result.exitCode === 2) {
49
- // 唯一の usecase 由来 2 は mode === "signed"。
50
- return { output: 'Error: --mode "signed" is not yet implemented (only unsigned-poc is supported)', exitCode: 2 };
50
+ const output = result.error
51
+ ? `Error: ${result.error}`
52
+ : 'Error: --mode "signed" is not yet implemented (only unsigned-poc is supported)';
53
+ return { output, exitCode: 2 };
51
54
  }
52
55
 
53
56
  if (result.exitCode === 1) {
@@ -7,6 +7,10 @@
7
7
  * @work-item-id WI-258
8
8
  * @work-item-id WI-259
9
9
  * @work-item-id WI-268
10
+ * @work-item-id WI-300
11
+ * @work-item-id WI-301
12
+ * @work-item-id WI-302
13
+ * @work-item-id WI-320
10
14
  */
11
15
  import type { HarnessConfigV2 } from "../../domain/harness-config.js";
12
16
 
@@ -23,6 +27,7 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
23
27
  "ac-bound-coverage": "L3-005",
24
28
  "injection-scan": "L3-006",
25
29
  "coverage-attestation-verification": "L3-007",
30
+ "world-constraint-rederivation": "L3-008",
26
31
  },
27
32
  /^L3-\d{3}$/,
28
33
  );
@@ -50,7 +55,10 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
50
55
  return {
51
56
  project: {
52
57
  preset: resolvedConfig.project.preset,
53
- languages: resolvedConfig.project.languages ?? ["typescript"],
58
+ // WI-320 (github#39): 未宣言時に ["typescript"] を注入せず undefined のまま渡す。
59
+ // HarnessConfigValidatorConfigAdapter.getProjectLanguages() が未宣言時のみ
60
+ // ファイルシステム検出(WI-319)にフォールバックできるようにするため。
61
+ ...(resolvedConfig.project.languages === undefined ? {} : { languages: resolvedConfig.project.languages }),
54
62
  },
55
63
  paths: {
56
64
  designDocs: resolvedConfig.paths.designDocs,
@@ -60,7 +68,10 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
60
68
  // WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating) を default-ON でリストに含める。
61
69
  L2: {
62
70
  enabled: resolvedConfig.layers.L2.enabled,
63
- validators: ["L2-001", "L2-002", "L2-003", "L2-013", "L2-014", "L2-015", "L2-016"],
71
+ validators:
72
+ resolvedConfig.world?.enabled === true
73
+ ? ["L2-001", "L2-002", "L2-003", "L2-013", "L2-014", "L2-015", "L2-016", "L2-017"]
74
+ : ["L2-001", "L2-002", "L2-003", "L2-013", "L2-014", "L2-015", "L2-016"],
64
75
  },
65
76
  L3: {
66
77
  enabled: resolvedConfig.layers.L3.enabled,
@@ -68,13 +79,28 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
68
79
  // WI-268 / ADR-030 §Decision.1・§Decision.3.② 第2段: L3-007 (coverage-attestation-verification)
69
80
  // は fail-closed default-ON。いずれも fallback 判定の後に force-include し、normalize 結果でも
70
81
  // fallback でも常に含める(L3-007 は fail-closed だが現 corpus は実参照 0 件ゆえ緑)。
71
- validators: includeValidator(
72
- includeValidator(
73
- l3Validators.length > 0 ? l3Validators : ["L3-001", "L3-002", "L3-003", "L3-004"],
74
- "L3-006",
75
- ),
76
- "L3-007",
77
- ),
82
+ validators:
83
+ resolvedConfig.world?.enabled === true
84
+ ? includeValidator(
85
+ includeValidator(
86
+ includeValidator(
87
+ l3Validators.length > 0 ? l3Validators : ["L3-001", "L3-002", "L3-003", "L3-004"],
88
+ "L3-006",
89
+ ),
90
+ "L3-007",
91
+ ),
92
+ "L3-008",
93
+ )
94
+ : excludeValidator(
95
+ includeValidator(
96
+ includeValidator(
97
+ l3Validators.length > 0 ? l3Validators : ["L3-001", "L3-002", "L3-003", "L3-004"],
98
+ "L3-006",
99
+ ),
100
+ "L3-007",
101
+ ),
102
+ "L3-008",
103
+ ),
78
104
  coverageThreshold: resolvedConfig.layers.L3.coverageThreshold,
79
105
  requirementMatrixPath: resolvedConfig.layers.L3.requirementMatrixPath,
80
106
  // WI-227 / H16-03: L3-005 のスコープ(additive-safe。未設定は [])
@@ -96,6 +122,7 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
96
122
  validate: {
97
123
  failOnWarning: resolvedConfig.validate.failOnWarning,
98
124
  },
125
+ ...(resolvedConfig.world === undefined ? {} : { world: structuredClone(resolvedConfig.world) }),
99
126
  };
100
127
  }
101
128
 
@@ -110,6 +137,10 @@ function includeValidator(validators: readonly string[], validatorId: string): r
110
137
  return validators.includes(validatorId) ? validators : [...validators, validatorId];
111
138
  }
112
139
 
140
+ function excludeValidator(validators: readonly string[], validatorId: string): readonly string[] {
141
+ return validators.filter((candidate) => candidate !== validatorId);
142
+ }
143
+
113
144
  function normalizeValidators(
114
145
  validators: readonly string[],
115
146
  aliases: Readonly<Record<string, string>>,
@@ -0,0 +1,15 @@
1
+ // @unit config-foundation
2
+ // @layer application
3
+ // @work-item-id WI-300
4
+
5
+ import type { HarnessConfigV2 } from "../../domain/harness-config.js";
6
+ import {
7
+ WORLD_CONFIG_DEFAULTS,
8
+ WorldConfig,
9
+ type WorldConfigDocument,
10
+ } from "../../domain/value-objects/world-config.js";
11
+
12
+ export function toWorldModelConfig(resolvedConfig: HarnessConfigV2 | undefined): WorldConfigDocument | undefined {
13
+ if (!resolvedConfig) return undefined;
14
+ return WorldConfig.create(resolvedConfig.world ?? WORLD_CONFIG_DEFAULTS).toDocument();
15
+ }