Stream graph rows over an IPC channel master
Rows are pushed to the frontend rather than returned page by page, and the push is bounded by a budget the frontend tops up as it scrolls. Credit-based flow control rather than request/response, because a plain request/response costs a round trip before anything can be drawn and leaves the backend unable to speak on its own — which is what pushing newly arrived commits into an open view will need later. The budget is what keeps a million-commit repository from flooding the boundary: the walk computes nothing beyond what has been asked for. Cancellation falls out of the design. A channel the webview has dropped makes the send fail, which ends the stream and drops the walk; closing the repository drops its actor, which drops the walk with it. There is nothing to clean up explicitly. One stream per repository — starting another replaces it, and the previous walk is dropped there. Twelve tests cover the flow control against the real streaming code: Channel takes a plain closure, so what the test observes is exactly what would have crossed the boundary. They pin the budget being respected, resuming without repeating or skipping a row, batches carrying their start index, the end of history being announced, a replaced stream going quiet while the new one continues, and asking for more after the end being a harmless no-op rather than an error. The TypeScript bindings are written by hand — the surface is small and a generator is another dependency to keep current. One of the Rust tests asserts the wire format matches the names in bindings.ts, so drift on one side fails on the other. Also suppresses unicorn/prefer-add-event-listener at the one place it misfires: Tauri's Channel is not an EventTarget, so onmessage is the only way to receive from it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>