feat(platform): complete the Gelios external data loop
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
# Gelios provider package v5
|
||||
|
||||
Version 5 preserves the Ontology-exact monitoring logic from provider package
|
||||
v4 and publishes it through the immutable `fleet.positions.current.v4@4.0.0`
|
||||
contract.
|
||||
|
||||
The Data Product now declares a machine-enforced contract for every published
|
||||
field. In particular:
|
||||
|
||||
- `signal_state` is required and accepts only `active` or `inactive`;
|
||||
- `movement_state` is required and accepts only `moving` or `stopped`;
|
||||
- identity/presentation attributes are typed and required where the mapping
|
||||
must always produce them;
|
||||
- optional telemetry is type-checked and bounded where the physical domain has
|
||||
a stable lower or upper limit;
|
||||
- geometry remains optional, but when present it must be a valid GeoJSON Point.
|
||||
|
||||
The provider mapping is checked against the same contract before it can be
|
||||
packaged, and External Data Plane checks every publish at runtime. Existing
|
||||
v1-v3 products remain immutable and backward compatible.
|
||||
@@ -0,0 +1,9 @@
|
||||
export {
|
||||
GELIOS_POSITIONS_DATA_PRODUCT_ID,
|
||||
GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
|
||||
GELIOS_POSITIONS_ONTOLOGY_REVISION,
|
||||
GELIOS_PROVIDER_PACKAGE_ID,
|
||||
GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
GELIOS_UNIT_SOURCE_ID_PREFIX,
|
||||
geliosProviderPackageV5,
|
||||
} from "./package.mjs";
|
||||
@@ -0,0 +1,105 @@
|
||||
import { geliosProviderPackageV4 } from "../v4/package.mjs";
|
||||
|
||||
export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v5";
|
||||
export const GELIOS_PROVIDER_PACKAGE_VERSION = "5.0.0";
|
||||
export const GELIOS_POSITIONS_DATA_PRODUCT_ID = "fleet.positions.current.v4";
|
||||
export const GELIOS_POSITIONS_DATA_PRODUCT_VERSION = "4.0.0";
|
||||
export const GELIOS_POSITIONS_ONTOLOGY_REVISION = "ontology.map.moving_object.v3";
|
||||
export const GELIOS_UNIT_SOURCE_ID_PREFIX = "gelios-unit-";
|
||||
|
||||
const FIELD_POLICY_ID = "gelios.positions.current.fields.v4";
|
||||
const REALTIME_PROFILE_ID = "gelios.positions.current.realtime.v5";
|
||||
const MANUAL_PROFILE_ID = "gelios.positions.current.manual.v5";
|
||||
const MAPPING_ID = "gelios.units.to.fleet.positions.current.v5";
|
||||
const TEMPLATE_ID = "gelios.positions.current.l2.v5";
|
||||
|
||||
const value = structuredClone(geliosProviderPackageV4);
|
||||
const dataProduct = {
|
||||
id: GELIOS_POSITIONS_DATA_PRODUCT_ID,
|
||||
version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION,
|
||||
deliveryMode: "snapshot+patch",
|
||||
semanticTypes: ["map.moving_object"],
|
||||
fields: [...value.dataProducts[0].fields],
|
||||
fieldContracts: {
|
||||
course_degrees: { type: "number", required: false, minimum: 0, maximum: 360 },
|
||||
display_name: { type: "string", required: true },
|
||||
elevation_meters: { type: "number", required: false },
|
||||
geometry: { type: "point", required: false },
|
||||
hdop: { type: "number", required: false, minimum: 0 },
|
||||
horizontal_accuracy_meters: { type: "number", required: false, minimum: 0 },
|
||||
movement_state: { type: "string", required: true, enum: ["moving", "stopped"] },
|
||||
object_kind: { type: "string", required: true },
|
||||
position_source: { type: "string", required: true },
|
||||
satellite_count: { type: "number", required: false, minimum: 0 },
|
||||
signal_state: { type: "string", required: true, enum: ["active", "inactive"] },
|
||||
speed_kph: { type: "number", required: false, minimum: 0 },
|
||||
},
|
||||
history: { ...value.dataProducts[0].history },
|
||||
};
|
||||
|
||||
value.id = GELIOS_PROVIDER_PACKAGE_ID;
|
||||
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
value.manifest = {
|
||||
...value.manifest,
|
||||
id: "gelios.provider.manifest.v5",
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
fieldPolicyIds: [FIELD_POLICY_ID],
|
||||
collectionProfileIds: [REALTIME_PROFILE_ID, MANUAL_PROFILE_ID],
|
||||
dataProductIds: [GELIOS_POSITIONS_DATA_PRODUCT_ID],
|
||||
mappingContractIds: [MAPPING_ID],
|
||||
l2TemplateIds: [TEMPLATE_ID],
|
||||
};
|
||||
value.fieldPolicies = value.fieldPolicies.map((policy) => ({
|
||||
...policy,
|
||||
id: FIELD_POLICY_ID,
|
||||
version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
|
||||
dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
|
||||
}));
|
||||
value.collectionProfiles = value.collectionProfiles.map((profile, index) => ({
|
||||
...profile,
|
||||
id: index === 0 ? REALTIME_PROFILE_ID : MANUAL_PROFILE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
|
||||
mappingContractId: MAPPING_ID,
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
l2TemplateId: TEMPLATE_ID,
|
||||
}));
|
||||
value.dataProducts = [dataProduct];
|
||||
value.mappingContracts = value.mappingContracts.map((mapping) => ({
|
||||
...mapping,
|
||||
id: MAPPING_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
target: {
|
||||
...mapping.target,
|
||||
dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID,
|
||||
version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION,
|
||||
},
|
||||
}));
|
||||
const attributes = value.mappingContracts[0].fact.attributes;
|
||||
Object.assign(attributes.course_degrees, { minimum: 0, maximum: 360, omitIfInvalid: true });
|
||||
Object.assign(attributes.hdop, { minimum: 0, omitIfInvalid: true });
|
||||
Object.assign(attributes.horizontal_accuracy_meters, { minimum: 0, omitIfInvalid: true });
|
||||
Object.assign(attributes.satellite_count, { minimum: 0, omitIfInvalid: true });
|
||||
Object.assign(attributes.speed_kph, { minimum: 0, omitIfInvalid: true });
|
||||
value.l2Templates = value.l2Templates.map((template) => ({
|
||||
...template,
|
||||
id: TEMPLATE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
steps: template.steps.map((step) => {
|
||||
if (step.kind === "semantic_mapping") return { ...step, mappingContractId: MAPPING_ID };
|
||||
if (step.kind === "data_product_publish") return { ...step, dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID };
|
||||
return step;
|
||||
}),
|
||||
}));
|
||||
|
||||
export const geliosProviderPackageV5 = deepFreeze(value);
|
||||
|
||||
function deepFreeze(input) {
|
||||
if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
|
||||
Object.freeze(input);
|
||||
for (const child of Object.values(input)) deepFreeze(child);
|
||||
return input;
|
||||
}
|
||||
Reference in New Issue
Block a user