Fix tape nav rerender loop
This commit is contained in:
parent
5d8e5ea44a
commit
b44eaf83bf
3 changed files with 35 additions and 1 deletions
|
|
@ -1,3 +1,4 @@
|
|||
{"_type":"issue","id":"islandflow-zuf","title":"Fix Home to Tape tab navigation freeze","description":"Home-to-Tape navigation becomes unresponsive because TerminalAppShell enters a live-mode rerender loop. The pinned-evidence prune effect writes new Map instances even when contents are unchanged, which can retrigger state updates indefinitely on the Home route where alert evidence prefetch is active. Make pruning idempotent and add regression coverage.\n","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-13T15:05:56Z","created_by":"dirtydishes","updated_at":"2026-05-13T15:08:01Z","started_at":"2026-05-13T15:06:06Z","closed_at":"2026-05-13T15:08:01Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"_type":"issue","id":"islandflow-9ug","title":"Electron desktop shell for hosted Islandflow","description":"Build a macOS-first Electron desktop shell workspace that loads hosted Islandflow in a locked-down BrowserWindow, adds Bun-first dev/package scripts, documents the workflow, and preserves the existing remote API/WS contract.\n","status":"closed","priority":1,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-13T13:11:40Z","created_by":"dirtydishes","updated_at":"2026-05-13T13:20:57Z","started_at":"2026-05-13T13:12:03Z","closed_at":"2026-05-13T13:20:57Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"_type":"issue","id":"islandflow-sh1","title":"Fix live websocket stale lag and reconnect loop","description":"Investigate and fix API live consumer lag causing stale timestamps, feed-behind status, and reconnect loops. Optimize live cache persistence path, add lag telemetry/alerts, and validate in runtime.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-04T17:04:34Z","created_by":"dirtydishes","updated_at":"2026-05-04T17:09:44Z","started_at":"2026-05-04T17:04:38Z","closed_at":"2026-05-04T17:09:44Z","close_reason":"Completed: optimized live cache persistence path, added lag telemetry, deployed api via docker compose on di, verified ws freshness and low hotFeedLagMs","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
{"_type":"issue","id":"islandflow-b3o","title":"Implement options tape table with execution spot","description":"Redesign OptionsPane into a dense classifier-colored table and preserve execution-time underlying spot on option prints from equity quote mid.","status":"closed","priority":1,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-04T04:41:59Z","created_by":"dirtydishes","updated_at":"2026-05-04T05:14:26Z","started_at":"2026-05-04T04:42:08Z","closed_at":"2026-05-04T05:14:26Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
mergeNewestWithOverflow,
|
||||
normalizeAlertSeverity,
|
||||
nextFlowFilterPopoverState,
|
||||
prunePinnedEntries,
|
||||
projectPausableTapeState,
|
||||
reducePausableTapeData,
|
||||
shouldRetainLiveSnapshotHistory,
|
||||
|
|
@ -77,6 +78,20 @@ const makeAlert = (overrides: Record<string, unknown> = {}) =>
|
|||
...overrides
|
||||
}) as any;
|
||||
|
||||
describe("pinned evidence pruning", () => {
|
||||
it("returns the existing map when no entries need pruning", () => {
|
||||
const now = 50_000;
|
||||
const current = new Map([
|
||||
["flowpacket:1", { value: { id: "flowpacket:1" }, updatedAt: now - 500 }],
|
||||
["trace:2", { value: { id: "trace:2" }, updatedAt: now - 1_000 }]
|
||||
]);
|
||||
|
||||
const next = prunePinnedEntries(current, new Set(), now);
|
||||
|
||||
expect(next).toBe(current);
|
||||
});
|
||||
});
|
||||
|
||||
describe("live manifest", () => {
|
||||
it("includes only tape channels on /tape", () => {
|
||||
const filters = buildDefaultFlowFilters();
|
||||
|
|
|
|||
|
|
@ -1894,7 +1894,7 @@ const upsertPinnedEntries = <T,>(
|
|||
return next;
|
||||
};
|
||||
|
||||
const prunePinnedEntries = <T,>(
|
||||
export const prunePinnedEntries = <T,>(
|
||||
current: Map<string, PinnedEntry<T>>,
|
||||
activeKeys: Set<string>,
|
||||
now: number
|
||||
|
|
@ -1909,6 +1909,24 @@ const prunePinnedEntries = <T,>(
|
|||
|
||||
surviving.sort((a, b) => b[1].updatedAt - a[1].updatedAt);
|
||||
const trimmed = surviving.slice(0, PINNED_EVIDENCE_MAX_ITEMS);
|
||||
|
||||
if (trimmed.length === current.size) {
|
||||
let unchanged = true;
|
||||
let index = 0;
|
||||
for (const entry of current) {
|
||||
const next = trimmed[index];
|
||||
if (!next || next[0] !== entry[0] || next[1] !== entry[1]) {
|
||||
unchanged = false;
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if (unchanged) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
return new Map(trimmed);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue