import assert from "node:assert/strict"; import { mkdtemp, readFile, readdir, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; import { createFoundryDataProductConsumerManager } from "./foundry-data-product-consumer.mjs"; const target = { application: { id: "11111111-1111-4111-8111-111111111111" }, page: { id: "map" }, binding: { id: "fleet-current", dataProductId: "fleet.positions.current.v1", slotId: "points", delivery: "snapshot+patch", semanticTypes: ["map.moving_object"], fieldProjection: ["display_name", "operational_status"], }, }; function fact({ longitude = 37.61, observedAt = "2026-07-19T10:00:00.000Z" } = {}) { return { sourceId: "vehicle-001", semanticType: "map.moving_object", observedAt, receivedAt: observedAt, attributes: { display_name: "Vehicle 001", operational_status: "active" }, geometry: { type: "Point", coordinates: [longitude, 55.75] }, }; } function snapshot(cursor = "7", facts = [fact()]) { return { schemaVersion: "nodedc.data-product.snapshot/v1", dataProduct: { id: "fleet.positions.current.v1", version: "1.0.0" }, generatedAt: "2026-07-19T10:00:01.000Z", cursor, facts, }; } function patch(cursor, previousCursor, operations) { return { schemaVersion: "nodedc.data-product.patch/v1", dataProduct: { id: "fleet.positions.current.v1", version: "1.0.0" }, cursor, previousCursor, emittedAt: "2026-07-19T10:00:02.000Z", operations, }; } function sseResponse(value, signal, counters) { const encoder = new TextEncoder(); return new Response(new ReadableStream({ start(controller) { counters.open += 1; controller.enqueue(encoder.encode(`event: nodedc.data-product.patch.v1\ndata: ${JSON.stringify(value)}\n\n`)); const close = () => { counters.closed += 1; try { controller.close(); } catch { /* already closed */ } }; signal.addEventListener("abort", close, { once: true }); }, }), { status: 200, headers: { "content-type": "text/event-stream" } }); } async function waitUntil(check, label, timeoutMs = 2_000) { const deadline = Date.now() + timeoutMs; while (Date.now() < deadline) { if (await check()) return; await new Promise((resolve) => setTimeout(resolve, 10)); } throw new Error(`timeout:${label}`); } test("server-owned consumer persists cursor, shares streams, transitions stale and removes canonically", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-")); let nowMs = Date.parse("2026-07-19T10:00:10.000Z"); let currentSnapshot = snapshot(); const streamPatches = [ patch("8", "7", [{ op: "upsert", fact: fact({ longitude: 37.62 }) }]), patch("9", "8", [{ op: "remove", sourceId: "vehicle-001", semanticType: "map.moving_object", removedAt: "2026-07-19T10:01:30.000Z", reason: "tombstone", }]), ]; const counters = { catalog: 0, snapshot: 0, stream: 0, open: 0, closed: 0 }; const fetchImpl = async (input, options = {}) => { const url = new URL(input); assert.equal(options.headers.authorization, "Bearer ndc_edprb_test-reader-capability"); assert.equal(url.origin, "http://edp.test"); if (url.pathname.endsWith("/reader/data-products")) { counters.catalog += 1; return Response.json({ ok: true, dataProducts: [{ id: "fleet.positions.current.v1", version: "1.0.0", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], active: true, }], }); } if (url.pathname.endsWith("/snapshot")) { counters.snapshot += 1; return Response.json(currentSnapshot); } if (url.pathname.endsWith("/stream")) { counters.stream += 1; const next = streamPatches.shift(); assert.ok(next, "unexpected extra upstream stream"); assert.equal(url.searchParams.get("after"), next.previousCursor); return sseResponse(next, options.signal, counters); } throw new Error(`unexpected_url:${url}`); }; const sanitizeSnapshot = (value) => value; const sanitizePatch = (value) => value; const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => target, readReaderToken: async () => "ndc_edprb_test-reader-capability", resolvePolicy: (product) => ({ id: "map-moving-object-current-v1", version: "1.0.0", dataProductId: product.id, productVersion: product.version, staleAfterMs: 60_000, terminalStatuses: ["inactive", "no-position", "no_position"], removeMode: "canonical-tombstone-or-snapshot-rebase", }), sanitizeSnapshot, sanitizePatch, fetchImpl, now: () => nowMs, idleStopMs: 20, staleSweepMs: 10_000, reconnectMinMs: 10, reconnectMaxMs: 20, }); try { const input = { applicationId: target.application.id, pageId: target.page.id, bindingId: target.binding.id }; const plan = await manager.plan(input); assert.equal(plan.action, "create"); assert.match(plan.planId, /^fcp1_/); assert.equal(JSON.stringify(plan).includes("ndc_edprb_"), false); assert.equal(JSON.stringify(plan).includes("http://edp.test"), false); const applied = await manager.apply({ ...input, planId: plan.planId }); assert.equal(applied.consumer.cursor, "7"); assert.equal(applied.consumer.subjectCount, 1); assert.equal(applied.consumer.runtimeState, "idle"); const events = []; const first = await manager.subscribe({ ...target, after: "7" }, (event) => events.push(event)); const second = await manager.subscribe({ ...target, after: "7" }, (event) => events.push(event)); await waitUntil(async () => (await manager.status(input)).consumer.cursor === "8", "patch_cursor_8"); assert.equal(counters.stream, 1, "two viewers must share one upstream stream"); assert.equal((await manager.status(input)).consumer.subjectCount, 1); assert.equal(events.filter((event) => event.event === "nodedc.data-product.patch.v1").length, 2, "one committed patch is fanned out once per viewer"); nowMs = Date.parse("2026-07-19T10:01:30.001Z"); const stale = await manager.status(input); assert.equal(stale.consumer.subjects[0].status, "stale"); assert.equal(stale.consumer.metrics.staleTransitions, 1); first.release(); second.release(); await waitUntil(() => counters.closed === 1, "last_viewer_closes_upstream"); const removeEvents = []; const third = await manager.subscribe({ ...target, after: "8" }, (event) => removeEvents.push(event)); await waitUntil(async () => (await manager.status(input)).consumer.cursor === "9", "remove_cursor_9"); assert.equal((await manager.status(input)).consumer.subjectCount, 0); assert.equal((await manager.status(input)).consumer.metrics.canonicalRemovals, 1); assert.ok(removeEvents.some((event) => event.data?.operations?.some((operation) => operation.op === "remove"))); third.release(); await waitUntil(() => counters.closed === 2, "remove_stream_closed"); currentSnapshot = snapshot("9", []); const refreshPlan = await manager.plan(input); await manager.apply({ ...input, planId: refreshPlan.planId }); const empty = await manager.snapshot(target); assert.deepEqual(empty.facts, []); const rolledBack = await manager.rollback(input); assert.equal(rolledBack.snapshotPreserved, true); assert.equal(rolledBack.consumer.runtimeState, "stopped"); await assert.rejects(() => manager.snapshot(target), /data_product_consumer_stopped/); const stateFiles = await readdir(stateDir); assert.equal(stateFiles.length, 1); const persisted = await readFile(join(stateDir, stateFiles[0]), "utf8"); assert.equal(persisted.includes("ndc_edprb_"), false); assert.equal(persisted.includes("http://edp.test"), false); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } }); test("restart restores the committed cursor and transient stream errors preserve subjects", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-restart-")); const input = { applicationId: target.application.id, pageId: target.page.id, bindingId: target.binding.id }; let streamAttempts = 0; const fetchImpl = async (request, options = {}) => { const url = new URL(request); assert.equal(options.headers.authorization, "Bearer ndc_edprb_test-reader-capability"); if (url.pathname.endsWith("/reader/data-products")) { return Response.json({ ok: true, dataProducts: [{ id: "fleet.positions.current.v1", version: "1.0.0", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], active: true, }] }); } if (url.pathname.endsWith("/snapshot")) return Response.json(snapshot()); if (url.pathname.endsWith("/stream")) { streamAttempts += 1; return Response.json({ ok: false, error: "temporary_failure" }, { status: 503 }); } throw new Error(`unexpected_url:${url}`); }; const createManager = () => createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => target, readReaderToken: async () => "ndc_edprb_test-reader-capability", resolvePolicy: (product) => ({ id: "map-moving-object-current-v1", version: "1.0.0", dataProductId: product.id, productVersion: product.version, staleAfterMs: 60_000, terminalStatuses: ["inactive", "no-position", "no_position"], removeMode: "canonical-tombstone-or-snapshot-rebase", }), sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl, now: () => Date.parse("2026-07-19T10:00:10.000Z"), idleStopMs: 10, staleSweepMs: 10_000, reconnectMinMs: 10, reconnectMaxMs: 20, }); const first = createManager(); let second; try { const plan = await first.plan(input); await first.apply({ ...input, planId: plan.planId }); await first.shutdown(); second = createManager(); await second.resumePersisted(); const restored = await second.status(input); assert.equal(restored.consumer.cursor, "7"); assert.equal(restored.consumer.subjectCount, 1); const lease = await second.subscribe({ ...target, after: "7" }, () => undefined); await waitUntil(async () => (await second.status(input)).consumer.metrics.reconnects > 0, "transient_reconnect"); lease.release(); const afterFailure = await second.status(input); assert.equal(afterFailure.consumer.subjectCount, 1); assert.equal(afterFailure.consumer.cursor, "7"); assert.ok(streamAttempts >= 1); } finally { await first.shutdown(); await second?.shutdown(); await rm(stateDir, { recursive: true, force: true }); } }); test("exact apply can ensure a missing target-scoped reader grant without exposing it in the plan", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-grant-")); const input = { applicationId: target.application.id, pageId: target.page.id, bindingId: target.binding.id }; const product = { id: "fleet.positions.current.v1", version: "1.0.0", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], active: true, }; let grantReady = false; let ensureCount = 0; const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => target, readReaderToken: async () => grantReady ? "ndc_edprb_managed-reader-capability" : null, inspectReaderGrant: async () => ({ product, readerGrantAction: grantReady ? "reuse" : "ensure" }), ensureReaderGrant: async () => { ensureCount += 1; grantReady = true; return { ensured: true }; }, resolvePolicy: (resolvedProduct) => ({ id: "map-moving-object-current-v1", version: "1.0.0", dataProductId: resolvedProduct.id, productVersion: resolvedProduct.version, staleAfterMs: 60_000, terminalStatuses: ["inactive", "no-position", "no_position"], removeMode: "canonical-tombstone-or-snapshot-rebase", }), sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async (request, options = {}) => { assert.equal(options.headers.authorization, "Bearer ndc_edprb_managed-reader-capability"); assert.ok(new URL(request).pathname.endsWith("/snapshot")); return Response.json(snapshot()); }, }); try { const plan = await manager.plan(input); assert.equal(plan.configuration.readerGrantAction, "ensure"); assert.ok(plan.effects.includes("ensure-target-scoped-reader-grant")); assert.equal(JSON.stringify(plan).includes("capability"), false); const applied = await manager.apply({ ...input, planId: plan.planId }); assert.equal(ensureCount, 1); assert.equal(applied.consumer.subjectCount, 1); const refresh = await manager.plan(input); assert.equal(refresh.configuration.readerGrantAction, "reuse"); assert.equal(refresh.effects.includes("ensure-target-scoped-reader-grant"), false); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } }); test("Data Product replacement bootstraps a successor reader generation before revoking its predecessor", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-generation-")); const input = { applicationId: target.application.id, pageId: target.page.id, bindingId: target.binding.id }; let currentTarget = structuredClone(target); let failV2Snapshot = true; let failPredecessorRevoke = true; const grants = new Map([[1, "fleet.positions.current.v1"]]); const events = []; const product = (id) => ({ id, version: id.endsWith(".v2") ? "2.0.0" : "1.0.0", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], active: true, }); const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(currentTarget), readReaderToken: async (_applicationId, _pageId, _bindingId, generation = 1) => { return grants.has(generation) ? `ndc_edprb_generation-${generation}` : null; }, inspectReaderGrant: async (resolvedTarget, { generation = 1 } = {}) => { const desiredProductId = resolvedTarget.binding.dataProductId; return { product: product(desiredProductId), readerGrantAction: grants.get(generation) === desiredProductId ? "reuse" : "ensure", readerGrantGeneration: generation, }; }, ensureReaderGrant: async (resolvedTarget, { generation }) => { grants.set(generation, resolvedTarget.binding.dataProductId); events.push(`ensure-g${generation}`); return { ensured: true, generation }; }, revokeReaderGrant: async (_resolvedTarget, { generation }) => { if (generation === 1 && failPredecessorRevoke) { failPredecessorRevoke = false; events.push("revoke-g1-failed"); throw Object.assign(new Error("foundry_reader_grant_provisioner_unavailable"), { statusCode: 503 }); } grants.delete(generation); events.push(`revoke-g${generation}`); return { revoked: true, generation }; }, resolvePolicy: (resolvedProduct) => ({ id: resolvedProduct.id.endsWith(".v2") ? "map-moving-object-current-v2" : "map-moving-object-current-v1", version: resolvedProduct.version, dataProductId: resolvedProduct.id, productVersion: resolvedProduct.version, staleAfterMs: 60_000, terminalStatuses: ["inactive", "no-position", "no_position"], removeMode: "canonical-tombstone-or-snapshot-rebase", }), sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async (request, options = {}) => { const dataProductId = decodeURIComponent(new URL(request).pathname.split("/").at(-2)); const generation = Number(String(options.headers.authorization).match(/generation-(\d+)/)?.[1]); assert.equal(grants.get(generation), dataProductId); events.push(`snapshot-${dataProductId}-g${generation}`); if (dataProductId.endsWith(".v2") && failV2Snapshot) { throw Object.assign(new Error("data_product_runtime_unavailable"), { statusCode: 503 }); } return Response.json({ ...snapshot(dataProductId.endsWith(".v2") ? "20" : "10"), dataProduct: { id: dataProductId, version: dataProductId.endsWith(".v2") ? "2.0.0" : "1.0.0" }, }); }, idleStopMs: 10, staleSweepMs: 10_000, }); try { const createPlan = await manager.plan(input); assert.equal(createPlan.configuration.readerGrantGeneration, 1); const created = await manager.apply({ ...input, planId: createPlan.planId }); assert.equal(created.consumer.product.id, "fleet.positions.current.v1"); assert.equal(created.consumer.readerGrantGeneration, 1); currentTarget.binding.dataProductId = "fleet.positions.current.v2"; currentTarget.binding.fieldProjection = [ "display_name", "availability_state", "motion_state", "position_state", "freshness_state", ]; const replacePlan = await manager.plan(input); assert.equal(replacePlan.action, "replace"); assert.equal(replacePlan.configuration.readerGrantAction, "ensure"); assert.equal(replacePlan.configuration.readerGrantGeneration, 2); assert.ok(replacePlan.effects.includes("ensure-successor-target-scoped-reader-grant")); await assert.rejects( manager.apply({ ...input, planId: replacePlan.planId }), /data_product_runtime_unavailable/, ); const preserved = await manager.status(input); assert.equal(preserved.consumer.product.id, "fleet.positions.current.v1"); assert.equal(preserved.consumer.readerGrantGeneration, 1); assert.equal(grants.get(1), "fleet.positions.current.v1"); assert.equal(grants.get(2), "fleet.positions.current.v2"); assert.equal(events.includes("revoke-g1"), false); failV2Snapshot = false; const retryPlan = await manager.plan(input); assert.equal(retryPlan.configuration.readerGrantGeneration, 2); await assert.rejects( manager.apply({ ...input, planId: retryPlan.planId }), /foundry_reader_grant_provisioner_unavailable/, ); const pendingFinalization = await manager.status(input); assert.equal(pendingFinalization.consumer.product.id, "fleet.positions.current.v2"); assert.equal(pendingFinalization.consumer.readerGrantGeneration, 2); assert.equal(grants.has(1), true); const finalizePlan = await manager.plan(input); assert.equal(finalizePlan.action, "finalize-reader-grant-rotation"); assert.equal(finalizePlan.effects.includes("bootstrap-scoped-snapshot"), false); assert.ok(finalizePlan.effects.includes("revoke-predecessor-reader-grant")); const replaced = await manager.apply({ ...input, planId: finalizePlan.planId }); assert.equal(replaced.consumer.product.id, "fleet.positions.current.v2"); assert.equal(replaced.consumer.readerGrantGeneration, 2); assert.equal(grants.has(1), false); assert.equal(grants.get(2), "fleet.positions.current.v2"); assert.ok(events.lastIndexOf("snapshot-fleet.positions.current.v2-g2") < events.indexOf("revoke-g1")); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } }); const movingObjectV4Policy = { id: "map-moving-object-current-v4", version: "4.0.0", dataProductId: "fleet.positions.current.v4", productVersion: "4.0.0", staleAfterMs: null, terminalStatuses: ["inactive"], statusContract: { attribute: "signal_state", allowedValues: ["active", "inactive"], missing: "reject", freshness: "none", }, removeMode: "canonical-tombstone-or-snapshot-rebase", }; const movingObjectV4Product = { id: "fleet.positions.current.v4", version: "4.0.0", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], active: true, }; function movingObjectV4Target(fieldProjection = ["display_name", "signal_state", "movement_state", "speed_kph"]) { return { application: { id: "44444444-4444-4444-8444-444444444444" }, page: { id: "map" }, binding: { id: "fleet-current-v4", dataProductId: movingObjectV4Product.id, slotId: "points", delivery: "snapshot+patch", semanticTypes: ["map.moving_object"], fieldProjection, }, }; } function movingObjectV4Snapshot(signalState = "active") { return { schemaVersion: "nodedc.data-product.snapshot/v1", dataProduct: { id: movingObjectV4Product.id, version: movingObjectV4Product.version }, generatedAt: "2026-07-20T12:00:01.000Z", cursor: "40", facts: [{ sourceId: "gelios-unit-001", semanticType: "map.moving_object", observedAt: "2026-01-01T00:00:00.000Z", receivedAt: "2026-07-20T12:00:00.000Z", attributes: { display_name: "Unit 001", signal_state: signalState, movement_state: "stopped", speed_kph: 0, }, geometry: { type: "Point", coordinates: [37.61, 55.75] }, }], }; } test("v4 consumer preserves the closed signal and movement states without inventing freshness", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-v4-")); const currentTarget = movingObjectV4Target(); let signalState = "active"; const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(currentTarget), readReaderToken: async () => "ndc_edprb_v4-reader-capability", inspectReaderGrant: async () => ({ product: movingObjectV4Product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => movingObjectV4Policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async (request, options = {}) => { assert.equal(options.headers.authorization, "Bearer ndc_edprb_v4-reader-capability"); assert.ok(new URL(request).pathname.endsWith("/snapshot")); return Response.json(movingObjectV4Snapshot(signalState)); }, now: () => Date.parse("2026-07-20T12:00:10.000Z"), }); try { const input = { applicationId: currentTarget.application.id, pageId: currentTarget.page.id, bindingId: currentTarget.binding.id }; const plan = await manager.plan(input); assert.deepEqual(plan.configuration.policy.statusContract.allowedValues, ["active", "inactive"]); assert.equal(plan.configuration.policy.staleAfterMs, null); const active = await manager.apply({ ...input, planId: plan.planId }); assert.equal(active.consumer.subjects[0].status, "active"); assert.equal(active.consumer.metrics.staleTransitions, 0); assert.equal((await manager.snapshot(currentTarget)).facts[0].attributes.movement_state, "stopped"); signalState = "inactive"; const refreshPlan = await manager.plan(input); const inactive = await manager.apply({ ...input, planId: refreshPlan.planId }); assert.equal(inactive.consumer.subjects[0].status, "inactive"); assert.equal(inactive.consumer.metrics.staleTransitions, 0); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } }); test("v4 consumer rejects bindings that omit signal_state and snapshots outside the closed contract", async () => { const omittedStateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-v4-omitted-")); const omittedTarget = movingObjectV4Target(["display_name", "movement_state"]); const omittedManager = createFoundryDataProductConsumerManager({ stateDir: omittedStateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(omittedTarget), readReaderToken: async () => "ndc_edprb_v4-reader-capability", inspectReaderGrant: async () => ({ product: movingObjectV4Product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => movingObjectV4Policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, }); try { await assert.rejects( omittedManager.plan({ applicationId: omittedTarget.application.id, pageId: omittedTarget.page.id, bindingId: omittedTarget.binding.id }), /data_product_consumer_status_field_not_projected/, ); } finally { await omittedManager.shutdown(); await rm(omittedStateDir, { recursive: true, force: true }); } const invalidStateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-v4-invalid-")); const invalidTarget = movingObjectV4Target(); const invalidManager = createFoundryDataProductConsumerManager({ stateDir: invalidStateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(invalidTarget), readReaderToken: async () => "ndc_edprb_v4-reader-capability", inspectReaderGrant: async () => ({ product: movingObjectV4Product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => movingObjectV4Policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async () => Response.json(movingObjectV4Snapshot("unknown")), }); try { const input = { applicationId: invalidTarget.application.id, pageId: invalidTarget.page.id, bindingId: invalidTarget.binding.id }; const plan = await invalidManager.plan(input); await assert.rejects( invalidManager.apply({ ...input, planId: plan.planId }), /data_product_consumer_fact_status_invalid/, ); const failed = await invalidManager.status(input); assert.equal(failed.consumer.runtimeState, "error"); assert.equal(failed.consumer.subjectCount, 0); } finally { await invalidManager.shutdown(); await rm(invalidStateDir, { recursive: true, force: true }); } }); const zoneV2Projection = [ "display_name", "geometry_kind", "max_speed_kph", "schedule_timezone", "applies_to_couriers", "applies_to_kicksharing", ]; const zoneV2Policy = { id: "map-zone-current-v2", version: "2.0.0", dataProductId: "map.zones.current.v2", productVersion: "2.0.0", freshness: "none", staleAfterMs: null, terminalStatuses: [], consumerContract: { ontologyRevision: "ontology.map.zone.v1", deliveryMode: "snapshot+patch", semanticTypes: ["map.zone"], fieldProjection: zoneV2Projection, fieldTypes: { display_name: "string", geometry_kind: "string", max_speed_kph: "number", schedule_timezone: "string", applies_to_couriers: "boolean", applies_to_kicksharing: "boolean", }, geometryTypes: ["Polygon", "MultiPolygon"], subjectIdentity: "semantic-type+source-id", snapshotMode: "atomic-replace", patchMode: "atomic", }, removeMode: "canonical-tombstone-or-snapshot-rebase", }; const zoneV2Product = { id: "map.zones.current.v2", version: "2.0.0", ontologyRevision: "ontology.map.zone.v1", deliveryMode: "snapshot+patch", semanticTypes: ["map.zone"], fields: [...zoneV2Projection, "geometry", "source_revision"], fieldContracts: { display_name: { type: "string", required: true }, geometry_kind: { type: "string", required: true }, max_speed_kph: { type: "number", required: false }, schedule_timezone: { type: "string", required: false }, applies_to_couriers: { type: "boolean", required: false }, applies_to_kicksharing: { type: "boolean", required: false }, geometry: { type: "geometry", required: true }, }, active: true, }; function zoneV2Target(fieldProjection = zoneV2Projection) { return { application: { id: "55555555-5555-4555-8555-555555555555" }, page: { id: "map" }, binding: { id: "depttrans-pmd-slow-zones", dataProductId: zoneV2Product.id, slotId: "zones", delivery: "snapshot+patch", semanticTypes: ["map.zone"], fieldProjection: [...fieldProjection], }, }; } function zoneFact({ sourceId = "depttrans-zone-001", geometryType = "Polygon", maxSpeedKph = 20 } = {}) { const polygon = [[[37.60, 55.75], [37.61, 55.75], [37.61, 55.76], [37.60, 55.75]]]; return { sourceId, semanticType: "map.zone", observedAt: "2026-07-21T10:00:00.000Z", receivedAt: "2026-07-21T10:00:01.000Z", attributes: { display_name: "Slow zone 001", geometry_kind: "polygon", max_speed_kph: maxSpeedKph, schedule_timezone: "Europe/Moscow", applies_to_couriers: true, applies_to_kicksharing: true, }, geometry: geometryType === "MultiPolygon" ? { type: "MultiPolygon", coordinates: [polygon] } : geometryType === "Polygon" ? { type: "Polygon", coordinates: polygon } : { type: geometryType, coordinates: [37.61, 55.75] }, }; } function zoneSnapshot({ cursor = "903", version = "2.0.0", facts = [zoneFact()] } = {}) { return { schemaVersion: "nodedc.data-product.snapshot/v1", dataProduct: { id: zoneV2Product.id, version }, generatedAt: "2026-07-21T10:00:02.000Z", cursor, facts, }; } function zonePatch(cursor, previousCursor, operations, version = "2.0.0") { return { schemaVersion: "nodedc.data-product.patch/v1", dataProduct: { id: zoneV2Product.id, version }, cursor, previousCursor, emittedAt: "2026-07-21T10:00:03.000Z", operations, }; } test("zone v2 consumer pins provider-neutral contract and commits Polygon/MultiPolygon patches by stable subject identity", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-zone-v2-")); const currentTarget = zoneV2Target(); const streamCounters = { open: 0, closed: 0 }; const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(currentTarget), readReaderToken: async () => "ndc_edprb_zone-reader-capability", inspectReaderGrant: async () => ({ product: zoneV2Product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => zoneV2Policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async () => Response.json(zoneSnapshot()), openStream: async ({ signal }) => sseResponse( zonePatch("904", "903", [{ op: "upsert", fact: zoneFact({ geometryType: "MultiPolygon", maxSpeedKph: 15 }) }]), signal, streamCounters, ), now: () => Date.parse("2026-07-21T10:00:10.000Z"), idleStopMs: 10, reconnectMinMs: 10, reconnectMaxMs: 20, }); try { const input = { applicationId: currentTarget.application.id, pageId: currentTarget.page.id, bindingId: currentTarget.binding.id }; const plan = await manager.plan(input); assert.equal(plan.configuration.product.version, "2.0.0"); assert.deepEqual(plan.configuration.policy.consumerContract.semanticTypes, ["map.zone"]); assert.deepEqual(plan.configuration.policy.consumerContract.fieldProjection, zoneV2Projection); assert.deepEqual(plan.configuration.policy.consumerContract.geometryTypes, ["Polygon", "MultiPolygon"]); assert.equal(JSON.stringify(plan).includes("http://edp.test"), false); assert.equal(JSON.stringify(plan).includes("ndc_edprb_"), false); const applied = await manager.apply({ ...input, planId: plan.planId }); assert.equal(applied.consumer.cursor, "903"); assert.equal(applied.consumer.subjectCount, 1); assert.equal(applied.consumer.subjects[0].subjectId, "depttrans-zone-001"); assert.equal(applied.consumer.subjects[0].status, "active"); assert.equal(applied.consumer.metrics.staleTransitions, 0); const lease = await manager.subscribe({ ...currentTarget, after: "903" }, () => undefined); await waitUntil(async () => (await manager.status(input)).consumer.cursor === "904", "zone_patch_cursor_904"); const patched = await manager.snapshot(currentTarget); assert.equal(patched.facts.length, 1); assert.equal(patched.facts[0].sourceId, "depttrans-zone-001"); assert.equal(patched.facts[0].geometry.type, "MultiPolygon"); assert.equal(patched.facts[0].attributes.max_speed_kph, 15); assert.equal((await manager.status(input)).consumer.upstreamStreamCount, 1); lease.release(); await waitUntil(() => streamCounters.closed === 1, "zone_stream_closed"); await waitUntil(async () => (await manager.status(input)).consumer.runtimeState === "idle", "zone_stream_idle"); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 }); } }); test("zone v2 consumer fails closed on projection, product, envelope and geometry contract drift", async () => { const cases = [ { name: "projection", target: zoneV2Target(zoneV2Projection.slice(0, -1)), product: zoneV2Product, policy: zoneV2Policy, snapshot: zoneSnapshot(), planError: /data_product_consumer_contract_mismatch/, }, { name: "field-type", target: zoneV2Target(), product: { ...zoneV2Product, fieldContracts: { ...zoneV2Product.fieldContracts, max_speed_kph: { type: "string" } } }, policy: zoneV2Policy, snapshot: zoneSnapshot(), planError: /data_product_consumer_contract_mismatch/, }, { name: "product-version", target: zoneV2Target(), product: { ...zoneV2Product, version: "2.0.1" }, policy: zoneV2Policy, snapshot: zoneSnapshot({ version: "2.0.1" }), planError: /data_product_consumer_policy_not_found/, }, { name: "envelope-version", target: zoneV2Target(), product: zoneV2Product, policy: zoneV2Policy, snapshot: zoneSnapshot({ version: "2.0.1" }), applyError: /data_product_snapshot_product_mismatch/, }, { name: "point-geometry", target: zoneV2Target(), product: zoneV2Product, policy: zoneV2Policy, snapshot: zoneSnapshot({ facts: [zoneFact({ geometryType: "Point" })] }), applyError: /data_product_consumer_fact_contract_invalid/, }, ]; for (const variant of cases) { const stateDir = await mkdtemp(join(tmpdir(), `foundry-consumer-zone-v2-${variant.name}-`)); const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(variant.target), readReaderToken: async () => "ndc_edprb_zone-reader-capability", inspectReaderGrant: async () => ({ product: variant.product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => variant.policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async () => Response.json(variant.snapshot), }); const input = { applicationId: variant.target.application.id, pageId: variant.target.page.id, bindingId: variant.target.binding.id }; try { if (variant.planError) { await assert.rejects(manager.plan(input), variant.planError); continue; } const plan = await manager.plan(input); await assert.rejects(manager.apply({ ...input, planId: plan.planId }), variant.applyError); const failed = await manager.status(input); assert.equal(failed.consumer.subjectCount, 0); assert.equal(failed.consumer.runtimeState, "error"); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } } }); 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", ]; const unitProfileV1FieldTypes = { corrected_engine_hours_factor: "number", corrected_mileage_factor: "number", display_name: "string", filter_by_satellite_count_enabled: "boolean", filter_by_satellite_count_value: "number", filter_emissions: "number", hardware_manufacturer_name: "string", hardware_port: "number", hardware_type_class: "string", hardware_type_name: "string", limit_acceleration: "number", lost_connection_enabled: "boolean", lost_connection_time_value: "number", maximum_permissible_speed: "number", maximum_valid_height: "number", maximum_valid_speed: "number", mileage_by_ignition: "boolean", minimum_movement_speed: "number", minimum_movement_time: "number", minimum_parking_time: "number", minimum_stop_time: "number", minimum_trip_distance: "number", minimum_valid_height: "number", speed_parameter: "string", trip_detection_type: "string", unit_type_class: "string", unit_type_name: "string", use_odometer: "boolean", }; const unitProfileV1Policy = { id: "map-moving-object-unit-profile-current-v1", version: "1.0.0", dataProductId: "fleet.units.profile.current.v1", productVersion: "1.0.0", freshness: "none", staleAfterMs: null, terminalStatuses: [], consumerContract: { ontologyRevision: "ontology.map.moving_object.v3", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], fieldProjection: unitProfileV1Projection, fieldTypes: unitProfileV1FieldTypes, geometryTypes: [], subjectIdentity: "semantic-type+source-id", snapshotMode: "atomic-replace", patchMode: "atomic", }, removeMode: "canonical-tombstone-or-snapshot-rebase", }; const unitProfileV1Product = { id: "fleet.units.profile.current.v1", version: "1.0.0", ontologyRevision: "ontology.map.moving_object.v3", deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], fields: [...unitProfileV1Projection], fieldContracts: Object.fromEntries(unitProfileV1Projection.map((field) => [ field, { type: unitProfileV1FieldTypes[field], required: field === "display_name" }, ])), active: true, }; function unitProfileV1Target(fieldProjection = unitProfileV1Projection) { return { application: { id: "66666666-6666-4666-8666-666666666666" }, page: { id: "map" }, binding: { id: "trike-unit-profile", dataProductId: unitProfileV1Product.id, slotId: "points", delivery: "snapshot+patch", semanticTypes: ["map.moving_object"], fieldProjection: [...fieldProjection], }, }; } function unitProfileV1Fact({ geometry } = {}) { return { sourceId: "gelios-unit-501", semanticType: "map.moving_object", observedAt: "2026-07-23T06:28:52.000Z", receivedAt: "2026-07-23T06:28:53.000Z", attributes: { display_name: "501 B2", hardware_manufacturer_name: "Gelios", hardware_type_name: "Trike tracker", maximum_permissible_speed: 25, minimum_movement_speed: 3, use_odometer: true, }, ...(geometry === undefined ? {} : { geometry }), }; } function unitProfileV1Snapshot(facts = [unitProfileV1Fact()]) { return { schemaVersion: "nodedc.data-product.snapshot/v1", dataProduct: { id: unitProfileV1Product.id, version: unitProfileV1Product.version }, generatedAt: "2026-07-23T06:28:54.000Z", cursor: "107", facts, }; } test("non-geometric unit profile aspect is strictly typed and joins by stable subject identity", async () => { const stateDir = await mkdtemp(join(tmpdir(), "foundry-consumer-unit-profile-v1-")); const currentTarget = unitProfileV1Target(); const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(currentTarget), readReaderToken: async () => "ndc_edprb_profile-reader-capability", inspectReaderGrant: async () => ({ product: unitProfileV1Product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => unitProfileV1Policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async () => Response.json(unitProfileV1Snapshot()), }); const input = { applicationId: currentTarget.application.id, pageId: currentTarget.page.id, bindingId: currentTarget.binding.id }; try { const plan = await manager.plan(input); assert.deepEqual(plan.configuration.policy.consumerContract.geometryTypes, []); assert.deepEqual(plan.configuration.policy.consumerContract.fieldProjection, unitProfileV1Projection); const applied = await manager.apply({ ...input, planId: plan.planId }); assert.equal(applied.consumer.subjectCount, 1); assert.equal(applied.consumer.subjects[0].subjectId, "gelios-unit-501"); assert.equal(applied.consumer.subjects[0].status, "active"); const persisted = await manager.snapshot(currentTarget); assert.equal(persisted.facts[0].geometry, undefined); assert.equal(persisted.facts[0].attributes.hardware_type_name, "Trike tracker"); } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } }); test("non-geometric unit profile aspect fails closed on projection drift and injected geometry", async () => { const variants = [ { name: "projection", target: unitProfileV1Target(unitProfileV1Projection.slice(1)), snapshot: unitProfileV1Snapshot(), planError: /data_product_consumer_contract_mismatch/, }, { name: "geometry", target: unitProfileV1Target(), snapshot: unitProfileV1Snapshot([unitProfileV1Fact({ geometry: { type: "Point", coordinates: [37.61, 55.75] } })]), applyError: /data_product_consumer_fact_contract_invalid/, }, ]; for (const variant of variants) { const stateDir = await mkdtemp(join(tmpdir(), `foundry-consumer-unit-profile-v1-${variant.name}-`)); const manager = createFoundryDataProductConsumerManager({ stateDir, dataPlaneUrl: "http://edp.test", resolveTarget: async () => structuredClone(variant.target), readReaderToken: async () => "ndc_edprb_profile-reader-capability", inspectReaderGrant: async () => ({ product: unitProfileV1Product, readerGrantAction: "reuse", readerGrantGeneration: 1 }), resolvePolicy: () => unitProfileV1Policy, sanitizeSnapshot: (value) => value, sanitizePatch: (value) => value, fetchImpl: async () => Response.json(variant.snapshot), }); const input = { applicationId: variant.target.application.id, pageId: variant.target.page.id, bindingId: variant.target.binding.id }; try { if (variant.planError) { await assert.rejects(manager.plan(input), variant.planError); } else { const plan = await manager.plan(input); await assert.rejects(manager.apply({ ...input, planId: plan.planId }), variant.applyError); } } finally { await manager.shutdown(); await rm(stateDir, { recursive: true, force: true }); } } });