<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-node/tests/test_replug_restores_enrichment.py, branch 0.14</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.14</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.14'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-07T01:13:14Z</updated>
<entry>
<title>fix(node): carry enrichment across a rescan instead of re-deriving it</title>
<updated>2026-09-07T01:13:14Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-07T01:13:14Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=eeda274d751c537f4ecef3087994a16a9517478f'/>
<id>urn:sha1:eeda274d751c537f4ecef3087994a16a9517478f</id>
<content type='text'>
e1dbdf0 made a replugged root re-enrich, which was correct and not enough:
the operator still watched their albums vanish. Measured on the reported
library with a cold metadata cache, the node broadcast twice — the first
delta stripped every album, the second put them back 14 seconds later.
Fourteen seconds of "no music found" is the bug, whatever happens after.

An entry's id is its content hash, so an entry that comes back under the
same id, name and path is the same bytes in the same place and everything
enrichment derived from it still holds. `_rescan_root` now carries those
fields across the drop-and-rescan that `reconcile` and `plug_root` share.
Re-enrichment stays as the fallback for what genuinely changed: a
different id is different content, and a different name or path can change
the folder and filename fallbacks that artist, album, display_title and
track_no rest on, so those entries are still handed to the daemon through
`rescanned_ids`.

`uploader_id`/`uploader_pk` ride along. They are the same shape of field —
set once on an entry, readable from nowhere on disk — and they decide who
may delete the file, so losing them to a replug quietly took a right away.

Verified on the running node: one broadcast 550ms after the plug, carrying
the albums, and no metadata lookups at all.

The tests now assert the field on the entry rather than a call to an
enricher. Counting calls is what let the previous version of this file pass
while the operator still saw an empty tab.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_011pvMdvLBG92jyhvD5pD6us
</content>
</entry>
<entry>
<title>fix(node): a replugged root came back without its metadata</title>
<updated>2026-09-07T00:26:17Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-07T00:26:17Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=e1dbdf0b7bebc27c2da7ae0c7095c5f88d4e1967'/>
<id>urn:sha1:e1dbdf0b7bebc27c2da7ae0c7095c5f88d4e1967</id>
<content type='text'>
Reported live: a removable root ejected from Files and plugged back in
returned with its files and without its albums. Music showed "no music
found" and stayed there through a force reload — the loss was on the
node, not in the client.

`plug_root` drops the root's entries and rescans, which is right; the
drive may have changed while it was away. What comes back is a bare
IndexEntry: `_hash_or_cached` fills id/name/path/size/type and nothing
else. Every enrichment field goes with the old object, and the Music tag
fields are cached nowhere by design (enrich_audio.py re-reads them so a
rename can re-derive the filename fallback), so re-enrichment is the only
way back.

Two gates then made sure it never ran:

  * enrichment is scheduled for `delta.additions`, and ejecting broadcasts
    nothing, so `_last_broadcast_snapshot` still held those ids — the
    rebuilt entries diffed as updates, not additions;
  * `_enrich_new_*_entries` skips anything in `_enriched_attempted`, which
    is only discarded for `delta.deletions` — and dropping and rescanning
    inside one call broadcasts no deletion either.

A restart cleared both, since an empty snapshot makes every entry an
addition. Nothing short of one did.

The indexer now records the ids it rebuilt and the daemon drains them at
broadcast time: their "already attempted" mark is discarded and they
rejoin the entries offered to the three enrichment passes. Not
Music-specific — Videos lost durations and titles and Photos lost
thumbnails the same way; Music is just where an untagged file has no
album to file itself under, so the app goes empty rather than plain.

`reconcile()` does the same drop-and-rescan when a root reappears on its
own, so a USB drive that fell off and re-mounted hit this with nobody
touching the UI. Covered too.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_011pvMdvLBG92jyhvD5pD6us
</content>
</entry>
</feed>
