fix(control-pane): reject failed views and coalesce projection sampling

This commit is contained in:
Affaan Mustafa
2026-09-12 03:11:12 -04:00
parent ff03da1dc8
commit 5c2fbce26e
6 changed files with 122 additions and 9 deletions
+1 -1
View File
@@ -231,7 +231,7 @@ function projectPairs(links, options = {}) {
const minWindow = Number.isFinite(options.minWindowForZscore) ? options.minWindowForZscore : PROJECTION_DEFAULTS.minWindowForZscore;
const raw = list.map(l => channelVector(l.channels));
if (window) for (const vec of raw) window.push(vec);
if (window && options.sample !== false) for (const vec of raw) window.push(vec);
let stats = null;
let normalization = 'raw';
@@ -207,10 +207,13 @@ function renderControlPlaneViewHtml() {
}
function apply(data) {
view = data || view;
view.tasks = view.tasks || []; view.lanes = view.lanes || []; view.pairs = view.pairs || [];
view.events = view.events || []; view.projection = view.projection || { agents: [] };
view.thresholds = view.thresholds || { ta: 0.35, ra: 0.7 };
if (!data || data.schemaVersion !== 'ecc.control-plane.view.v1' ||
!['tasks', 'lanes', 'pairs', 'events'].every(function (key) { return Array.isArray(data[key]); }) ||
!data.projection || !Array.isArray(data.projection.agents) || !data.thresholds ||
!Number.isFinite(data.thresholds.ta) || !Number.isFinite(data.thresholds.ra)) {
throw new Error('Invalid control-plane view');
}
view = Object.assign({}, data);
renderEvents(); renderLanes(); draw();
var c = view.counts || {};
document.getElementById('status').textContent =
@@ -220,7 +223,10 @@ function renderControlPlaneViewHtml() {
}
function poll() {
fetch('/api/control-plane').then(function (r) { return r.json(); }).then(apply).catch(function () {
fetch('/api/control-plane').then(function (r) {
if (!r.ok) throw new Error('Control-plane request failed');
return r.json();
}).then(apply).catch(function () {
document.getElementById('status').textContent = 'offline';
});
}
+22 -2
View File
@@ -225,6 +225,7 @@ function buildControlPlaneView(snapshot, options = {}) {
const projection = projectPairs(prox.links || [], {
window: options.window,
channelWeights: options.channelWeights,
sample: options.sample,
minWindowForZscore: options.minWindowForZscore
});
const pointByAgent = new Map(projection.agents.map(a => [a.agentId, a]));
@@ -319,11 +320,30 @@ function buildControlPlaneView(snapshot, options = {}) {
*/
function createControlPlaneViewSource(deps = {}) {
const window = deps.window || createProjectionWindow(deps.projection || {});
const clock = deps.clock || Date.now;
const interval = deps.sampleIntervalMs === undefined ? 5000 : deps.sampleIntervalMs;
if (!Number.isFinite(interval) || interval <= 0) throw new Error('sampleIntervalMs must be positive and finite');
let cached = null;
let pending = null;
let expiresAt = 0;
async function refresh() {
const snapshot = await deps.buildSnapshot();
const view = buildControlPlaneView(snapshot, { ...deps.viewOptions, window });
cached = { snapshot, view };
expiresAt = clock() + interval;
return cached;
}
return {
window,
async build(extra = {}) {
const snapshot = await deps.buildSnapshot();
return buildControlPlaneView(snapshot, { ...deps.viewOptions, ...extra, window });
if (!cached || clock() >= expiresAt) {
if (!pending) pending = refresh().finally(() => { pending = null; });
await pending;
}
if (Object.keys(extra).length === 0) return cached.view;
return buildControlPlaneView(cached.snapshot, {
...deps.viewOptions, ...extra, now: extra.now || cached.view.generatedAt, window, sample: false
});
}
};
}