From d427118bd91d67f1a041e5daf267aebcd34ca9d7 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Tue, 25 Aug 2026 00:29:24 +0200 Subject: fix(node): scope _enriched_attempted by group, not just content hash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major finding: entry.id is a content hash, so the exact same physical file — the same MP3, byte-for-byte — indexed into two different groups (a shared library reused across several demo/test groups, or genuinely the same folder shared into two groups) produces the *same id* in both. _enriched_attempted was a single flat set of bare ids shared across every group this node hosts. The moment one group's copy got enriched, every other group's otherwise-identical copy read as "already attempted" and was skipped forever — nothing else ever revisits an id once it's in this set. That group's Music tab (or Videos tab, same bug, same set) showed every affected file at duration 0 with no artist/album/thumbnail, permanently, no matter how long you waited or how many times you reloaded — group A having been enriched first was enough to silently starve every later group of the same content. Now keyed by (group_id, entry.id) throughout — the enrichment gate, the sweep, and the rename re-enrichment path, for both video and audio (they already shared the one set, and the collision risk is identical for both). New regression test constructs two groups with byte-identical audio content and confirms both enrich independently. --- packages/meshbay-node/tests/test_video_root_gates_enrichment.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/meshbay-node/tests/test_video_root_gates_enrichment.py') diff --git a/packages/meshbay-node/tests/test_video_root_gates_enrichment.py b/packages/meshbay-node/tests/test_video_root_gates_enrichment.py index df86a79..9cfb819 100644 --- a/packages/meshbay-node/tests/test_video_root_gates_enrichment.py +++ b/packages/meshbay-node/tests/test_video_root_gates_enrichment.py @@ -108,8 +108,8 @@ async def test_only_entries_under_the_configured_root_are_enriched(tmp_path): await asyncio.sleep(0.05) by_name = {e.name: e for e in indexer.index.entries} - assert by_name["in-root.mkv"].id in daemon._enriched_attempted - assert by_name["outside.mkv"].id not in daemon._enriched_attempted, ( + assert (group_id, by_name["in-root.mkv"].id) in daemon._enriched_attempted + assert (group_id, by_name["outside.mkv"].id) not in daemon._enriched_attempted, ( "a file outside the configured video_root must never be enriched") finally: await _teardown(daemon) @@ -146,7 +146,7 @@ async def test_setting_the_video_root_sweeps_what_it_already_contains(tmp_path): await asyncio.sleep(0.05) # let the fire-and-forget sweep actually run entry = next(iter(indexer.index.entries)) - assert entry.id in daemon._enriched_attempted, ( + assert (group_id, entry.id) in daemon._enriched_attempted, ( "a file already sitting in the newly-chosen root must be picked " "up by the sweep, not wait for some unrelated future change") finally: -- cgit v1.2.3