phasegate 0.254.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 +22 -0
- package/README.ja.md +6 -3
- package/README.md +6 -3
- package/docs/contracts/attestation-v2.schema.json +110 -0
- package/docs/guide/cli-reference.md +12 -1
- 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/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 +5 -0
- package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
- package/scripts/harness/attestation/index.ts +7 -1
- 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/integrations/pre-commit.ts +169 -27
- package/scripts/harness/main.ts +174 -130
- package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
- package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
- package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
- package/scripts/harness/traceability-model/composition-root.ts +5 -0
- package/scripts/harness/traceability-model/index.ts +9 -0
- package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
- 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-resolved-config-input.ts +92 -27
- 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/usecases/derive-world-obligations-use-case.ts +3 -1
- package/scripts/harness/world-model/composition-root.ts +62 -33
- package/scripts/harness/world-model/index.ts +11 -0
- package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +48 -13
- package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +6 -4
- package/scripts/harness/world-model/presentation/cli/world-derive-command-handler.ts +6 -2
|
@@ -4,36 +4,36 @@
|
|
|
4
4
|
* @work-item-id WI-012
|
|
5
5
|
* @work-item-id WI-212
|
|
6
6
|
* @work-item-id WI-219
|
|
7
|
+
* @work-item-id WI-300
|
|
7
8
|
*/
|
|
8
|
-
import { ConfigFoundationDomainError } from
|
|
9
|
-
import { ConfigValidationError } from
|
|
10
|
-
import { UnsupportedFeatureError } from
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import type {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import type {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
export type
|
|
33
|
-
export type
|
|
34
|
-
export type PlanningModeValue = 'interactive' | 'embedded-qa' | 'manual';
|
|
35
|
-
export type ModelDelegationPolicy = 'delegate-sonnet' | 'none';
|
|
9
|
+
import { ConfigFoundationDomainError } from "./errors/config-foundation-domain-error.js";
|
|
10
|
+
import { ConfigValidationError } from "./errors/config-validation-error.js";
|
|
11
|
+
import { UnsupportedFeatureError } from "./errors/unsupported-feature-error.js";
|
|
12
|
+
import type { ArchitectureConfigDocument, ArchitectureConfigSource } from "./value-objects/architecture-config.js";
|
|
13
|
+
import type { FeatureName, FeatureNameValue } from "./value-objects/feature-name.js";
|
|
14
|
+
import { HarnessesConfig } from "./value-objects/harnesses-config.js";
|
|
15
|
+
import type { L1Config } from "./value-objects/l1-config.js";
|
|
16
|
+
import type { L2Config } from "./value-objects/l2-config.js";
|
|
17
|
+
import type { L3Config } from "./value-objects/l3-config.js";
|
|
18
|
+
import type { L4Config } from "./value-objects/l4-config.js";
|
|
19
|
+
import { LayersConfig } from "./value-objects/layers-config.js";
|
|
20
|
+
import { PathsConfig } from "./value-objects/paths-config.js";
|
|
21
|
+
import type { PhaseDependenciesPresetId } from "./value-objects/phase-dependencies-config.js";
|
|
22
|
+
import { PhaseDependenciesConfig } from "./value-objects/phase-dependencies-config.js";
|
|
23
|
+
import { PlanningModeConfig } from "./value-objects/planning-mode-config.js";
|
|
24
|
+
import { ProjectConfig } from "./value-objects/project-config.js";
|
|
25
|
+
import { QuickModeConfig } from "./value-objects/quick-mode-config.js";
|
|
26
|
+
import { ReportingConfig } from "./value-objects/reporting-config.js";
|
|
27
|
+
import { ValidateConfig } from "./value-objects/validate-config.js";
|
|
28
|
+
import type { WorldConfigDocument, WorldConfigSourceDocument } from "./value-objects/world-config.js";
|
|
29
|
+
import { WORLD_CONFIG_DEFAULTS, WorldConfig } from "./value-objects/world-config.js";
|
|
30
|
+
|
|
31
|
+
export type LayerId = "L1" | "L2" | "L3" | "L4";
|
|
32
|
+
export type PresetId = "minimal" | "standard" | "strict";
|
|
33
|
+
export type PlanningModeValue = "interactive" | "embedded-qa" | "manual";
|
|
34
|
+
export type ModelDelegationPolicy = "delegate-sonnet" | "none";
|
|
36
35
|
export type { PhaseDependenciesPresetId };
|
|
36
|
+
|
|
37
37
|
type DeepPartial<T> = {
|
|
38
38
|
[K in keyof T]?: T[K] extends Array<infer TItem>
|
|
39
39
|
? Array<DeepPartial<TItem>>
|
|
@@ -48,19 +48,20 @@ export interface HarnessConfigSourceDocument {
|
|
|
48
48
|
preset: PresetId;
|
|
49
49
|
languages?: string[];
|
|
50
50
|
};
|
|
51
|
-
layers: DeepPartial<HarnessConfigResolvedDocument[
|
|
52
|
-
quickMode: Partial<HarnessConfigResolvedDocument[
|
|
53
|
-
phaseDependencies: HarnessConfigResolvedDocument[
|
|
54
|
-
planningMode: HarnessConfigResolvedDocument[
|
|
55
|
-
harnesses: Partial<HarnessConfigResolvedDocument[
|
|
56
|
-
paths: HarnessConfigResolvedDocument[
|
|
57
|
-
reporting: HarnessConfigResolvedDocument[
|
|
58
|
-
ci?: HarnessConfigResolvedDocument[
|
|
59
|
-
validate?: HarnessConfigResolvedDocument[
|
|
60
|
-
preCommit?: Partial<HarnessConfigResolvedDocument[
|
|
61
|
-
modelRouting?: HarnessConfigResolvedDocument[
|
|
62
|
-
phase2Extensions?: HarnessConfigResolvedDocument[
|
|
51
|
+
layers: DeepPartial<HarnessConfigResolvedDocument["layers"]>;
|
|
52
|
+
quickMode: Partial<HarnessConfigResolvedDocument["quickMode"]>;
|
|
53
|
+
phaseDependencies: HarnessConfigResolvedDocument["phaseDependencies"];
|
|
54
|
+
planningMode: HarnessConfigResolvedDocument["planningMode"];
|
|
55
|
+
harnesses: Partial<HarnessConfigResolvedDocument["harnesses"]>;
|
|
56
|
+
paths: HarnessConfigResolvedDocument["paths"];
|
|
57
|
+
reporting: HarnessConfigResolvedDocument["reporting"];
|
|
58
|
+
ci?: HarnessConfigResolvedDocument["ci"];
|
|
59
|
+
validate?: HarnessConfigResolvedDocument["validate"];
|
|
60
|
+
preCommit?: Partial<HarnessConfigResolvedDocument["preCommit"]>;
|
|
61
|
+
modelRouting?: HarnessConfigResolvedDocument["modelRouting"];
|
|
62
|
+
phase2Extensions?: HarnessConfigResolvedDocument["phase2Extensions"];
|
|
63
63
|
architecture?: ArchitectureConfigSource;
|
|
64
|
+
world?: WorldConfigSourceDocument;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
export interface HarnessConfigResolvedDocument {
|
|
@@ -142,11 +143,12 @@ export interface HarnessConfigResolvedDocument {
|
|
|
142
143
|
documentPattern: string;
|
|
143
144
|
daysThreshold: number;
|
|
144
145
|
commitCountThreshold: number;
|
|
145
|
-
evaluationMode:
|
|
146
|
+
evaluationMode: "or" | "and";
|
|
146
147
|
enabled?: boolean;
|
|
147
148
|
}>;
|
|
148
149
|
};
|
|
149
150
|
architecture?: ArchitectureConfigDocument;
|
|
151
|
+
world?: WorldConfigDocument;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
export type HarnessConfigV2 = HarnessConfigResolvedDocument;
|
|
@@ -159,7 +161,7 @@ export interface HarnessConfigReconstitutionProps {
|
|
|
159
161
|
}
|
|
160
162
|
|
|
161
163
|
export interface FeatureToggled {
|
|
162
|
-
type:
|
|
164
|
+
type: "FeatureToggled";
|
|
163
165
|
occurredAt: Date;
|
|
164
166
|
projectName: string;
|
|
165
167
|
featureName: FeatureNameValue | string;
|
|
@@ -168,7 +170,7 @@ export interface FeatureToggled {
|
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
export interface PresetApplied {
|
|
171
|
-
type:
|
|
173
|
+
type: "PresetApplied";
|
|
172
174
|
occurredAt: Date;
|
|
173
175
|
projectName: string;
|
|
174
176
|
preset: PresetId;
|
|
@@ -178,23 +180,23 @@ export interface PresetApplied {
|
|
|
178
180
|
export type DomainEvent = FeatureToggled | PresetApplied;
|
|
179
181
|
|
|
180
182
|
const SUPPORTED_FEATURE_NAMES = [
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
"agentLessonCollection",
|
|
184
|
+
"cascadeUpdate",
|
|
185
|
+
"bundleSizeLimit",
|
|
186
|
+
"deadCodeGC",
|
|
185
187
|
] as const satisfies readonly FeatureNameValue[];
|
|
186
188
|
|
|
187
189
|
export class UnknownLayerError extends ConfigFoundationDomainError {
|
|
188
190
|
constructor(layerId: string) {
|
|
189
|
-
super(`未知のレイヤーです: ${layerId} [L1-006]`,
|
|
190
|
-
this.name =
|
|
191
|
+
super(`未知のレイヤーです: ${layerId} [L1-006]`, "L1-006");
|
|
192
|
+
this.name = "UnknownLayerError";
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
export class FeatureActivationRuleError extends ConfigFoundationDomainError {
|
|
195
197
|
constructor(message: string) {
|
|
196
|
-
super(`${message} [L1-005]`,
|
|
197
|
-
this.name =
|
|
198
|
+
super(`${message} [L1-005]`, "L1-005");
|
|
199
|
+
this.name = "FeatureActivationRuleError";
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
|
|
@@ -207,11 +209,8 @@ function deepClone<T>(value: T): T {
|
|
|
207
209
|
return value.map((item) => deepClone(item)) as T;
|
|
208
210
|
}
|
|
209
211
|
|
|
210
|
-
if (value !== null && typeof value ===
|
|
211
|
-
const clonedEntries = Object.entries(value).map(([key, entryValue]) => [
|
|
212
|
-
key,
|
|
213
|
-
deepClone(entryValue),
|
|
214
|
-
]);
|
|
212
|
+
if (value !== null && typeof value === "object") {
|
|
213
|
+
const clonedEntries = Object.entries(value).map(([key, entryValue]) => [key, deepClone(entryValue)]);
|
|
215
214
|
|
|
216
215
|
return Object.fromEntries(clonedEntries) as T;
|
|
217
216
|
}
|
|
@@ -226,7 +225,7 @@ function createFeatureToggledEvent(
|
|
|
226
225
|
currentState: boolean,
|
|
227
226
|
): FeatureToggled {
|
|
228
227
|
return Object.freeze({
|
|
229
|
-
type:
|
|
228
|
+
type: "FeatureToggled",
|
|
230
229
|
occurredAt: new Date(),
|
|
231
230
|
projectName,
|
|
232
231
|
featureName,
|
|
@@ -240,14 +239,14 @@ function assertSupportedFeature(name: FeatureName): FeatureNameValue {
|
|
|
240
239
|
|
|
241
240
|
if (!SUPPORTED_FEATURE_NAMES.includes(raw as FeatureNameValue)) {
|
|
242
241
|
throw new UnsupportedFeatureError(
|
|
243
|
-
`機能名 "${raw}" は利用できません。利用可能: ${SUPPORTED_FEATURE_NAMES.join(
|
|
242
|
+
`機能名 "${raw}" は利用できません。利用可能: ${SUPPORTED_FEATURE_NAMES.join(", ")}`,
|
|
244
243
|
);
|
|
245
244
|
}
|
|
246
245
|
|
|
247
246
|
return raw as FeatureNameValue;
|
|
248
247
|
}
|
|
249
248
|
|
|
250
|
-
function toHarnessesDocument(harnesses: HarnessesConfig): HarnessConfigResolvedDocument[
|
|
249
|
+
function toHarnessesDocument(harnesses: HarnessesConfig): HarnessConfigResolvedDocument["harnesses"] {
|
|
251
250
|
return {
|
|
252
251
|
agentLessonCollection: harnesses.agentLessonCollection,
|
|
253
252
|
cascadeUpdate: harnesses.cascadeUpdate,
|
|
@@ -303,22 +302,17 @@ export class HarnessConfig {
|
|
|
303
302
|
const project = ProjectConfig.create(props.resolvedDocument.project);
|
|
304
303
|
const layers = LayersConfig.create(props.resolvedDocument.layers);
|
|
305
304
|
const quickMode = QuickModeConfig.create(props.resolvedDocument.quickMode);
|
|
306
|
-
const phaseDependencies = PhaseDependenciesConfig.create(
|
|
307
|
-
|
|
308
|
-
);
|
|
309
|
-
const planningMode = PlanningModeConfig.create(
|
|
310
|
-
props.resolvedDocument.planningMode,
|
|
311
|
-
);
|
|
305
|
+
const phaseDependencies = PhaseDependenciesConfig.create(props.resolvedDocument.phaseDependencies);
|
|
306
|
+
const planningMode = PlanningModeConfig.create(props.resolvedDocument.planningMode);
|
|
312
307
|
const harnesses = HarnessesConfig.create(props.resolvedDocument.harnesses);
|
|
313
308
|
const paths = PathsConfig.create(props.resolvedDocument.paths);
|
|
314
309
|
const reporting = ReportingConfig.create(props.resolvedDocument.reporting);
|
|
315
310
|
const validate = ValidateConfig.create(props.resolvedDocument.validate);
|
|
311
|
+
const world = WorldConfig.create(props.resolvedDocument.world ?? WORLD_CONFIG_DEFAULTS).toDocument();
|
|
316
312
|
|
|
317
|
-
if (
|
|
318
|
-
props.sourceDocument.project.preset !== props.resolvedDocument.project.preset
|
|
319
|
-
) {
|
|
313
|
+
if (props.sourceDocument.project.preset !== props.resolvedDocument.project.preset) {
|
|
320
314
|
throw new ConfigValidationError(
|
|
321
|
-
|
|
315
|
+
"sourceDocument.project.preset と resolvedDocument.project.preset は一致しなければなりません",
|
|
322
316
|
);
|
|
323
317
|
}
|
|
324
318
|
|
|
@@ -333,7 +327,7 @@ export class HarnessConfig {
|
|
|
333
327
|
reporting,
|
|
334
328
|
validate,
|
|
335
329
|
sourceDocument: props.sourceDocument,
|
|
336
|
-
resolvedDocument: props.resolvedDocument,
|
|
330
|
+
resolvedDocument: { ...props.resolvedDocument, world },
|
|
337
331
|
pendingEvents: props.pendingEvents ?? [],
|
|
338
332
|
});
|
|
339
333
|
}
|
|
@@ -355,14 +349,7 @@ export class HarnessConfig {
|
|
|
355
349
|
...this.resolvedDocument,
|
|
356
350
|
harnesses: toHarnessesDocument(nextHarnesses),
|
|
357
351
|
};
|
|
358
|
-
this.pendingEvents.push(
|
|
359
|
-
createFeatureToggledEvent(
|
|
360
|
-
this.project.name,
|
|
361
|
-
featureName,
|
|
362
|
-
previousState,
|
|
363
|
-
true,
|
|
364
|
-
),
|
|
365
|
-
);
|
|
352
|
+
this.pendingEvents.push(createFeatureToggledEvent(this.project.name, featureName, previousState, true));
|
|
366
353
|
}
|
|
367
354
|
|
|
368
355
|
disableFeature(name: FeatureName): void {
|
|
@@ -382,18 +369,11 @@ export class HarnessConfig {
|
|
|
382
369
|
...this.resolvedDocument,
|
|
383
370
|
harnesses: toHarnessesDocument(nextHarnesses),
|
|
384
371
|
};
|
|
385
|
-
this.pendingEvents.push(
|
|
386
|
-
createFeatureToggledEvent(
|
|
387
|
-
this.project.name,
|
|
388
|
-
featureName,
|
|
389
|
-
previousState,
|
|
390
|
-
false,
|
|
391
|
-
),
|
|
392
|
-
);
|
|
372
|
+
this.pendingEvents.push(createFeatureToggledEvent(this.project.name, featureName, previousState, false));
|
|
393
373
|
}
|
|
394
374
|
|
|
395
375
|
getLayerConfig(layerId: LayerId): L1Config | L2Config | L3Config | L4Config {
|
|
396
|
-
if (![
|
|
376
|
+
if (!["L1", "L2", "L3", "L4"].includes(layerId)) {
|
|
397
377
|
throw new UnknownLayerError(layerId);
|
|
398
378
|
}
|
|
399
379
|
|
|
@@ -2,43 +2,43 @@
|
|
|
2
2
|
* @layer domain
|
|
3
3
|
* @unit config-foundation
|
|
4
4
|
* @work-item-id WI-212
|
|
5
|
+
* @work-item-id WI-300
|
|
5
6
|
*/
|
|
6
|
-
import { ConfigFoundationDomainError } from
|
|
7
|
-
import type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from
|
|
11
|
-
import { HarnessesConfig } from '../value-objects/harnesses-config.js';
|
|
12
|
-
import type { FeatureToggle } from '../value-objects/feature-toggle.js';
|
|
7
|
+
import { ConfigFoundationDomainError } from "../errors/config-foundation-domain-error.js";
|
|
8
|
+
import type { HarnessConfigResolvedDocument, HarnessConfigSourceDocument } from "../harness-config.js";
|
|
9
|
+
import type { FeatureToggle } from "../value-objects/feature-toggle.js";
|
|
10
|
+
import { HarnessesConfig } from "../value-objects/harnesses-config.js";
|
|
11
|
+
import { WORLD_CONFIG_DEFAULTS, WorldConfig, type WorldConfigDocument } from "../value-objects/world-config.js";
|
|
13
12
|
|
|
14
13
|
export interface PresetDefinition {
|
|
15
|
-
layers: HarnessConfigResolvedDocument[
|
|
16
|
-
quickMode: HarnessConfigResolvedDocument[
|
|
17
|
-
phaseDependencies: HarnessConfigResolvedDocument[
|
|
18
|
-
planningMode: HarnessConfigResolvedDocument[
|
|
19
|
-
harnesses: HarnessConfigResolvedDocument[
|
|
20
|
-
paths: HarnessConfigResolvedDocument[
|
|
21
|
-
reporting: HarnessConfigResolvedDocument[
|
|
22
|
-
validate: HarnessConfigResolvedDocument[
|
|
23
|
-
preCommit?: HarnessConfigResolvedDocument[
|
|
14
|
+
layers: HarnessConfigResolvedDocument["layers"];
|
|
15
|
+
quickMode: HarnessConfigResolvedDocument["quickMode"];
|
|
16
|
+
phaseDependencies: HarnessConfigResolvedDocument["phaseDependencies"];
|
|
17
|
+
planningMode: HarnessConfigResolvedDocument["planningMode"];
|
|
18
|
+
harnesses: HarnessConfigResolvedDocument["harnesses"];
|
|
19
|
+
paths: HarnessConfigResolvedDocument["paths"];
|
|
20
|
+
reporting: HarnessConfigResolvedDocument["reporting"];
|
|
21
|
+
validate: HarnessConfigResolvedDocument["validate"];
|
|
22
|
+
preCommit?: HarnessConfigResolvedDocument["preCommit"];
|
|
23
|
+
world?: WorldConfigDocument;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export class InvalidPresetDefinitionError extends ConfigFoundationDomainError {
|
|
27
27
|
constructor(message: string) {
|
|
28
|
-
super(`${message} [L1-007]`,
|
|
29
|
-
this.name =
|
|
28
|
+
super(`${message} [L1-007]`, "L1-007");
|
|
29
|
+
this.name = "InvalidPresetDefinitionError";
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export class ConfigMergeError extends ConfigFoundationDomainError {
|
|
34
34
|
constructor(message: string) {
|
|
35
|
-
super(`${message} [L1-008]`,
|
|
36
|
-
this.name =
|
|
35
|
+
super(`${message} [L1-008]`, "L1-008");
|
|
36
|
+
this.name = "ConfigMergeError";
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
41
|
-
return value !== null && typeof value ===
|
|
41
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function deepClone<T>(value: T): T {
|
|
@@ -47,9 +47,7 @@ function deepClone<T>(value: T): T {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (isPlainObject(value)) {
|
|
50
|
-
return Object.fromEntries(
|
|
51
|
-
Object.entries(value).map(([key, entryValue]) => [key, deepClone(entryValue)]),
|
|
52
|
-
) as T;
|
|
50
|
+
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, deepClone(entryValue)])) as T;
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
return value;
|
|
@@ -74,10 +72,7 @@ function deepMerge<T>(baseValue: T, overrideValue: unknown, path: string): T {
|
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
const merged: Record<string, unknown> = {};
|
|
77
|
-
const keys = new Set([
|
|
78
|
-
...Object.keys(baseValue),
|
|
79
|
-
...Object.keys(overrideValue),
|
|
80
|
-
]);
|
|
75
|
+
const keys = new Set([...Object.keys(baseValue), ...Object.keys(overrideValue)]);
|
|
81
76
|
|
|
82
77
|
for (const key of keys) {
|
|
83
78
|
const nestedBaseValue = (baseValue as Record<string, unknown>)[key];
|
|
@@ -88,11 +83,7 @@ function deepMerge<T>(baseValue: T, overrideValue: unknown, path: string): T {
|
|
|
88
83
|
continue;
|
|
89
84
|
}
|
|
90
85
|
|
|
91
|
-
merged[key] = deepMerge(
|
|
92
|
-
nestedBaseValue,
|
|
93
|
-
nestedOverrideValue,
|
|
94
|
-
`${path}.${key}`,
|
|
95
|
-
);
|
|
86
|
+
merged[key] = deepMerge(nestedBaseValue, nestedOverrideValue, `${path}.${key}`);
|
|
96
87
|
}
|
|
97
88
|
|
|
98
89
|
return merged as T;
|
|
@@ -105,35 +96,26 @@ function deepMerge<T>(baseValue: T, overrideValue: unknown, path: string): T {
|
|
|
105
96
|
return deepClone(overrideValue as T);
|
|
106
97
|
}
|
|
107
98
|
|
|
108
|
-
function assertValidPresetDefinition(
|
|
109
|
-
presetDefinition: PresetDefinition,
|
|
110
|
-
): void {
|
|
99
|
+
function assertValidPresetDefinition(presetDefinition: PresetDefinition): void {
|
|
111
100
|
const requiredKeys: Array<keyof PresetDefinition> = [
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
101
|
+
"layers",
|
|
102
|
+
"quickMode",
|
|
103
|
+
"phaseDependencies",
|
|
104
|
+
"planningMode",
|
|
105
|
+
"harnesses",
|
|
106
|
+
"paths",
|
|
107
|
+
"reporting",
|
|
108
|
+
"validate",
|
|
120
109
|
];
|
|
121
110
|
|
|
122
111
|
for (const key of requiredKeys) {
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
(presetDefinition as unknown as Record<string, unknown>)[key] === undefined
|
|
126
|
-
) {
|
|
127
|
-
throw new InvalidPresetDefinitionError(
|
|
128
|
-
`presetDefinition.${key} は必須です`,
|
|
129
|
-
);
|
|
112
|
+
if (!(key in presetDefinition) || (presetDefinition as unknown as Record<string, unknown>)[key] === undefined) {
|
|
113
|
+
throw new InvalidPresetDefinitionError(`presetDefinition.${key} は必須です`);
|
|
130
114
|
}
|
|
131
115
|
}
|
|
132
116
|
}
|
|
133
117
|
|
|
134
|
-
function toHarnessesDocument(
|
|
135
|
-
harnesses: HarnessesConfig,
|
|
136
|
-
): HarnessConfigResolvedDocument['harnesses'] {
|
|
118
|
+
function toHarnessesDocument(harnesses: HarnessesConfig): HarnessConfigResolvedDocument["harnesses"] {
|
|
137
119
|
return {
|
|
138
120
|
agentLessonCollection: harnesses.agentLessonCollection,
|
|
139
121
|
cascadeUpdate: harnesses.cascadeUpdate,
|
|
@@ -149,49 +131,58 @@ export class PresetResolutionService {
|
|
|
149
131
|
): HarnessConfigResolvedDocument {
|
|
150
132
|
assertValidPresetDefinition(presetDefinition);
|
|
151
133
|
|
|
134
|
+
const layers = deepMerge(presetDefinition.layers, sourceDocument.layers, "layers");
|
|
135
|
+
const paths = deepMerge(presetDefinition.paths, sourceDocument.paths, "paths");
|
|
136
|
+
const world = deepMerge(presetDefinition.world ?? WORLD_CONFIG_DEFAULTS, sourceDocument.world, "world");
|
|
137
|
+
const explicitCorpus = sourceDocument.world?.corpus;
|
|
138
|
+
const explicitInputs = sourceDocument.world?.inputs;
|
|
139
|
+
const derivedProductRoot = paths.designDocs.endsWith("/construction")
|
|
140
|
+
? paths.designDocs.slice(0, -"/construction".length)
|
|
141
|
+
: paths.designDocs;
|
|
142
|
+
const resolvedWorld: WorldConfigDocument = {
|
|
143
|
+
...world,
|
|
144
|
+
corpus: {
|
|
145
|
+
...world.corpus,
|
|
146
|
+
productRoots:
|
|
147
|
+
explicitCorpus?.productRoots === undefined && !world.corpus.productRoots.includes(derivedProductRoot)
|
|
148
|
+
? [...world.corpus.productRoots, derivedProductRoot]
|
|
149
|
+
: world.corpus.productRoots,
|
|
150
|
+
inceptionRoots:
|
|
151
|
+
explicitCorpus?.inceptionRoots === undefined ? [paths.inceptionDocs] : world.corpus.inceptionRoots,
|
|
152
|
+
},
|
|
153
|
+
inputs: {
|
|
154
|
+
...world.inputs,
|
|
155
|
+
matrixPath:
|
|
156
|
+
explicitInputs?.matrixPath === undefined
|
|
157
|
+
? (layers.L3.requirementMatrixPath ?? world.inputs.matrixPath)
|
|
158
|
+
: world.inputs.matrixPath,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
152
162
|
return {
|
|
153
163
|
project: {
|
|
154
164
|
name: sourceDocument.project.name,
|
|
155
165
|
preset: sourceDocument.project.preset,
|
|
156
|
-
languages: sourceDocument.project.languages ?? [
|
|
166
|
+
languages: sourceDocument.project.languages ?? ["typescript"],
|
|
157
167
|
},
|
|
158
|
-
layers
|
|
159
|
-
quickMode: deepMerge(
|
|
160
|
-
presetDefinition.quickMode,
|
|
161
|
-
sourceDocument.quickMode,
|
|
162
|
-
'quickMode',
|
|
163
|
-
),
|
|
168
|
+
layers,
|
|
169
|
+
quickMode: deepMerge(presetDefinition.quickMode, sourceDocument.quickMode, "quickMode"),
|
|
164
170
|
phaseDependencies: deepMerge(
|
|
165
171
|
presetDefinition.phaseDependencies,
|
|
166
172
|
sourceDocument.phaseDependencies,
|
|
167
|
-
|
|
168
|
-
),
|
|
169
|
-
planningMode: deepMerge(
|
|
170
|
-
presetDefinition.planningMode,
|
|
171
|
-
sourceDocument.planningMode,
|
|
172
|
-
'planningMode',
|
|
173
|
-
),
|
|
174
|
-
harnesses: deepMerge(
|
|
175
|
-
presetDefinition.harnesses,
|
|
176
|
-
sourceDocument.harnesses,
|
|
177
|
-
'harnesses',
|
|
178
|
-
),
|
|
179
|
-
paths: deepMerge(presetDefinition.paths, sourceDocument.paths, 'paths'),
|
|
180
|
-
reporting: deepMerge(
|
|
181
|
-
presetDefinition.reporting,
|
|
182
|
-
sourceDocument.reporting,
|
|
183
|
-
'reporting',
|
|
184
|
-
),
|
|
185
|
-
validate: deepMerge(
|
|
186
|
-
presetDefinition.validate,
|
|
187
|
-
sourceDocument.validate,
|
|
188
|
-
'validate',
|
|
173
|
+
"phaseDependencies",
|
|
189
174
|
),
|
|
175
|
+
planningMode: deepMerge(presetDefinition.planningMode, sourceDocument.planningMode, "planningMode"),
|
|
176
|
+
harnesses: deepMerge(presetDefinition.harnesses, sourceDocument.harnesses, "harnesses"),
|
|
177
|
+
paths,
|
|
178
|
+
reporting: deepMerge(presetDefinition.reporting, sourceDocument.reporting, "reporting"),
|
|
179
|
+
validate: deepMerge(presetDefinition.validate, sourceDocument.validate, "validate"),
|
|
190
180
|
preCommit: deepMerge(
|
|
191
|
-
presetDefinition.preCommit ?? { implementationExtensions: [
|
|
181
|
+
presetDefinition.preCommit ?? { implementationExtensions: [".ts"] },
|
|
192
182
|
sourceDocument.preCommit,
|
|
193
|
-
|
|
183
|
+
"preCommit",
|
|
194
184
|
),
|
|
185
|
+
world: WorldConfig.create(resolvedWorld).toDocument(),
|
|
195
186
|
};
|
|
196
187
|
}
|
|
197
188
|
|
|
@@ -200,9 +191,7 @@ export class PresetResolutionService {
|
|
|
200
191
|
override: FeatureToggle,
|
|
201
192
|
): HarnessConfigResolvedDocument {
|
|
202
193
|
const harnesses = HarnessesConfig.create(document.harnesses);
|
|
203
|
-
const nextHarnesses = override.enabled
|
|
204
|
-
? harnesses.enable(override.name)
|
|
205
|
-
: harnesses.disable(override.name);
|
|
194
|
+
const nextHarnesses = override.enabled ? harnesses.enable(override.name) : harnesses.disable(override.name);
|
|
206
195
|
|
|
207
196
|
return {
|
|
208
197
|
...deepClone(document),
|