From 77615ddb5fead3e74751a94847d3bcc99fc0a96d Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Tue, 8 Sep 2026 23:43:46 +0200 Subject: fix(hub): the transfers row exists from the click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clicking Download produced nothing — no row, no icon, no panel — for as long as it took to open somewhere to write, and then several rows at once. The streamed path waits for the worker twice; a Save As dialog waits for a person. The row was created after that, so the slowest part of a download happened with nothing on screen to say it had begun. The store gains a `prepare` step, distinct from `run`, and the order is now: row, then target, then slot. That last part is why the obvious fix was wrong. Taking the slot first would let the row appear immediately, and it was tried this morning: a granted slot has to be taken up within the node's deadline, opening a target can outlast it, and three downloads became one. (The diagnosis at the time blamed that ordering for revocations which were in fact a missing `touch()` call — the revert was right for the wrong reason.) `makeLease` is called after `prepare` succeeds, never before. Three behaviours fall out, each with a test: - a dismissed dialog leaves nothing behind. `prepare` returning false drops the row: nothing started, so nothing should remain on screen to explain it; - the row takes the name the file was actually saved under, once known; - a refusal above the memory ceiling fails the row that is already there, rather than creating one to kill it. `preparing` counts as live everywhere — badge, cancel, clearFinished, and `_busy`, since closing a transport under a preparing transfer strands it exactly as under a queued one. Six places asked "is this finished?" and were drifting apart; there is one definition now. Two mistakes in the tests, worth the note: one counted positions in an output array by hand and was one out, which reads exactly like a failing assertion about the code — the values are tagged now, not indexed. And test_zip_size_limit.py's stub did not run `prepare`, so it no longer reached the size check the file is about; it now behaves like the real store. 819 hub, 1169 node, 0 failed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST --- packages/meshbay-hub/src/meshbay_hub/static/app.js | 23 +++- .../src/meshbay_hub/static/file-utils.js | 111 +++++++++----------- .../src/meshbay_hub/static/locales/de.js | 1 + .../src/meshbay_hub/static/locales/en.js | 1 + .../src/meshbay_hub/static/locales/es.js | 1 + .../src/meshbay_hub/static/locales/fr.js | 1 + .../src/meshbay_hub/static/locales/it.js | 1 + .../src/meshbay_hub/static/locales/ja.js | 1 + .../src/meshbay_hub/static/locales/nl.js | 1 + .../src/meshbay_hub/static/locales/pl.js | 1 + .../src/meshbay_hub/static/locales/pt-BR.js | 1 + .../src/meshbay_hub/static/locales/zh-CN.js | 1 + .../src/meshbay_hub/static/transfers.js | 90 ++++++++++++---- packages/meshbay-hub/tests/test_transfers.py | 116 +++++++++++++++++++++ packages/meshbay-hub/tests/test_zip_size_limit.py | 17 ++- 15 files changed, 280 insertions(+), 87 deletions(-) (limited to 'packages') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index ff066cf..6f4bb92 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -157,9 +157,11 @@ function TransferWidget() { }, [open]); const running = items.filter(i => i.status === 'running'); - const waiting = items.filter(i => i.status === 'queued'); + const waiting = items.filter( + i => i.status === 'queued' || i.status === 'preparing'); const finished = items.filter( - i => i.status !== 'running' && i.status !== 'queued'); + i => i.status !== 'running' && i.status !== 'queued' + && i.status !== 'preparing'); const active = running.length + waiting.length; // Grouped, and in this order: what is moving, what is waiting, what is over. @@ -240,7 +242,8 @@ function TransferRow({ it }) { ? html` { e.preventDefault(); transfers.open(it.id); }}>${it.name}` : html`${it.name}`} - ${(it.status === 'running' || it.status === 'queued') && html` + ${(it.status === 'running' || it.status === 'queued' + || it.status === 'preparing') && html`