feat(foundry): close the operational map data loop

This commit is contained in:
Codex
2026-07-20 20:45:05 +03:00
parent aac44d057f
commit a02c3ff3dd
44 changed files with 4158 additions and 811 deletions
@@ -334,3 +334,283 @@ test("exact apply can ensure a missing target-scoped reader grant without exposi
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 });
}
});