feat(foundry): close the operational map data loop
This commit is contained in:
@@ -15,6 +15,8 @@ const applicationManifestSchema = await parse("registry/schemas/application-mani
|
||||
const designProfileSchema = await parse("registry/schemas/design-profile-v0.1.schema.json");
|
||||
const mapSceneFixtureSchema = await parse("registry/schemas/map-scene-fixture-v0.1.schema.json");
|
||||
const mapLodPolicySchema = await parse("registry/schemas/map-lod-policy-v0.1.schema.json");
|
||||
const mapPresentationProfiles = await parse("registry/map-presentation-profiles.json");
|
||||
const dataProductConsumerPolicies = await parse("registry/data-product-consumer-policies.json");
|
||||
|
||||
const failures = [];
|
||||
const requireValue = (condition, message) => {
|
||||
@@ -26,7 +28,13 @@ requireValue(registry.libraryVersion, "registry libraryVersion is required");
|
||||
requireValue(Array.isArray(registry.packages) && registry.packages.length >= 4, "registry must list all packages");
|
||||
requireValue(Array.isArray(sources.sources) && sources.sources.length >= 6, "source audit is incomplete");
|
||||
requireValue(Array.isArray(components.components) && components.components.length >= 10, "component registry is incomplete");
|
||||
requireValue(Array.isArray(candidates.candidates) && candidates.candidates.length >= 10, "candidate registry is incomplete");
|
||||
requireValue(Array.isArray(candidates.candidates) && candidates.candidates.length >= 1, "candidate registry is incomplete");
|
||||
requireValue(
|
||||
Array.isArray(components.components)
|
||||
&& Array.isArray(candidates.candidates)
|
||||
&& components.components.length + candidates.candidates.length >= 20,
|
||||
"component inventory is incomplete",
|
||||
);
|
||||
requireValue(Array.isArray(icons.groups) && icons.groups.length >= 5, "icon registry is incomplete");
|
||||
requireValue(pages.schemaVersion === "0.1.0", "page registry schemaVersion must be 0.1.0");
|
||||
requireValue(Array.isArray(pages.templates) && pages.templates.length >= 1, "page registry must contain at least one template");
|
||||
@@ -34,10 +42,48 @@ requireValue(registry.applicationManifestSchema === "schemas/application-manifes
|
||||
requireValue(registry.designProfileSchema === "schemas/design-profile-v0.1.schema.json", "design profile schema must be registered");
|
||||
requireValue(registry.mapSceneFixtureSchema === "schemas/map-scene-fixture-v0.1.schema.json", "map scene fixture schema must be registered");
|
||||
requireValue(registry.mapLodPolicySchema === "schemas/map-lod-policy-v0.1.schema.json", "map LOD policy schema must be registered");
|
||||
requireValue(registry.mapPresentationProfileRegistry === "map-presentation-profiles.json", "map presentation profile registry must be registered");
|
||||
requireValue(applicationManifestSchema.properties?.schemaVersion?.const === "0.1.0", "application manifest schema version must be 0.1.0");
|
||||
requireValue(designProfileSchema.properties?.schemaVersion?.const === "0.1.0", "design profile schema version must be 0.1.0");
|
||||
requireValue(mapSceneFixtureSchema.properties?.schemaVersion?.const === "0.1.0", "map scene fixture schema version must be 0.1.0");
|
||||
requireValue(mapLodPolicySchema.properties?.schemaVersion?.const === "0.1.0", "map LOD policy schema version must be 0.1.0");
|
||||
requireValue(mapPresentationProfiles.schemaVersion === "nodedc.map-presentation-profiles/v1", "map presentation profile registry schema is unsupported");
|
||||
requireValue(Array.isArray(mapPresentationProfiles.profiles) && mapPresentationProfiles.profiles.length >= 1, "map presentation profiles are missing");
|
||||
requireValue(dataProductConsumerPolicies.schemaVersion === "nodedc.foundry.data-product-consumer-policies/v1", "data product consumer policy registry schema is unsupported");
|
||||
requireValue(Array.isArray(dataProductConsumerPolicies.policies) && dataProductConsumerPolicies.policies.length >= 1, "data product consumer policies are missing");
|
||||
|
||||
const consumerPolicies = dataProductConsumerPolicies.policies ?? [];
|
||||
const consumerPolicyIds = consumerPolicies.map((policy) => `${policy.id}@${policy.version}`);
|
||||
const consumerPolicyProducts = consumerPolicies.map((policy) => `${policy.dataProductId}@${policy.productVersion}`);
|
||||
requireValue(new Set(consumerPolicyIds).size === consumerPolicyIds.length, "data product consumer policy id/version pairs must be unique");
|
||||
requireValue(new Set(consumerPolicyProducts).size === consumerPolicyProducts.length, "data product consumer policy product/version pairs must be unique");
|
||||
for (const policy of consumerPolicies) {
|
||||
const statusContract = policy.statusContract;
|
||||
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"}`);
|
||||
requireValue(typeof policy.productVersion === "string" && /^\d+\.\d+\.\d+$/.test(policy.productVersion), `invalid data product consumer product version: ${policy.id ?? "unknown"}`);
|
||||
requireValue(Array.isArray(policy.terminalStatuses) && policy.terminalStatuses.every((value) => typeof value === "string" && /^[a-z0-9_-]{1,64}$/.test(value)), `invalid terminal statuses: ${policy.id ?? "unknown"}`);
|
||||
requireValue(policy.removeMode === "canonical-tombstone-or-snapshot-rebase", `invalid remove mode: ${policy.id ?? "unknown"}`);
|
||||
if (statusContract === undefined) {
|
||||
requireValue(Number.isInteger(policy.staleAfterMs) && policy.staleAfterMs >= 1_000 && policy.staleAfterMs <= 7 * 24 * 60 * 60 * 1000, `invalid stale window: ${policy.id ?? "unknown"}`);
|
||||
continue;
|
||||
}
|
||||
requireValue(statusContract && typeof statusContract === "object" && !Array.isArray(statusContract), `invalid status contract: ${policy.id ?? "unknown"}`);
|
||||
requireValue(typeof statusContract?.attribute === "string" && /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(statusContract.attribute), `invalid status attribute: ${policy.id ?? "unknown"}`);
|
||||
requireValue(Array.isArray(statusContract?.allowedValues) && statusContract.allowedValues.length >= 1 && new Set(statusContract.allowedValues).size === statusContract.allowedValues.length, `invalid allowed status values: ${policy.id ?? "unknown"}`);
|
||||
requireValue(statusContract?.allowedValues?.every((value) => typeof value === "string" && /^[a-z0-9_-]{1,64}$/.test(value)), `invalid allowed status value: ${policy.id ?? "unknown"}`);
|
||||
requireValue(statusContract?.missing === "reject", `status contract must reject missing values: ${policy.id ?? "unknown"}`);
|
||||
requireValue(["none", "observed-at"].includes(statusContract?.freshness), `invalid status freshness mode: ${policy.id ?? "unknown"}`);
|
||||
requireValue(statusContract?.freshness === "none" ? policy.staleAfterMs === null : Number.isInteger(policy.staleAfterMs), `status freshness/stale window mismatch: ${policy.id ?? "unknown"}`);
|
||||
requireValue(policy.terminalStatuses.every((value) => statusContract.allowedValues.includes(value)), `terminal status is outside the closed value contract: ${policy.id ?? "unknown"}`);
|
||||
}
|
||||
|
||||
const movingObjectV4Policy = consumerPolicies.find((policy) => policy.dataProductId === "fleet.positions.current.v4" && policy.productVersion === "4.0.0");
|
||||
requireValue(movingObjectV4Policy?.id === "map-moving-object-current-v4", "fleet.positions.current.v4 consumer policy is missing");
|
||||
requireValue(movingObjectV4Policy?.statusContract?.attribute === "signal_state", "fleet.positions.current.v4 status source must be signal_state");
|
||||
requireValue(JSON.stringify(movingObjectV4Policy?.statusContract?.allowedValues) === JSON.stringify(["active", "inactive"]), "fleet.positions.current.v4 signal states must remain closed active/inactive");
|
||||
requireValue(movingObjectV4Policy?.statusContract?.freshness === "none" && movingObjectV4Policy?.staleAfterMs === null, "fleet.positions.current.v4 must not invent freshness states");
|
||||
|
||||
const ids = components.components.map((component) => component.id);
|
||||
requireValue(new Set(ids).size === ids.length, "component ids must be unique");
|
||||
|
||||
Reference in New Issue
Block a user