From a294c1d338ba4c20d66873d593d1c101e69c5a40 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 14 Sep 2026 11:08:12 +0200 Subject: feat(node): progress names the root under way and the roots waiting `IndexProgress` said "scanning, this many bytes of that many" and nothing more. A group's roots are walked one after another, so a second directory added during a large scan showed as the bar jumping back to 0 %. It now also carries the root being walked and its position in the roots table, the kind of walk (scan, rescan, reconcile, watch), file counts, and the roots waiting for the scan lock in order: queued by the initial scan, by a retarget, and by a plug; dropped when a root is removed. `GET /api/index-status` answers for every group at once, including a group still in its initial scan, so a client can show indexing on any page. It names roots: loopback only, like `current_dir`. `index_progress` and the handshake ack gain the same counters, still naming nothing (decision D3): the root is a position in the roots table the member already opened from the sealed index, and the queue is a count. The pusher keeps speaking while a root only waits for the lock. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01T6jPTeocXA1BePekdsgPya --- packages/meshbay-node/src/meshbay_node/daemon.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'packages/meshbay-node/src/meshbay_node/daemon.py') diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py index 932a90d..a43e3a3 100644 --- a/packages/meshbay-node/src/meshbay_node/daemon.py +++ b/packages/meshbay-node/src/meshbay_node/daemon.py @@ -1163,14 +1163,16 @@ class NodeDaemon: parameter (not a bare constant) only so a test can drive this loop without waiting on the real 2s cadence. """ - was_scanning = False + was_busy = False while True: await asyncio.sleep(interval) progress = indexer.progress - now_scanning = progress.scanning - if now_scanning or was_scanning: + # A root waiting for the scan lock is work the operator is owed a + # sight of, even in the gap where nothing is walking yet. + busy = progress.scanning or bool(progress.queued) + if busy or was_busy: self._push_index_progress(indexer.group_id, progress) - was_scanning = now_scanning + was_busy = busy def _push_index_progress(self, group_id: str, progress) -> None: if not self._webrtc: @@ -1181,7 +1183,9 @@ class NodeDaemon: # scan. Sealing it would buy an attacker's rough estimate of a library's # size and cost a key derivation and a decrypt per push. If a field that # names anything is ever added here, that trade is void and this message - # joins the other two. + # joins the other two. `kind` is one of four fixed words; the root under + # way is a position in the roots table the member already opened from + # the sealed index, and the roots waiting are a count, never names. msg = { "type": MNP.INDEX_PROGRESS, "v": MNP_VERSION, @@ -1189,6 +1193,11 @@ class NodeDaemon: "scanning": progress.scanning, "scanned_bytes": progress.scanned_bytes, "total_bytes": progress.total_bytes, + "files_done": progress.files_done, + "files_total": progress.files_total, + "kind": progress.kind, + "root_pos": progress.root_pos, + "queued": len(progress.queued), } pushed = 0 for session in list(self._webrtc._sessions.values()): -- cgit v1.2.3