feat(provider-contract): add classified unit contact aspect

This commit is contained in:
Codex
2026-07-24 09:31:34 +03:00
parent f02a1d4125
commit eab47bc1fa
10 changed files with 501 additions and 31 deletions
@@ -9,9 +9,10 @@ export const L2_EXECUTION_PLAN_SCHEMA_VERSION = "nodedc.l2-execution-plan/v1";
export const L2_GRAPH_BLUEPRINT_SCHEMA_VERSION = "nodedc.l2-graph-blueprint/v1";
export const L2_MATERIALIZATION_RECEIPT_SCHEMA_VERSION = "nodedc.l2-materialization-receipt/v1";
export const L2_MAPPING_RUNTIME_SCHEMA_VERSION = "nodedc.semantic-mapping-runtime/v1";
export const L2_EXECUTION_PLAN_COMPILER_VERSION = "1.2.0";
export const L2_EXECUTION_PLAN_COMPILER_VERSION = "1.3.0";
export const L2_EXECUTION_PLAN_SUPPORTED_COMPILER_VERSIONS = Object.freeze([
"1.1.0",
"1.2.0",
L2_EXECUTION_PLAN_COMPILER_VERSION,
]);
@@ -86,7 +87,10 @@ export function compileL2ExecutionPlan(providerPackage, connectionInstance, opti
mappingContractDigest: canonicalDigest(mapping),
fieldPolicyDigest: canonicalDigest(fieldPolicy),
dataProductDigest: canonicalDigest(dataProduct),
...(telemetryProjection ? { telemetryRegistryDigest: telemetryProjection.registry.digest } : {}),
...(telemetryProjection ? {
telemetryRegistryDigest: telemetryProjection.registry.digest,
telemetryProjectionDigest: canonicalDigest(telemetryProjection),
} : {}),
};
const steps = template.steps.map((step) => compileStep({
@@ -140,7 +140,7 @@ const MAPPING_TARGET_KEYS = new Set(["dataProductId", "version", "ontologyRevisi
const FACT_KEYS = new Set(["sourceId", "semanticType", "observedAt", "geometry", "attributes"]);
const EXPRESSION_KEYS = new Set([
"strategy", "paths", "coerce", "prefix", "fallback", "constant", "derive",
"omitIfMissing", "omitIfInvalid", "minimum", "maximum",
"omitIfMissing", "omitIfInvalid", "minimum", "maximum", "guardPath", "guardEquals",
]);
const GEOMETRY_KEYS = new Set([
"type", "longitude", "latitude", "strategy", "paths", "allowedTypes", "omitIfInvalid",
@@ -1013,6 +1013,18 @@ function validateExpression(value, path, errors) {
if (value.derive !== undefined) requiredIdentifier(value.derive, `${path}.derive`, errors);
if (value.omitIfMissing !== undefined && typeof value.omitIfMissing !== "boolean") errors.push(`${path}.omitIfMissing_must_be_boolean`);
if (value.omitIfInvalid !== undefined && typeof value.omitIfInvalid !== "boolean") errors.push(`${path}.omitIfInvalid_must_be_boolean`);
const hasGuardPath = value.guardPath !== undefined;
const hasGuardEquals = value.guardEquals !== undefined;
if (hasGuardPath !== hasGuardEquals) errors.push(`${path}.guard_requires_path_and_equals`);
if (hasGuardPath) {
if (!isCanonicalSourcePath(value.guardPath)) {
errors.push(`${path}.guardPath_must_be_canonical_dot_path`);
}
if (!["string", "number", "boolean"].includes(typeof value.guardEquals)) {
errors.push(`${path}.guardEquals_must_be_scalar`);
}
if (value.omitIfMissing !== true) errors.push(`${path}.guard_requires_omitIfMissing`);
}
if (value.minimum !== undefined || value.maximum !== undefined) {
if (value.coerce !== "number") errors.push(`${path}.range_requires_number_coercion`);
if (value.minimum !== undefined && !Number.isFinite(value.minimum)) errors.push(`${path}.minimum_invalid`);