fix(#2632): remove /api/loose-ends endpoint; drop refreshLooseEnds (address argus/mara review)

Both old endpoints removed. refreshLooseEnds() call sites cleaned up;
lastLooseEnds stays as empty [] for reconcileAskBinds (no-op now that
the loose-ends source is gone).
This commit is contained in:
iris 2026-07-22 17:44:52 +02:00 committed by mara
commit 88f17320b6
3 changed files with 3 additions and 79 deletions

View file

@ -839,23 +839,6 @@ window.marked = marked;
renderTodos([]);
}
}
// Loose-ends: fetched silently (background only) for reconcileAskBinds.
// Not displayed as a pill; provides the question/reminder/approval data
// the inline ask-form wiring needs.
async function refreshLooseEnds() {
try {
const resp = await fetch('api/loose-ends');
if (!resp.ok) {
renderLooseEnds([]);
return;
}
const data = await resp.json();
renderLooseEnds(data.loose_ends || []);
} catch (err) {
console.warn('loose-ends fetch failed', err);
renderLooseEnds([]);
}
}
/** Latest snapshot kept in module state so the pill click handler
* has fresh data to render into the panel without re-fetching. */
let lastTodos = [];
@ -933,15 +916,6 @@ window.marked = marked;
return wrap;
}
/** Loose-ends render: background-only (no pill). Keeps lastLooseEnds
* fresh for reconcileAskBinds (inline ask-form wiring). */
function renderLooseEnds(threads) {
lastLooseEnds = threads;
// Wire inline answer forms into any `ask → operator` rows
// waiting on a broker-assigned question id.
reconcileAskBinds();
}
/** Build the todos side-panel list. Each entry is a LooseEnd::Todo
* (subsystem, summary, source, age_seconds). */
function buildTodosList(todos) {
@ -1045,7 +1019,6 @@ window.marked = marked;
});
if (resp.ok) {
status.textContent = 'answered ✓';
refreshLooseEnds();
} else {
status.textContent = 'failed: ' + (await resp.text());
}
@ -1342,10 +1315,7 @@ window.marked = marked;
renderModelChip(s.model);
renderEffortChip(s.effort);
renderTokenUsage({ ctx: s.ctx_usage, cost: s.cost_usage });
// Open-threads: loose-ends (background, for reconcileAskBinds) and
// todos (displayed pill). Cold-load fetches both; turn_end refreshes
// them via the renderers below.
refreshLooseEnds();
// Todos pill: cold-load populate; turn_end refreshes via renderTodos.
refreshTodos();
// Skip the re-render if nothing structurally changed. The most
// common case is `online` polling itself — without this guard, the
@ -1477,11 +1447,7 @@ window.marked = marked;
slot._askQuestion = c._body;
d.appendChild(slot);
pendingAskBinds.push(slot);
// Mid-turn refresh — the standard `turn_end` refresh
// won't fire until the agent's turn finishes; we want
// the form to show up as soon as the ask lands.
if (!api.fromHistory) refreshLooseEnds();
else reconcileAskBinds();
if (api.fromHistory) reconcileAskBinds();
}
}
return d;
@ -1510,15 +1476,6 @@ window.marked = marked;
const sourceName = c.tool_use_id ? toolNameById.get(c.tool_use_id) : null;
const isMessageBearing = sourceName === 'mcp__hyperhive__recv';
// When an ask's tool_result lands the broker has just
// persisted the question with its assigned id. Refresh
// loose-ends so reconcileAskBinds finds the new entry and
// mounts the inline answer form under the rendered ask row.
// Skipped during history replay (the question's likely
// long-resolved; turn_end refresh on cold-load covers
// reconciliation).
if (sourceName === 'mcp__hyperhive__ask' && !api.fromHistory) {
refreshLooseEnds();
}
const trimmed = txt.replace(/\s+/g, ' ').trim();
const summaryBody = (() => {
if (!trimmed) return '(empty)';
@ -1738,8 +1695,6 @@ window.marked = marked;
openTurnsFromHistory = Math.max(0, openTurnsFromHistory - 1);
} else {
setBannerActive(false); setState('idle');
// Likely answered/asked/scheduled something — refresh both.
refreshLooseEnds();
refreshTodos();
}
const cls = ev.ok ? 'turn-end-ok' : 'turn-end-fail';