project-tiny-context-harness 0.8.16 → 0.8.17
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/README.md +31 -16
- package/assets/README.md +31 -16
- package/assets/README.zh-CN.md +29 -14
- package/assets/context_templates/screen-contract.md +16 -0
- package/assets/skills/context_development_engineer/SKILL.md +16 -30
- package/assets/skills/context_development_engineer/references/engineering-design-reasoning.md +93 -0
- package/assets/skills/context_surface_contract/SKILL.md +13 -2
- package/assets/skills/context_uiux_design/SKILL.md +7 -3
- package/assets/skills/context_uiux_design/references/task-uiux-analysis.md +82 -0
- package/assets/skills/design-resource-authoring/SKILL.md +14 -8
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +18 -6
- package/assets/skills/design-resource-authoring/references/formal-selected-web-app-handoff.md +26 -8
- package/assets/skills/design-resource-authoring/references/implementation-feasibility.md +111 -0
- package/assets/skills/design-resource-authoring/references/open-design-provider.md +45 -7
- package/assets/skills/design-resource-authoring/references/recovery-and-writeback.md +7 -1
- package/assets/skills/design-resource-authoring/references/resource-selection.md +115 -3
- package/dist/commands/design-resource.js +9 -2
- package/dist/index.d.ts +1 -1
- package/dist/lib/design-resource-handoff-bundle.js +5 -0
- package/dist/lib/design-resource-handoff-input-types.d.ts +1 -1
- package/dist/lib/design-resource-handoff-manifest-projection.js +1 -0
- package/dist/lib/design-resource-handoff-set-integrity.js +1 -0
- package/dist/lib/design-resource-handoff-shape.js +6 -2
- package/dist/lib/design-resource-handoff-types.d.ts +5 -0
- package/dist/lib/design-resource-handoff-validation.js +12 -0
- package/dist/lib/design-resource-implementation-feasibility-model.d.ts +35 -0
- package/dist/lib/design-resource-implementation-feasibility-model.js +62 -0
- package/dist/lib/design-resource-implementation-feasibility-shape-sections.d.ts +43 -0
- package/dist/lib/design-resource-implementation-feasibility-shape-sections.js +142 -0
- package/dist/lib/design-resource-implementation-feasibility-shape.d.ts +4 -0
- package/dist/lib/design-resource-implementation-feasibility-shape.js +154 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision-projection.d.ts +24 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision-projection.js +106 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision.d.ts +21 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision.js +75 -0
- package/dist/lib/design-resource-implementation-feasibility-types.d.ts +135 -0
- package/dist/lib/design-resource-implementation-feasibility-types.js +37 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-cells.d.ts +5 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-cells.js +125 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-document.d.ts +4 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-document.js +167 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-facts.d.ts +3 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-facts.js +76 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-realizations.d.ts +8 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-realizations.js +76 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-support.d.ts +10 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-support.js +75 -0
- package/dist/lib/design-resource-implementation-feasibility-validation.d.ts +3 -0
- package/dist/lib/design-resource-implementation-feasibility-validation.js +138 -0
- package/dist/lib/design-resource-symbolic-fact-shape.js +3 -1
- package/dist/lib/design-resource-symbolic-fact-types.d.ts +5 -0
- package/dist/lib/design-resource-symbolic-fact-validation.js +13 -0
- package/dist/lib/long-task-activation-validation.js +77 -7
- package/dist/lib/long-task-check-runner.js +3 -296
- package/dist/lib/long-task-command-process.d.ts +9 -0
- package/dist/lib/long-task-command-process.js +175 -0
- package/dist/lib/long-task-delivery-validation.d.ts +5 -2
- package/dist/lib/long-task-delivery-validation.js +4 -4
- package/dist/lib/long-task-design-feasibility-binding-owners.d.ts +6 -0
- package/dist/lib/long-task-design-feasibility-binding-owners.js +52 -0
- package/dist/lib/long-task-design-feasibility-binding.d.ts +13 -0
- package/dist/lib/long-task-design-feasibility-binding.js +114 -0
- package/dist/lib/long-task-design-feasibility-source-closure.d.ts +11 -0
- package/dist/lib/long-task-design-feasibility-source-closure.js +78 -0
- package/dist/lib/long-task-design-resource-handoff.d.ts +3 -3
- package/dist/lib/long-task-design-resource-handoff.js +39 -3
- package/dist/lib/long-task-design-resource-method-binding.js +8 -2
- package/dist/lib/long-task-freshness.js +1 -1
- package/dist/lib/long-task-process-table.d.ts +12 -0
- package/dist/lib/long-task-process-table.js +119 -0
- package/dist/lib/long-task-process-tree.d.ts +9 -0
- package/dist/lib/long-task-process-tree.js +138 -0
- package/dist/lib/long-task-protected-files.d.ts +1 -1
- package/dist/lib/long-task-protected-files.js +1 -1
- package/dist/lib/long-task-ui-surface-policy.d.ts +2 -1
- package/dist/lib/long-task-ui-surface-policy.js +7 -4
- package/dist/lib/long-task-ui-surface-validation.d.ts +3 -1
- package/dist/lib/long-task-ui-surface-validation.js +2 -2
- package/dist/lib/repository-path-safety.d.ts +2 -0
- package/dist/lib/repository-path-safety.js +36 -0
- package/dist/public-types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { SymbolicDenotationPredicate } from "./symbolic-denotation-types.js";
|
|
2
|
+
export interface DesignResourceTechnicalFeasibilityInputV1 {
|
|
3
|
+
key: string;
|
|
4
|
+
target_ref: string;
|
|
5
|
+
path: string;
|
|
6
|
+
media_type: "application/json";
|
|
7
|
+
sha256: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const DESIGN_RESOURCE_SUBSTRATE_OBSERVATION_KINDS: readonly ["platform", "framework_runtime", "ui_system", "token_theming_adapter", "component_owner_roots", "route_owner_roots"];
|
|
10
|
+
export type DesignResourceSubstrateObservationKind = (typeof DESIGN_RESOURCE_SUBSTRATE_OBSERVATION_KINDS)[number];
|
|
11
|
+
export type DesignResourceSubstrateObservationDisposition = "observed" | "not_applicable" | "decision_required" | "unavailable";
|
|
12
|
+
export declare const DESIGN_RESOURCE_TECHNICAL_SOURCE_ROLES: readonly ["technical_platform", "framework_runtime", "ui_system", "token_theming_adapter", "component_owner", "route_owner", "capability_basis", "planned_owner_authorization", "technical_authority", "feasibility_basis"];
|
|
13
|
+
export type DesignResourceTechnicalSourceRole = (typeof DESIGN_RESOURCE_TECHNICAL_SOURCE_ROLES)[number];
|
|
14
|
+
export interface DesignResourceTechnicalSourceRecordV1 {
|
|
15
|
+
key: string;
|
|
16
|
+
path: string;
|
|
17
|
+
media_type: string;
|
|
18
|
+
sha256: string;
|
|
19
|
+
locator: {
|
|
20
|
+
kind: "whole_resource";
|
|
21
|
+
value: ".";
|
|
22
|
+
} | {
|
|
23
|
+
kind: "json_pointer";
|
|
24
|
+
value: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "markdown_anchor" | "source_anchor";
|
|
27
|
+
value: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "source_item";
|
|
30
|
+
value: string;
|
|
31
|
+
text_sha256: string;
|
|
32
|
+
};
|
|
33
|
+
roles: DesignResourceTechnicalSourceRole[];
|
|
34
|
+
}
|
|
35
|
+
export type DesignResourceSubstrateObservationValueV1 = {
|
|
36
|
+
kind: "identifier";
|
|
37
|
+
name: string;
|
|
38
|
+
version_source_ref: string | null;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "repository_paths";
|
|
41
|
+
paths: string[];
|
|
42
|
+
};
|
|
43
|
+
export interface DesignResourceSubstrateObservationV1 {
|
|
44
|
+
kind: DesignResourceSubstrateObservationKind;
|
|
45
|
+
disposition: DesignResourceSubstrateObservationDisposition;
|
|
46
|
+
value: DesignResourceSubstrateObservationValueV1 | null;
|
|
47
|
+
source_record_refs: string[];
|
|
48
|
+
reason: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface DesignResourceExplicitConditionProfileV1 {
|
|
51
|
+
key: string;
|
|
52
|
+
condition_refs: string[];
|
|
53
|
+
}
|
|
54
|
+
export interface DesignResourceSymbolicConditionProfileV1 {
|
|
55
|
+
key: string;
|
|
56
|
+
region: SymbolicDenotationPredicate;
|
|
57
|
+
}
|
|
58
|
+
export type DesignResourceImplementationConditionModelV1 = {
|
|
59
|
+
kind: "explicit_conditions_v1";
|
|
60
|
+
profiles: DesignResourceExplicitConditionProfileV1[];
|
|
61
|
+
} | {
|
|
62
|
+
kind: "symbolic_regions_v2";
|
|
63
|
+
profiles: DesignResourceSymbolicConditionProfileV1[];
|
|
64
|
+
};
|
|
65
|
+
export declare const DESIGN_RESOURCE_IMPLEMENTATION_STRATEGY_STEPS: readonly ["reuse_existing", "compose_existing", "extend_shared_component", "theme_with_tokens", "create_shared_component"];
|
|
66
|
+
export type DesignResourceImplementationStrategyStep = (typeof DESIGN_RESOURCE_IMPLEMENTATION_STRATEGY_STEPS)[number];
|
|
67
|
+
export declare const DESIGN_RESOURCE_CUSTOMIZATION_SURFACES: readonly ["theme_tokens", "component_variant", "primitive_props", "composition", "content_slot", "icon_slot", "behavior_slot", "style_api"];
|
|
68
|
+
export type DesignResourceCustomizationSurface = (typeof DESIGN_RESOURCE_CUSTOMIZATION_SURFACES)[number];
|
|
69
|
+
export type DesignResourceImplementationOwnerCandidateV1 = {
|
|
70
|
+
kind: "existing_path";
|
|
71
|
+
locator: string;
|
|
72
|
+
existence: "existing";
|
|
73
|
+
} | {
|
|
74
|
+
kind: "planned_logical_owner";
|
|
75
|
+
locator: string;
|
|
76
|
+
existence: "planned";
|
|
77
|
+
authorization_source_refs: string[];
|
|
78
|
+
};
|
|
79
|
+
export interface DesignResourceFeasibleRealizationV1 {
|
|
80
|
+
key: string;
|
|
81
|
+
strategy_steps: DesignResourceImplementationStrategyStep[];
|
|
82
|
+
primitive_refs: string[];
|
|
83
|
+
owner_candidates: DesignResourceImplementationOwnerCandidateV1[];
|
|
84
|
+
supported_customization_surfaces: DesignResourceCustomizationSurface[];
|
|
85
|
+
feasibility_basis_refs: string[];
|
|
86
|
+
observed_costs: string[];
|
|
87
|
+
observed_risks: string[];
|
|
88
|
+
}
|
|
89
|
+
export interface DesignResourceImplementationFeasibilityCellV1 {
|
|
90
|
+
key: string;
|
|
91
|
+
component_family_ref: string;
|
|
92
|
+
target_ref: string;
|
|
93
|
+
condition_profile_ref: string;
|
|
94
|
+
design_fact_refs: string[];
|
|
95
|
+
feasible_realizations: DesignResourceFeasibleRealizationV1[];
|
|
96
|
+
required_realization: {
|
|
97
|
+
realization_ref: string | null;
|
|
98
|
+
technical_authority_source_refs: string[];
|
|
99
|
+
};
|
|
100
|
+
blocker_refs: string[];
|
|
101
|
+
}
|
|
102
|
+
export interface DesignResourceImplementationFeasibilityBlockerV1 {
|
|
103
|
+
key: string;
|
|
104
|
+
component_family_ref: string;
|
|
105
|
+
target_ref: string;
|
|
106
|
+
condition_profile_ref: string;
|
|
107
|
+
source_record_refs: string[];
|
|
108
|
+
substrate_observation_refs: DesignResourceSubstrateObservationKind[];
|
|
109
|
+
description: string;
|
|
110
|
+
}
|
|
111
|
+
export interface DesignResourceImplementationFeasibilityV1 {
|
|
112
|
+
schema_version: "design-resource-implementation-feasibility-v1";
|
|
113
|
+
key: string;
|
|
114
|
+
target_ref: string;
|
|
115
|
+
realization_mode: "native_substrate" | "mapped_substrate" | "reference";
|
|
116
|
+
source_records: DesignResourceTechnicalSourceRecordV1[];
|
|
117
|
+
substrate_observations: DesignResourceSubstrateObservationV1[];
|
|
118
|
+
condition_model: DesignResourceImplementationConditionModelV1;
|
|
119
|
+
component_family_cells: DesignResourceImplementationFeasibilityCellV1[];
|
|
120
|
+
blockers: DesignResourceImplementationFeasibilityBlockerV1[];
|
|
121
|
+
}
|
|
122
|
+
export interface DesignResourceImplementationFeasibilityIdentityV1 {
|
|
123
|
+
key: string;
|
|
124
|
+
target_ref: string;
|
|
125
|
+
path: string;
|
|
126
|
+
sha256: string;
|
|
127
|
+
realization_mode: DesignResourceImplementationFeasibilityV1["realization_mode"];
|
|
128
|
+
component_family_cells: number;
|
|
129
|
+
blockers: number;
|
|
130
|
+
}
|
|
131
|
+
export interface LoadedDesignResourceImplementationFeasibilityV1 {
|
|
132
|
+
index: DesignResourceTechnicalFeasibilityInputV1;
|
|
133
|
+
document: DesignResourceImplementationFeasibilityV1;
|
|
134
|
+
identity: DesignResourceImplementationFeasibilityIdentityV1;
|
|
135
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const DESIGN_RESOURCE_SUBSTRATE_OBSERVATION_KINDS = [
|
|
2
|
+
"platform",
|
|
3
|
+
"framework_runtime",
|
|
4
|
+
"ui_system",
|
|
5
|
+
"token_theming_adapter",
|
|
6
|
+
"component_owner_roots",
|
|
7
|
+
"route_owner_roots",
|
|
8
|
+
];
|
|
9
|
+
export const DESIGN_RESOURCE_TECHNICAL_SOURCE_ROLES = [
|
|
10
|
+
"technical_platform",
|
|
11
|
+
"framework_runtime",
|
|
12
|
+
"ui_system",
|
|
13
|
+
"token_theming_adapter",
|
|
14
|
+
"component_owner",
|
|
15
|
+
"route_owner",
|
|
16
|
+
"capability_basis",
|
|
17
|
+
"planned_owner_authorization",
|
|
18
|
+
"technical_authority",
|
|
19
|
+
"feasibility_basis",
|
|
20
|
+
];
|
|
21
|
+
export const DESIGN_RESOURCE_IMPLEMENTATION_STRATEGY_STEPS = [
|
|
22
|
+
"reuse_existing",
|
|
23
|
+
"compose_existing",
|
|
24
|
+
"extend_shared_component",
|
|
25
|
+
"theme_with_tokens",
|
|
26
|
+
"create_shared_component",
|
|
27
|
+
];
|
|
28
|
+
export const DESIGN_RESOURCE_CUSTOMIZATION_SURFACES = [
|
|
29
|
+
"theme_tokens",
|
|
30
|
+
"component_variant",
|
|
31
|
+
"primitive_props",
|
|
32
|
+
"composition",
|
|
33
|
+
"content_slot",
|
|
34
|
+
"icon_slot",
|
|
35
|
+
"behavior_slot",
|
|
36
|
+
"style_api",
|
|
37
|
+
];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DesignResourceImplementationFeasibilityV1, DesignResourceTechnicalSourceRecordV1 } from "./design-resource-implementation-feasibility-types.js";
|
|
2
|
+
import type { DesignResourceImplementationFeasibilityTargetModel } from "./design-resource-implementation-feasibility-model.js";
|
|
3
|
+
import { type DesignResourceFeasibilityDecisionSourceIndex } from "./design-resource-implementation-feasibility-source-decision.js";
|
|
4
|
+
export declare function validateFeasibilityCells(repository: string, document: DesignResourceImplementationFeasibilityV1, model: DesignResourceImplementationFeasibilityTargetModel, profileRefs: Set<string>, sources: Map<string, DesignResourceTechnicalSourceRecordV1>, decisionSources: DesignResourceFeasibilityDecisionSourceIndex): Promise<void>;
|
|
5
|
+
export declare function validateSubstrateObservationBlockerCoverage(document: Pick<DesignResourceImplementationFeasibilityV1, "substrate_observations" | "component_family_cells" | "blockers">, model: Pick<DesignResourceImplementationFeasibilityTargetModel, "component_family_refs">): void;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { validateDesignFactRefs } from "./design-resource-implementation-feasibility-validation-facts.js";
|
|
2
|
+
import { validateFeasibleRealization, validateRequiredRealization, } from "./design-resource-implementation-feasibility-validation-realizations.js";
|
|
3
|
+
import { assertSameSet, cellPair, invalidFeasibility, requireKnownRefs, unique, } from "./design-resource-implementation-feasibility-validation-support.js";
|
|
4
|
+
import { DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA, deriveDesignResourceFeasibilityConditionScopeSha256, requireExactFeasibilityDecisionProjection, } from "./design-resource-implementation-feasibility-source-decision.js";
|
|
5
|
+
export async function validateFeasibilityCells(repository, document, model, profileRefs, sources, decisionSources) {
|
|
6
|
+
unique(document.component_family_cells.map((item) => item.key), "cell_key_duplicate");
|
|
7
|
+
unique(document.blockers.map((item) => item.key), "blocker_key_duplicate");
|
|
8
|
+
const families = new Set(model.component_family_refs);
|
|
9
|
+
const blockers = new Map(document.blockers.map((item) => [item.key, item]));
|
|
10
|
+
const componentOwnerObservation = document.substrate_observations.find((observation) => observation.kind === "component_owner_roots");
|
|
11
|
+
const componentOwnerRoots = componentOwnerObservation?.value?.kind === "repository_paths"
|
|
12
|
+
? componentOwnerObservation.value.paths
|
|
13
|
+
: [];
|
|
14
|
+
const usedBlockers = new Set();
|
|
15
|
+
const cellPairs = [];
|
|
16
|
+
const realizationKeys = [];
|
|
17
|
+
for (const cell of document.component_family_cells) {
|
|
18
|
+
cellPairs.push(cellPair(cell.component_family_ref, cell.condition_profile_ref));
|
|
19
|
+
await validateCell(repository, cell, document, model, families, profileRefs, sources, decisionSources, componentOwnerRoots, blockers, usedBlockers, realizationKeys);
|
|
20
|
+
}
|
|
21
|
+
unique(cellPairs, "component_family_condition_cell_duplicate");
|
|
22
|
+
unique(realizationKeys, "realization_key_duplicate");
|
|
23
|
+
if (document.realization_mode !== "reference") {
|
|
24
|
+
const expected = model.component_family_refs.flatMap((familyRef) => [...profileRefs].map((profileRef) => cellPair(familyRef, profileRef)));
|
|
25
|
+
assertSameSet(cellPairs, expected, "component_family_condition_cell_set_mismatch");
|
|
26
|
+
}
|
|
27
|
+
validateBlockers(document, model, families, profileRefs, sources, decisionSources, usedBlockers);
|
|
28
|
+
validateSubstrateObservationBlockerCoverage(document, model);
|
|
29
|
+
}
|
|
30
|
+
export function validateSubstrateObservationBlockerCoverage(document, model) {
|
|
31
|
+
const observations = new Map(document.substrate_observations.map((observation) => [
|
|
32
|
+
observation.kind,
|
|
33
|
+
observation,
|
|
34
|
+
]));
|
|
35
|
+
const blockers = new Map(document.blockers.map((blocker) => [blocker.key, blocker]));
|
|
36
|
+
for (const blocker of document.blockers) {
|
|
37
|
+
unique(blocker.substrate_observation_refs, "blocker_substrate_observation_ref_duplicate", blocker.key);
|
|
38
|
+
for (const observationRef of blocker.substrate_observation_refs) {
|
|
39
|
+
const observation = observations.get(observationRef);
|
|
40
|
+
if (!observation ||
|
|
41
|
+
!["decision_required", "unavailable"].includes(observation.disposition))
|
|
42
|
+
invalidFeasibility("blocker_substrate_observation_not_unresolved", `${blocker.key}:${observationRef}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const unresolved = document.substrate_observations.filter((observation) => ["decision_required", "unavailable"].includes(observation.disposition));
|
|
46
|
+
if (unresolved.length && model.component_family_refs.length === 0)
|
|
47
|
+
invalidFeasibility("unresolved_substrate_without_family_carrier", unresolved.map((observation) => observation.kind).join(","));
|
|
48
|
+
for (const cell of document.component_family_cells)
|
|
49
|
+
for (const observation of unresolved)
|
|
50
|
+
if (!cell.blocker_refs.some((blockerRef) => blockers
|
|
51
|
+
.get(blockerRef)
|
|
52
|
+
?.substrate_observation_refs.includes(observation.kind)))
|
|
53
|
+
invalidFeasibility("unresolved_substrate_observation_cell_uncovered", `${observation.kind}:${cell.key}`);
|
|
54
|
+
}
|
|
55
|
+
async function validateCell(repository, cell, document, model, families, profileRefs, sources, decisionSources, componentOwnerRoots, blockers, usedBlockers, realizationKeys) {
|
|
56
|
+
validateCellIdentity(cell, document.target_ref, families, profileRefs);
|
|
57
|
+
unique(cell.design_fact_refs, "cell_design_fact_ref_duplicate", cell.key);
|
|
58
|
+
if (!cell.design_fact_refs.length &&
|
|
59
|
+
document.realization_mode !== "reference")
|
|
60
|
+
invalidFeasibility("cell_design_fact_refs_required", cell.key);
|
|
61
|
+
validateDesignFactRefs(cell, model, document);
|
|
62
|
+
const conditionScopeSha256 = deriveDesignResourceFeasibilityConditionScopeSha256(document, model, cell.condition_profile_ref);
|
|
63
|
+
validateCellBlockers(cell, blockers, usedBlockers);
|
|
64
|
+
if (!cell.feasible_realizations.length && !cell.blocker_refs.length)
|
|
65
|
+
invalidFeasibility("cell_candidate_or_blocker_required", cell.key);
|
|
66
|
+
unique(cell.feasible_realizations.map((item) => item.key), "cell_realization_key_duplicate", cell.key);
|
|
67
|
+
for (const realization of cell.feasible_realizations) {
|
|
68
|
+
realizationKeys.push(realization.key);
|
|
69
|
+
await validateFeasibleRealization(repository, realization, sources, decisionSources, componentOwnerRoots, {
|
|
70
|
+
target_ref: cell.target_ref,
|
|
71
|
+
component_family_ref: cell.component_family_ref,
|
|
72
|
+
condition_scope_sha256: conditionScopeSha256,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
validateRequiredRealization(cell, sources, decisionSources, conditionScopeSha256);
|
|
76
|
+
}
|
|
77
|
+
function validateCellBlockers(cell, blockers, usedBlockers) {
|
|
78
|
+
unique(cell.blocker_refs, "cell_blocker_ref_duplicate", cell.key);
|
|
79
|
+
for (const blockerRef of cell.blocker_refs) {
|
|
80
|
+
const blocker = blockers.get(blockerRef);
|
|
81
|
+
if (!blocker)
|
|
82
|
+
invalidFeasibility("cell_blocker_unknown", `${cell.key}:${blockerRef}`);
|
|
83
|
+
if (blocker.target_ref !== cell.target_ref ||
|
|
84
|
+
blocker.component_family_ref !== cell.component_family_ref ||
|
|
85
|
+
blocker.condition_profile_ref !== cell.condition_profile_ref)
|
|
86
|
+
invalidFeasibility("cell_blocker_scope_mismatch", `${cell.key}:${blockerRef}`);
|
|
87
|
+
usedBlockers.add(blockerRef);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function validateBlockers(document, model, families, profileRefs, sources, decisionSources, usedBlockers) {
|
|
91
|
+
for (const blocker of document.blockers) {
|
|
92
|
+
if (blocker.target_ref !== document.target_ref)
|
|
93
|
+
invalidFeasibility("blocker_target_mismatch", blocker.key);
|
|
94
|
+
if (!families.has(blocker.component_family_ref))
|
|
95
|
+
invalidFeasibility("blocker_component_family_unknown", blocker.key);
|
|
96
|
+
if (!profileRefs.has(blocker.condition_profile_ref))
|
|
97
|
+
invalidFeasibility("blocker_condition_profile_unknown", blocker.key);
|
|
98
|
+
if (!blocker.source_record_refs.length)
|
|
99
|
+
invalidFeasibility("blocker_source_required", blocker.key);
|
|
100
|
+
unique(blocker.source_record_refs, "blocker_source_duplicate", blocker.key);
|
|
101
|
+
requireKnownRefs(blocker.source_record_refs, sources, "blocker_source_unknown", blocker.key);
|
|
102
|
+
requireExactFeasibilityDecisionProjection(blocker.source_record_refs, decisionSources, {
|
|
103
|
+
schema_version: DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA,
|
|
104
|
+
mode: "feasibility_blocker",
|
|
105
|
+
target_ref: blocker.target_ref,
|
|
106
|
+
component_family_ref: blocker.component_family_ref,
|
|
107
|
+
condition_scope_sha256: deriveDesignResourceFeasibilityConditionScopeSha256(document, model, blocker.condition_profile_ref),
|
|
108
|
+
blocker_ref: blocker.key,
|
|
109
|
+
substrate_observation_refs: blocker.substrate_observation_refs,
|
|
110
|
+
}, `blocker:${blocker.key}`, {
|
|
111
|
+
allReferencesMustBeSourceItems: false,
|
|
112
|
+
allowedItemKinds: ["decision", "external_confirmation"],
|
|
113
|
+
});
|
|
114
|
+
if (!usedBlockers.has(blocker.key))
|
|
115
|
+
invalidFeasibility("blocker_unreferenced", blocker.key);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function validateCellIdentity(cell, targetRef, families, profiles) {
|
|
119
|
+
if (cell.target_ref !== targetRef)
|
|
120
|
+
invalidFeasibility("cell_target_mismatch", cell.key);
|
|
121
|
+
if (!families.has(cell.component_family_ref))
|
|
122
|
+
invalidFeasibility("cell_component_family_unknown", cell.key);
|
|
123
|
+
if (!profiles.has(cell.condition_profile_ref))
|
|
124
|
+
invalidFeasibility("cell_condition_profile_unknown", cell.key);
|
|
125
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type DesignResourceImplementationFeasibilityV1 } from "./design-resource-implementation-feasibility-types.js";
|
|
2
|
+
import type { DesignResourceImplementationFeasibilityTargetModel } from "./design-resource-implementation-feasibility-model.js";
|
|
3
|
+
import type { DesignResourceFeasibilityDecisionSourceIndex } from "./design-resource-implementation-feasibility-source-decision.js";
|
|
4
|
+
export declare function validateFeasibilityDocument(repository: string, document: DesignResourceImplementationFeasibilityV1, model: DesignResourceImplementationFeasibilityTargetModel, decisionSources: DesignResourceFeasibilityDecisionSourceIndex): Promise<void>;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { DESIGN_RESOURCE_SUBSTRATE_OBSERVATION_KINDS, } from "./design-resource-implementation-feasibility-types.js";
|
|
2
|
+
import { validateFeasibilityCells } from "./design-resource-implementation-feasibility-validation-cells.js";
|
|
3
|
+
import { assertSameSet, invalidFeasibility, requireKnownRefs, unique, } from "./design-resource-implementation-feasibility-validation-support.js";
|
|
4
|
+
import { createSymbolicDenotationCompilationSession } from "./symbolic-denotation-engine.js";
|
|
5
|
+
import { validateNoExactVisualValueCarriers } from "./design-resource-implementation-feasibility-validation-support.js";
|
|
6
|
+
import { assertProtectedRepositoryDirectory, assertProtectedRepositoryPath, } from "./repository-path-safety.js";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
const OBSERVATION_SOURCE_ROLES = {
|
|
9
|
+
platform: "technical_platform",
|
|
10
|
+
framework_runtime: "framework_runtime",
|
|
11
|
+
ui_system: "ui_system",
|
|
12
|
+
token_theming_adapter: "token_theming_adapter",
|
|
13
|
+
component_owner_roots: "component_owner",
|
|
14
|
+
route_owner_roots: "route_owner",
|
|
15
|
+
};
|
|
16
|
+
export async function validateFeasibilityDocument(repository, document, model, decisionSources) {
|
|
17
|
+
if (document.target_ref !== model.target_ref)
|
|
18
|
+
invalidFeasibility("document_target_mismatch", `${document.target_ref}:${model.target_ref}`);
|
|
19
|
+
if (document.realization_mode === "reference" &&
|
|
20
|
+
model.source_profile_kind !== "reference")
|
|
21
|
+
invalidFeasibility("reference_mode_formal_implementation_forbidden", model.target_ref);
|
|
22
|
+
if (document.realization_mode !== "reference" &&
|
|
23
|
+
model.source_profile_kind === "reference")
|
|
24
|
+
invalidFeasibility("reference_profile_feasibility_mode_invalid", model.target_ref);
|
|
25
|
+
const sources = new Map(document.source_records.map((item) => [item.key, item]));
|
|
26
|
+
validateNoExactVisualValueCarriers(document);
|
|
27
|
+
await validateObservations(repository, document, sources);
|
|
28
|
+
validateCandidateComponentOwnerRoots(document);
|
|
29
|
+
const profileRefs = validateConditionModel(document, model);
|
|
30
|
+
await validateFeasibilityCells(repository, document, model, profileRefs, sources, decisionSources);
|
|
31
|
+
}
|
|
32
|
+
async function validateObservations(repository, document, sources) {
|
|
33
|
+
unique(document.substrate_observations.map((item) => item.kind), "substrate_observation_kind_duplicate");
|
|
34
|
+
if (document.realization_mode !== "reference")
|
|
35
|
+
assertSameSet(document.substrate_observations.map((item) => item.kind), [...DESIGN_RESOURCE_SUBSTRATE_OBSERVATION_KINDS], "substrate_observation_kind_set_mismatch");
|
|
36
|
+
for (const observation of document.substrate_observations) {
|
|
37
|
+
unique(observation.source_record_refs, "substrate_observation_source_duplicate", observation.kind);
|
|
38
|
+
requireKnownRefs(observation.source_record_refs, sources, "substrate_observation_source_unknown", observation.kind);
|
|
39
|
+
if (observation.disposition === "observed") {
|
|
40
|
+
validateObservedSubstrate(observation, sources);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
if (observation.value !== null)
|
|
44
|
+
invalidFeasibility("unobserved_substrate_value_forbidden", observation.kind);
|
|
45
|
+
if (observation.reason === null)
|
|
46
|
+
invalidFeasibility("unobserved_substrate_reason_required", observation.kind);
|
|
47
|
+
}
|
|
48
|
+
validateObservationValue(observation, sources);
|
|
49
|
+
if (observation.value?.kind === "repository_paths")
|
|
50
|
+
for (const repositoryPath of observation.value.paths)
|
|
51
|
+
await (observation.kind === "component_owner_roots" ||
|
|
52
|
+
observation.kind === "route_owner_roots"
|
|
53
|
+
? assertProtectedRepositoryDirectory
|
|
54
|
+
: assertProtectedRepositoryPath)(repository, path.resolve(repository, ...repositoryPath.split("/")), `design_resource_feasibility_repository_path:${observation.kind}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function validateCandidateComponentOwnerRoots(document) {
|
|
58
|
+
if (!document.component_family_cells.some((cell) => cell.feasible_realizations.length > 0))
|
|
59
|
+
return;
|
|
60
|
+
const roots = document.substrate_observations.find((observation) => observation.kind === "component_owner_roots");
|
|
61
|
+
if (roots?.disposition !== "observed" ||
|
|
62
|
+
roots.value?.kind !== "repository_paths" ||
|
|
63
|
+
roots.value.paths.length === 0)
|
|
64
|
+
invalidFeasibility("candidate_component_owner_roots_required", document.target_ref);
|
|
65
|
+
}
|
|
66
|
+
function validateObservedSubstrate(observation, sources) {
|
|
67
|
+
if (!observation.value)
|
|
68
|
+
invalidFeasibility("observed_substrate_value_required", observation.kind);
|
|
69
|
+
if (observation.reason !== null)
|
|
70
|
+
invalidFeasibility("observed_substrate_reason_forbidden", observation.kind);
|
|
71
|
+
if (!observation.source_record_refs.length)
|
|
72
|
+
invalidFeasibility("observed_substrate_source_required", observation.kind);
|
|
73
|
+
const requiredRole = OBSERVATION_SOURCE_ROLES[observation.kind];
|
|
74
|
+
if (!observation.source_record_refs.some((ref) => sources.get(ref).roles.includes(requiredRole)))
|
|
75
|
+
invalidFeasibility("observed_substrate_source_role_missing", `${observation.kind}:${requiredRole}`);
|
|
76
|
+
}
|
|
77
|
+
function validateObservationValue(observation, sources) {
|
|
78
|
+
if (!observation.value)
|
|
79
|
+
return;
|
|
80
|
+
if (["platform", "framework_runtime", "ui_system"].includes(observation.kind) &&
|
|
81
|
+
observation.value.kind !== "identifier")
|
|
82
|
+
invalidFeasibility("observation_value_kind_invalid", `${observation.kind}:${observation.value.kind}`);
|
|
83
|
+
if (["component_owner_roots", "route_owner_roots"].includes(observation.kind) &&
|
|
84
|
+
observation.value.kind !== "repository_paths")
|
|
85
|
+
invalidFeasibility("observation_value_kind_invalid", `${observation.kind}:${observation.value.kind}`);
|
|
86
|
+
if (observation.value?.kind === "identifier") {
|
|
87
|
+
const versionRef = observation.value.version_source_ref;
|
|
88
|
+
if (versionRef && !sources.has(versionRef))
|
|
89
|
+
invalidFeasibility("observation_version_source_unknown", versionRef);
|
|
90
|
+
}
|
|
91
|
+
else if (observation.value?.kind === "repository_paths" &&
|
|
92
|
+
!observation.value.paths.length) {
|
|
93
|
+
invalidFeasibility("observation_repository_paths_required", observation.kind);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function validateConditionModel(document, model) {
|
|
97
|
+
const conditionModel = document.condition_model;
|
|
98
|
+
if (model.representation === "fact_cells_v1" &&
|
|
99
|
+
conditionModel.kind !== "explicit_conditions_v1")
|
|
100
|
+
invalidFeasibility("v1_explicit_condition_model_required", model.target_ref);
|
|
101
|
+
if (model.representation === "symbolic_rules_v2" &&
|
|
102
|
+
conditionModel.kind !== "symbolic_regions_v2")
|
|
103
|
+
invalidFeasibility("v2_symbolic_condition_model_required", model.target_ref);
|
|
104
|
+
if (!conditionModel.profiles.length &&
|
|
105
|
+
document.realization_mode !== "reference")
|
|
106
|
+
invalidFeasibility("condition_profiles_required", model.target_ref);
|
|
107
|
+
unique(conditionModel.profiles.map((item) => item.key), "condition_profile_key_duplicate");
|
|
108
|
+
if (model.representation === "fact_cells_v1" &&
|
|
109
|
+
conditionModel.kind === "explicit_conditions_v1")
|
|
110
|
+
validateExplicitConditionProfiles(document, model);
|
|
111
|
+
if (model.representation === "symbolic_rules_v2" &&
|
|
112
|
+
conditionModel.kind === "symbolic_regions_v2" &&
|
|
113
|
+
conditionModel.profiles.length)
|
|
114
|
+
validateSymbolicConditionProfiles(document, model);
|
|
115
|
+
return new Set(conditionModel.profiles.map((item) => item.key));
|
|
116
|
+
}
|
|
117
|
+
function validateExplicitConditionProfiles(document, model) {
|
|
118
|
+
if (document.condition_model.kind !== "explicit_conditions_v1")
|
|
119
|
+
return;
|
|
120
|
+
const conditionRefs = document.condition_model.profiles.flatMap((profile) => {
|
|
121
|
+
if (!profile.condition_refs.length)
|
|
122
|
+
invalidFeasibility("condition_profile_empty", profile.key);
|
|
123
|
+
unique(profile.condition_refs, "condition_profile_ref_duplicate", profile.key);
|
|
124
|
+
return profile.condition_refs;
|
|
125
|
+
});
|
|
126
|
+
unique(conditionRefs, "condition_profile_overlap");
|
|
127
|
+
if (document.realization_mode !== "reference")
|
|
128
|
+
assertSameSet(conditionRefs, model.condition_refs, "condition_profile_set_mismatch");
|
|
129
|
+
}
|
|
130
|
+
function validateSymbolicConditionProfiles(document, model) {
|
|
131
|
+
if (document.condition_model.kind !== "symbolic_regions_v2")
|
|
132
|
+
return;
|
|
133
|
+
const profiles = document.condition_model.profiles;
|
|
134
|
+
const compilation = createSymbolicDenotationCompilationSession(model.axis_domains, [model.reachable_region, ...profiles.map((item) => item.region)]);
|
|
135
|
+
const reachable = compilation.compile(model.reachable_region);
|
|
136
|
+
for (const profile of profiles) {
|
|
137
|
+
const outside = compilation.compile({
|
|
138
|
+
op: "all",
|
|
139
|
+
predicates: [
|
|
140
|
+
profile.region,
|
|
141
|
+
{ op: "not", predicate: model.reachable_region },
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
if (outside.canonical_dag.root_ref !== "terminal.false")
|
|
145
|
+
invalidFeasibility("symbolic_condition_profile_unreachable", profile.key);
|
|
146
|
+
}
|
|
147
|
+
validateSymbolicProfileDisjointness(profiles, compilation);
|
|
148
|
+
if (document.realization_mode !== "reference") {
|
|
149
|
+
const union = compilation.compile({
|
|
150
|
+
op: "any",
|
|
151
|
+
predicates: profiles.map((item) => item.region),
|
|
152
|
+
});
|
|
153
|
+
if (union.canonical_sha256 !== reachable.canonical_sha256)
|
|
154
|
+
invalidFeasibility("symbolic_condition_profile_coverage_gap", model.target_ref);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function validateSymbolicProfileDisjointness(profiles, compilation) {
|
|
158
|
+
for (let left = 0; left < profiles.length; left += 1)
|
|
159
|
+
for (let right = left + 1; right < profiles.length; right += 1) {
|
|
160
|
+
const overlap = compilation.compile({
|
|
161
|
+
op: "all",
|
|
162
|
+
predicates: [profiles[left].region, profiles[right].region],
|
|
163
|
+
});
|
|
164
|
+
if (overlap.canonical_dag.root_ref !== "terminal.false")
|
|
165
|
+
invalidFeasibility("symbolic_condition_profile_overlap", `${profiles[left].key}:${profiles[right].key}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DesignResourceImplementationFeasibilityCellV1, DesignResourceImplementationFeasibilityV1 } from "./design-resource-implementation-feasibility-types.js";
|
|
2
|
+
import type { DesignResourceImplementationFeasibilityTargetModel } from "./design-resource-implementation-feasibility-model.js";
|
|
3
|
+
export declare function validateDesignFactRefs(cell: DesignResourceImplementationFeasibilityCellV1, model: DesignResourceImplementationFeasibilityTargetModel, document: DesignResourceImplementationFeasibilityV1): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { assertSameSet, invalidFeasibility, } from "./design-resource-implementation-feasibility-validation-support.js";
|
|
2
|
+
import { createSymbolicDenotationCompilationSession } from "./symbolic-denotation-engine.js";
|
|
3
|
+
export function validateDesignFactRefs(cell, model, document) {
|
|
4
|
+
if (model.representation === "fact_cells_v1") {
|
|
5
|
+
validateV1FactRefs(cell, model, document);
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
validateV2RuleRefs(cell, model, document);
|
|
9
|
+
}
|
|
10
|
+
function validateV1FactRefs(cell, model, document) {
|
|
11
|
+
if (document.condition_model.kind !== "explicit_conditions_v1")
|
|
12
|
+
invalidFeasibility("v1_explicit_condition_model_required", cell.key);
|
|
13
|
+
const profile = document.condition_model.profiles.find((item) => item.key === cell.condition_profile_ref);
|
|
14
|
+
for (const ref of cell.design_fact_refs) {
|
|
15
|
+
const fact = model.facts.get(ref);
|
|
16
|
+
if (!fact)
|
|
17
|
+
invalidFeasibility("cell_design_fact_unknown", `${cell.key}:${ref}`);
|
|
18
|
+
if (fact.target_ref !== cell.target_ref ||
|
|
19
|
+
!model.component_family_subject_refs
|
|
20
|
+
.get(cell.component_family_ref)
|
|
21
|
+
.has(fact.subject_ref) ||
|
|
22
|
+
!profile.condition_refs.includes(fact.condition_ref))
|
|
23
|
+
invalidFeasibility("cell_design_fact_scope_mismatch", `${cell.key}:${ref}`);
|
|
24
|
+
}
|
|
25
|
+
const expectedRefs = [...model.facts.entries()]
|
|
26
|
+
.filter(([, fact]) => fact.target_ref === cell.target_ref &&
|
|
27
|
+
model.component_family_subject_refs
|
|
28
|
+
.get(cell.component_family_ref)
|
|
29
|
+
.has(fact.subject_ref) &&
|
|
30
|
+
profile.condition_refs.includes(fact.condition_ref))
|
|
31
|
+
.map(([ref]) => ref);
|
|
32
|
+
assertSameSet(cell.design_fact_refs, expectedRefs, "cell_design_fact_set_mismatch");
|
|
33
|
+
}
|
|
34
|
+
function validateV2RuleRefs(cell, model, document) {
|
|
35
|
+
if (document.condition_model.kind !== "symbolic_regions_v2")
|
|
36
|
+
invalidFeasibility("v2_symbolic_condition_model_required", cell.key);
|
|
37
|
+
const profile = document.condition_model.profiles.find((item) => item.key === cell.condition_profile_ref);
|
|
38
|
+
const referencedRules = cell.design_fact_refs.map((ref) => {
|
|
39
|
+
const rule = model.fact_rules.get(ref);
|
|
40
|
+
if (!rule)
|
|
41
|
+
invalidFeasibility("cell_design_rule_unknown", `${cell.key}:${ref}`);
|
|
42
|
+
return rule;
|
|
43
|
+
});
|
|
44
|
+
const familyRules = [...model.fact_rules.values()].filter((rule) => rule.target_ref === cell.target_ref &&
|
|
45
|
+
model.component_family_subject_refs
|
|
46
|
+
.get(cell.component_family_ref)
|
|
47
|
+
.has(rule.subject_or_relation_ref));
|
|
48
|
+
const compilation = createSymbolicDenotationCompilationSession(model.axis_domains, [
|
|
49
|
+
model.reachable_region,
|
|
50
|
+
profile.region,
|
|
51
|
+
...familyRules.map((rule) => rule.region),
|
|
52
|
+
]);
|
|
53
|
+
for (const rule of referencedRules) {
|
|
54
|
+
if (rule.target_ref !== cell.target_ref ||
|
|
55
|
+
!model.component_family_subject_refs
|
|
56
|
+
.get(cell.component_family_ref)
|
|
57
|
+
.has(rule.subject_or_relation_ref))
|
|
58
|
+
invalidFeasibility("cell_design_rule_scope_mismatch", `${cell.key}:${rule.key}`);
|
|
59
|
+
const intersection = compilation.compile({
|
|
60
|
+
op: "all",
|
|
61
|
+
predicates: [profile.region, rule.region],
|
|
62
|
+
});
|
|
63
|
+
if (intersection.canonical_dag.root_ref === "terminal.false")
|
|
64
|
+
invalidFeasibility("cell_design_rule_condition_mismatch", `${cell.key}:${rule.key}`);
|
|
65
|
+
}
|
|
66
|
+
const expectedRefs = familyRules
|
|
67
|
+
.filter((rule) => {
|
|
68
|
+
const intersection = compilation.compile({
|
|
69
|
+
op: "all",
|
|
70
|
+
predicates: [profile.region, rule.region],
|
|
71
|
+
});
|
|
72
|
+
return intersection.canonical_dag.root_ref !== "terminal.false";
|
|
73
|
+
})
|
|
74
|
+
.map((rule) => rule.key);
|
|
75
|
+
assertSameSet(cell.design_fact_refs, expectedRefs, "cell_design_rule_set_mismatch");
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DesignResourceFeasibleRealizationV1, DesignResourceImplementationFeasibilityCellV1, DesignResourceTechnicalSourceRecordV1 } from "./design-resource-implementation-feasibility-types.js";
|
|
2
|
+
import { type DesignResourceFeasibilityDecisionSourceIndex } from "./design-resource-implementation-feasibility-source-decision.js";
|
|
3
|
+
export declare function validateFeasibleRealization(repository: string, realization: DesignResourceFeasibleRealizationV1, sources: Map<string, DesignResourceTechnicalSourceRecordV1>, decisionSources: DesignResourceFeasibilityDecisionSourceIndex, componentOwnerRoots: string[], scope: {
|
|
4
|
+
target_ref: string;
|
|
5
|
+
component_family_ref: string;
|
|
6
|
+
condition_scope_sha256: string;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
export declare function validateRequiredRealization(cell: DesignResourceImplementationFeasibilityCellV1, sources: Map<string, DesignResourceTechnicalSourceRecordV1>, decisionSources: DesignResourceFeasibilityDecisionSourceIndex, conditionScopeSha256: string): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { invalidFeasibility, requireAtLeastOneSourceRole, requireKnownRefs, requireSourceRole, unique, } from "./design-resource-implementation-feasibility-validation-support.js";
|
|
3
|
+
import { assertProtectedRepositoryFile } from "./long-task-protected-files.js";
|
|
4
|
+
import { DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA, requireExactFeasibilityDecisionProjection, } from "./design-resource-implementation-feasibility-source-decision.js";
|
|
5
|
+
export async function validateFeasibleRealization(repository, realization, sources, decisionSources, componentOwnerRoots, scope) {
|
|
6
|
+
if (!realization.strategy_steps.length)
|
|
7
|
+
invalidFeasibility("realization_strategy_steps_required", realization.key);
|
|
8
|
+
unique(realization.strategy_steps, "realization_strategy_step_duplicate", realization.key);
|
|
9
|
+
if (!realization.primitive_refs.length)
|
|
10
|
+
invalidFeasibility("realization_primitive_refs_required", realization.key);
|
|
11
|
+
unique(realization.primitive_refs, "realization_primitive_ref_duplicate", realization.key);
|
|
12
|
+
if (!realization.owner_candidates.length)
|
|
13
|
+
invalidFeasibility("realization_owner_candidates_required", realization.key);
|
|
14
|
+
unique(realization.owner_candidates.map((item) => `${item.kind}:${item.locator}`), "realization_owner_candidate_duplicate", realization.key);
|
|
15
|
+
unique(realization.supported_customization_surfaces, "realization_customization_surface_duplicate", realization.key);
|
|
16
|
+
validateFeasibilityBasis(realization, sources);
|
|
17
|
+
unique(realization.observed_costs, "realization_observed_cost_duplicate", realization.key);
|
|
18
|
+
unique(realization.observed_risks, "realization_observed_risk_duplicate", realization.key);
|
|
19
|
+
for (const owner of realization.owner_candidates)
|
|
20
|
+
await validateOwnerCandidate(repository, realization.key, owner, sources, decisionSources, componentOwnerRoots, scope);
|
|
21
|
+
}
|
|
22
|
+
function validateFeasibilityBasis(realization, sources) {
|
|
23
|
+
if (!realization.feasibility_basis_refs.length)
|
|
24
|
+
invalidFeasibility("realization_feasibility_basis_required", realization.key);
|
|
25
|
+
requireKnownRefs(realization.feasibility_basis_refs, sources, "realization_feasibility_basis_unknown", realization.key);
|
|
26
|
+
unique(realization.feasibility_basis_refs, "realization_feasibility_basis_duplicate", realization.key);
|
|
27
|
+
requireAtLeastOneSourceRole(realization.feasibility_basis_refs, sources, "feasibility_basis", "realization_feasibility_basis_role_missing", realization.key);
|
|
28
|
+
requireAtLeastOneSourceRole(realization.feasibility_basis_refs, sources, "capability_basis", "realization_capability_basis_role_missing", realization.key);
|
|
29
|
+
}
|
|
30
|
+
async function validateOwnerCandidate(repository, realizationKey, owner, sources, decisionSources, componentOwnerRoots, scope) {
|
|
31
|
+
if (owner.kind === "existing_path") {
|
|
32
|
+
await assertProtectedRepositoryFile(repository, path.resolve(repository, ...owner.locator.split("/")), `design_resource_feasibility_owner:${realizationKey}`);
|
|
33
|
+
if (componentOwnerRoots.length > 0 &&
|
|
34
|
+
!componentOwnerRoots.some((root) => owner.locator === root || owner.locator.startsWith(`${root}/`)))
|
|
35
|
+
invalidFeasibility("existing_owner_outside_component_roots", `${realizationKey}:${owner.locator}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!owner.authorization_source_refs.length)
|
|
39
|
+
invalidFeasibility("planned_owner_authorization_required", realizationKey);
|
|
40
|
+
unique(owner.authorization_source_refs, "planned_owner_authorization_duplicate", realizationKey);
|
|
41
|
+
requireSourceRole(owner.authorization_source_refs, sources, "planned_owner_authorization", "planned_owner_authorization_invalid", realizationKey);
|
|
42
|
+
requireExactFeasibilityDecisionProjection(owner.authorization_source_refs, decisionSources, {
|
|
43
|
+
schema_version: DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA,
|
|
44
|
+
mode: "planned_owner_authorization",
|
|
45
|
+
...scope,
|
|
46
|
+
owner_locator: owner.locator,
|
|
47
|
+
}, `planned_owner:${realizationKey}:${owner.locator}`, {
|
|
48
|
+
allReferencesMustBeSourceItems: true,
|
|
49
|
+
allowedItemKinds: ["technical_obligation"],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function validateRequiredRealization(cell, sources, decisionSources, conditionScopeSha256) {
|
|
53
|
+
const required = cell.required_realization;
|
|
54
|
+
unique(required.technical_authority_source_refs, "required_realization_authority_duplicate", cell.key);
|
|
55
|
+
if (required.realization_ref === null) {
|
|
56
|
+
if (required.technical_authority_source_refs.length)
|
|
57
|
+
invalidFeasibility("required_realization_authority_without_selection", cell.key);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!cell.feasible_realizations.some((realization) => realization.key === required.realization_ref))
|
|
61
|
+
invalidFeasibility("required_realization_unknown", cell.key);
|
|
62
|
+
if (!required.technical_authority_source_refs.length)
|
|
63
|
+
invalidFeasibility("required_realization_authority_required", cell.key);
|
|
64
|
+
requireSourceRole(required.technical_authority_source_refs, sources, "technical_authority", "required_realization_authority_invalid", cell.key);
|
|
65
|
+
requireExactFeasibilityDecisionProjection(required.technical_authority_source_refs, decisionSources, {
|
|
66
|
+
schema_version: DESIGN_RESOURCE_FEASIBILITY_DECISION_SCHEMA,
|
|
67
|
+
mode: "required_realization",
|
|
68
|
+
target_ref: cell.target_ref,
|
|
69
|
+
component_family_ref: cell.component_family_ref,
|
|
70
|
+
condition_scope_sha256: conditionScopeSha256,
|
|
71
|
+
realization_ref: required.realization_ref,
|
|
72
|
+
}, `required_realization:${cell.key}`, {
|
|
73
|
+
allReferencesMustBeSourceItems: true,
|
|
74
|
+
allowedItemKinds: ["technical_obligation"],
|
|
75
|
+
});
|
|
76
|
+
}
|