feat(foundry): support typed non-geometric subject aspects

This commit is contained in:
Codex
2026-07-23 09:43:51 +03:00
parent dc82ae4c07
commit 03aa9e3e7e
4 changed files with 376 additions and 7 deletions
+59 -1
View File
@@ -70,6 +70,19 @@ requireValue(new Set(consumerPolicyProducts).size === consumerPolicyProducts.len
for (const policy of consumerPolicies) {
const statusContract = policy.statusContract;
const freshness = policy.freshness ?? statusContract?.freshness ?? "observed-at";
const allowedPolicyKeys = new Set([
"id",
"version",
"dataProductId",
"productVersion",
"freshness",
"staleAfterMs",
"terminalStatuses",
"statusContract",
"consumerContract",
"removeMode",
]);
requireValue(Object.keys(policy).every((key) => allowedPolicyKeys.has(key)), `unsupported data product consumer policy key: ${policy.id ?? "unknown"}`);
requireValue(typeof policy.id === "string" && /^[a-z0-9._-]{1,160}$/.test(policy.id), `invalid data product consumer policy id: ${policy.id ?? "unknown"}`);
requireValue(typeof policy.version === "string" && /^\d+\.\d+\.\d+$/.test(policy.version), `invalid data product consumer policy version: ${policy.id ?? "unknown"}`);
requireValue(typeof policy.dataProductId === "string" && /^[A-Za-z0-9._:-]{1,160}$/.test(policy.dataProductId), `invalid data product consumer policy product: ${policy.id ?? "unknown"}`);
@@ -90,7 +103,14 @@ for (const policy of consumerPolicies) {
requireValue(contract?.fieldTypes && typeof contract.fieldTypes === "object" && !Array.isArray(contract.fieldTypes), `invalid consumer field types: ${policy.id ?? "unknown"}`);
requireValue(JSON.stringify(Object.keys(contract?.fieldTypes ?? {})) === JSON.stringify(contract?.fieldProjection ?? []), `consumer field type order/scope mismatch: ${policy.id ?? "unknown"}`);
requireValue(Object.values(contract?.fieldTypes ?? {}).every((value) => ["string", "number", "boolean"].includes(value)), `invalid consumer field type: ${policy.id ?? "unknown"}`);
requireValue(JSON.stringify(contract?.geometryTypes) === JSON.stringify(["Polygon", "MultiPolygon"]), `invalid consumer geometry types: ${policy.id ?? "unknown"}`);
const supportedGeometryTypes = ["Point", "LineString", "Polygon", "MultiPolygon"];
requireValue(
Array.isArray(contract?.geometryTypes)
&& contract.geometryTypes.length <= supportedGeometryTypes.length
&& new Set(contract.geometryTypes).size === contract.geometryTypes.length
&& contract.geometryTypes.every((value) => supportedGeometryTypes.includes(value)),
`invalid consumer geometry types: ${policy.id ?? "unknown"}`,
);
requireValue(contract?.subjectIdentity === "semantic-type+source-id", `invalid consumer subject identity: ${policy.id ?? "unknown"}`);
requireValue(contract?.snapshotMode === "atomic-replace" && contract?.patchMode === "atomic", `invalid consumer commit modes: ${policy.id ?? "unknown"}`);
}
@@ -147,6 +167,44 @@ requireValue(JSON.stringify(zoneV2Policy?.consumerContract?.fieldProjection) ===
requireValue(JSON.stringify(zoneV2Policy?.consumerContract?.geometryTypes) === JSON.stringify(["Polygon", "MultiPolygon"]), "map.zones.current.v2 geometry contract must be Polygon/MultiPolygon");
requireValue(!/(provider|tenant|connection|endpoint|credential|token|secret|authorization)/i.test(JSON.stringify(zoneV2Policy)), "map.zones.current.v2 consumer policy crosses the transport/secret boundary");
const unitProfileV1Policy = consumerPolicies.find((policy) => policy.dataProductId === "fleet.units.profile.current.v1" && policy.productVersion === "1.0.0");
const unitProfileV1Projection = [
"corrected_engine_hours_factor",
"corrected_mileage_factor",
"display_name",
"filter_by_satellite_count_enabled",
"filter_by_satellite_count_value",
"filter_emissions",
"hardware_manufacturer_name",
"hardware_port",
"hardware_type_class",
"hardware_type_name",
"limit_acceleration",
"lost_connection_enabled",
"lost_connection_time_value",
"maximum_permissible_speed",
"maximum_valid_height",
"maximum_valid_speed",
"mileage_by_ignition",
"minimum_movement_speed",
"minimum_movement_time",
"minimum_parking_time",
"minimum_stop_time",
"minimum_trip_distance",
"minimum_valid_height",
"speed_parameter",
"trip_detection_type",
"unit_type_class",
"unit_type_name",
"use_odometer",
];
requireValue(unitProfileV1Policy?.id === "map-moving-object-unit-profile-current-v1" && unitProfileV1Policy?.version === "1.0.0", "fleet.units.profile.current.v1 consumer policy is missing");
requireValue(unitProfileV1Policy?.freshness === "none" && unitProfileV1Policy?.staleAfterMs === null, "fleet.units.profile.current.v1 must not invent freshness states");
requireValue(JSON.stringify(unitProfileV1Policy?.consumerContract?.semanticTypes) === JSON.stringify(["map.moving_object"]), "fleet.units.profile.current.v1 semantic scope must be exact");
requireValue(JSON.stringify(unitProfileV1Policy?.consumerContract?.fieldProjection) === JSON.stringify(unitProfileV1Projection), "fleet.units.profile.current.v1 field projection must be exact");
requireValue(JSON.stringify(unitProfileV1Policy?.consumerContract?.geometryTypes) === JSON.stringify([]), "fleet.units.profile.current.v1 must remain a non-geometric aspect");
requireValue(!/(provider|tenant|endpoint|credential|token|secret|authorization)/i.test(JSON.stringify(unitProfileV1Policy)), "fleet.units.profile.current.v1 consumer policy crosses the transport/secret boundary");
const ids = components.components.map((component) => component.id);
requireValue(new Set(ids).size === ids.length, "component ids must be unique");
const candidateIds = candidates.candidates.map((component) => component.id);