2026-05-29 18:04 EDT Beads: islandflow-ggm Web terminal hardening

Harden Web Terminal UI States

The terminal UI now handles live and replay status, empty panes, clipped market data, and table semantics more reliably for real users, assistive technology, and unusual input values.

Summary

I hardened the main web terminal surface by adding accessible feed announcements, reusable empty-state markup, safer data cells for clipped values, and stronger table semantics on the busiest tape panes.

Changes Made

Context

Islandflow is an evidence console for live market investigation. The UI has to remain useful when feeds are stale, paused, empty, or carrying long contract identifiers and numeric values. Hardening here focused on making the existing dense terminal more robust without changing its visual identity.

Important Implementation Details

Relevant Diff Snippets

Diff snippets are presented in the format expected by diffs.com-style unified diff rendering. @pierre/diffs is installed in this repo, but it does not expose a CLI binary, so the relevant unified snippets are embedded directly.

diff --git a/apps/web/app/terminal.tsx b/apps/web/app/terminal.tsx
@@
+export const buildTapeStatusAnnouncement = ({
+  status,
+  replayTime,
+  replayComplete,
+  paused,
+  dropped,
+  mode
+}: Pick<TapeStatusProps, "status" | "replayTime" | "replayComplete" | "paused" | "dropped" | "mode">): string => {
+  const label = replayComplete ? "Replay Complete" : statusLabel(status, paused, mode);
+  const feedLabel = mode === "live" && label.toLowerCase().startsWith("feed ")
+    ? label.toLowerCase()
+    : `feed ${label.toLowerCase()}`;
+  const parts = [`${mode === "live" ? "Live" : "Replay"} ${feedLabel}`];
+  ...
+};
+
+const EmptyState = ({ children }: { children: ReactNode }) => (
+  <div className="empty" role="status" aria-live="polite">
+    {children}
+  </div>
+);

@@
-    <div className={`status-inline status-${status} ${mode === "replay" ? "status-replay" : ""}`.trim()}>
-      <span className="status-dot" />
+    <div
+      className={`status-inline status-${status} ${mode === "replay" ? "status-replay" : ""}`.trim()}
+      role="status"
+      aria-live="polite"
+      aria-label={announcement}
+    >
+      <span className="status-dot" aria-hidden="true" />
diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css
@@
 .data-table-cell {
   min-width: 0;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   font-size: 0.72rem;
+  unicode-bidi: plaintext;
 }

 .empty {
+  display: flex;
+  align-items: center;
+  min-height: 76px;
   padding: 18px;
   border-radius: 12px;
   border: 1px dashed var(--border);
   background: var(--bg-soft);
   color: var(--text-dim);
+  line-height: 1.4;
+  overflow-wrap: anywhere;
 }
diff --git a/apps/web/app/terminal.test.ts b/apps/web/app/terminal.test.ts
@@
+describe("tape status hardening", () => {
+  it("announces stale live feeds without relying on the colored dot", () => {
+    expect(
+      buildTapeStatusAnnouncement({
+        status: "stale",
+        replayTime: null,
+        replayComplete: false,
+        paused: false,
+        dropped: 0,
+        mode: "live"
+      })
+    ).toBe("Live feed behind");
+  });
+});

Expected Impact for End-Users

Traders and researchers should get a steadier terminal under imperfect feed conditions. Screen-reader users get explicit live and replay status changes, empty panes announce themselves clearly, and clipped market values are easier to inspect without widening the layout.

Validation

Issues, Limitations, and Mitigations

Follow-up Work

No additional Beads issue was required during this turn. A sensible future pass would extend the same DataCell and EmptyState treatment to Alerts, Smart Money, Dark Events, and the chart evidence lists.