summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/daemon.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-19 02:12:47 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-19 02:12:47 +0200
commit20a824118c09af15d6c338db4c9480ffe5cbcdb6 (patch)
tree39fa0c2056b12e3423eefe0cda78cf160ce17131 /packages/meshbay-node/src/meshbay_node/daemon.py
parentcc0820de8d8c33560c44bd6a0864de30e33a0109 (diff)
downloadmeshbay-20a824118c09af15d6c338db4c9480ffe5cbcdb6.tar.gz
docs: cite MESHBAY_DESIGN.md and a section instead of the merged notes
The per-feature design notes were merged into docs/MESHBAY_DESIGN.md and deleted from the tree on 2026-09-11, but ~230 comments across the three packages still named them — usually written `docs/musicbay.md §3.2`, as though the file were still in docs/. A reader had to know §16 existed to resolve any of them. They now name the section directly. Every mapping comes from §16, the concordance, which already records where each old section landed: musicbay -> §9.8, mediacenter -> §9.7 for the Videos app and §6.5 where the subject is derived data, photos -> §9.9, auth-confirm -> §3.6, refactoring-search -> §9.11, invite-pairing-v1 -> §3.4, per-node-identity-v1 -> §3.2, captcha -> §7.7, chat-sender-keys -> §4.5, apps/refactor-groups -> §9.1–§9.4, desktop-client-v1 per section. Bare citations of the same documents (`draft-v6 §2.11`, `§4.8`, `§3.4`) are retargeted too: those collide with real section numbers in the design document, so leaving them would have been worse than the named form. Four cases the concordance does not cover, each decided rather than guessed: Sub-item references into documents that no longer exist — mediacenter's `§3.3 row 4`, `§3.4b/c`, `apps.md §3b` — name rows and sub-items §9.7 and §9.2 do not reproduce. The module-level citation stays; the sub-item pointer is dropped. The V-findings keep their labels but lose the dead `§10.1/` prefix. §13.8 lists V1–V13 as per-application open items, which is not what the labels mean in these comments, so pointing them at §13.8 would have been a false citation. `apps.md §5`'s virtualization requirement has no counterpart anywhere in the design document. The requirement is stated in the comment itself, so the citation is dropped rather than aimed at a section that does not say it. Comments that attributed a *sentence* to an old note — musicbay's "several thousand files" example, its "what got measured" note, its measured ~11%/~26% cover-art figures, the "original no root, whole shared tree" call — state the fact without attribution now. §9.8 does not contain those sentences and citing it for them would have been wrong. CLAUDE.md's "a reference to a document that no longer exists" row now says the concordance is for git history and out-of-tree material; the code cites sections directly. Verified: 2851 passed, 4 skipped. The 12 errors in the run are the Firefox leg of test_sticky_header.py's browser harness, which is broken at the browser level on this machine — headless Firefox (snap) dies with `[GFX1-]: RenderCompositorSWGL failed mapping default framebuffer`, renders nothing, and the probe exits `{"error": "no measurement"}` after its full 90s wait. Chrome runs the same 12 assertions in 3.2s and passes. Nothing here can affect it: every changed line in style.css is inside a comment. Also checked: ast.parse on every changed .py, `node --check` on every changed .js, the /* */ balance in style.css, and that no changed line exceeds the width its file already used. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/daemon.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py77
1 files changed, 41 insertions, 36 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index 26f73fc..ad4a513 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -192,7 +192,7 @@ class NodeDaemon:
# failure — a persistently unprobeable file (corrupt, still being
# written) does not get re-queued on every coalesced broadcast. A
# restart retries everything, matching the "disposable, rebuildable"
- # stance the rest of this cache takes (docs/mediacenter.md §1/§2).
+ # stance the rest of this cache takes (docs/MESHBAY_DESIGN.md §6.5).
# Shared across the video and audio enrichment paths — content-
# addressed ids never collide between the two. Keyed by
# (group_id, entry.id), not entry.id alone: the id is a content
@@ -446,7 +446,7 @@ class NodeDaemon:
"tmdb_enabled": await self._roster.tmdb_enabled(
group_cfg.id) if self._roster else True,
# Music app equivalent of tmdb_enabled — per-group from
- # the start (docs/musicbay.md §6).
+ # the start (docs/MESHBAY_DESIGN.md §9.8).
"musicbrainz_enabled": await self._roster.musicbrainz_enabled(
group_cfg.id) if self._roster else True,
}
@@ -474,7 +474,7 @@ class NodeDaemon:
# 6b. Media cache (Videos app — TMDB metadata + thumbnails).
# Node-wide like audit.db, not per-group: a thumbnail is the same
# bytes regardless of which group happens to share the file
- # (docs/mediacenter.md §2/§5.5).
+ # (docs/MESHBAY_DESIGN.md §6.5, §9.7).
media_cache_db = data_dir / "media_cache.db"
self._media_cache = MediaCache(db_path=media_cache_db)
await self._media_cache.open()
@@ -491,16 +491,18 @@ class NodeDaemon:
self._state["tmdb_token_customized"] = bool(tmdb_token)
self._state["tmdb_language"] = tmdb_language or ""
- # 6c. Music app (docs/musicbay.md) — same media_cache.db, its own
- # enricher (mutagen, not ffmpeg) and its own MusicBrainz client.
+ # 6c. Music app (docs/MESHBAY_DESIGN.md §9.8) — same
+ # media_cache.db, its own enricher (mutagen, not ffmpeg) and its
+ # own MusicBrainz client.
# The User-Agent contact is the owner's hub email, resolved at
# login — no roster setting or env var needed any more.
self._audio_enricher = AudioEnricher(self._media_cache)
self._musicbrainz_client = MusicBrainzClient(owner_email=session.email)
self._state["musicbrainz_contact_configured"] = bool(session.email)
- # 6d. Photos app (docs/photos.md) — same media_cache.db, its own
- # enricher (Pillow, not ffmpeg/mutagen). No credential, no
+ # 6d. Photos app (docs/MESHBAY_DESIGN.md §9.9) — same
+ # media_cache.db, its own enricher (Pillow, not ffmpeg/mutagen).
+ # No credential, no
# third-party client to construct: EXIF is read locally.
self._photo_enricher = PhotoEnricher(self._media_cache)
self._state["media_cache"] = self._media_cache
@@ -1352,7 +1354,7 @@ class NodeDaemon:
delta = idx.diff(previous)
self._last_broadcast_snapshot[group_id] = (idx.version, idx.entries_by_id())
- # Videos app (docs/mediacenter.md §5.2): schedule async technical
+ # Videos app (docs/MESHBAY_DESIGN.md §6.5): schedule async technical
# probe + title parse + thumbnail generation for every newly-seen
# video entry under the group's configured video_root. Never blocks
# this broadcast — enrichment fields arrive later as their own
@@ -1377,18 +1379,19 @@ class NodeDaemon:
seen = {e.id for e in new_entries}
new_entries = new_entries + [e for e in rebuilt if e.id not in seen]
spawn(self._enrich_new_video_entries(indexer, new_entries))
- # Music app (docs/musicbay.md §6): same shape, gated on audio_root
- # exactly like video_root above (added later — musicbay.md's
- # original "no root, whole shared tree" call didn't hold up).
+ # Music app (docs/MESHBAY_DESIGN.md §9.8): same shape, gated on
+ # audio_root exactly like video_root above (added later — the original
+ # "no root, whole shared tree" call didn't hold up).
spawn(self._enrich_new_audio_entries(indexer, new_entries))
- # Photos app (docs/photos.md §5): same shape, gated on photo_roots
- # (a list, not a single string — §2.1).
+ # Photos app (docs/MESHBAY_DESIGN.md §9.9): same shape, gated on
+ # photo_roots (a list, not a single string).
spawn(self._enrich_new_photo_entries(indexer, new_entries))
# A rename/move changes the very filename (or season folder) that
- # §3.3/§3.4's title-parse read display_title/season/episode from,
- # but leaves the file's content — and so its id and everything
- # ffprobe/thumbnailing already found — untouched. Only entries
+ # docs/MESHBAY_DESIGN.md §9.7's title-parse read
+ # display_title/season/episode from, but leaves the file's content —
+ # and so its id and everything ffprobe/thumbnailing already found —
+ # untouched. Only entries
# whose name or path actually differ from the last broadcast get a
# fresh pass; an update that is enrichment's own field-fill
# (duration/thumb_hash/... landing via _on_enriched below) leaves
@@ -1403,13 +1406,13 @@ class NodeDaemon:
# Videos/Music/Photos apps: a file that leaves the index also loses
# its thumbnail/cover and file->tmdb/file->mbid mapping — the "real
- # deletion obligation" docs/mediacenter.md §2/§8 calls out
- # explicitly rather than leaving implicit (docs/musicbay.md §6
+ # deletion obligation" docs/MESHBAY_DESIGN.md §6.5 calls out
+ # explicitly rather than leaving implicit (docs/MESHBAY_DESIGN.md §9.8
# follows the same rule). tmdb_meta/mbid_meta rows are left alone
- # (§2: shared across files).
+ # (shared across files).
#
- # Found live (docs/photos.md): a root removed and a new one added
- # for the identical content (an operator renaming/relocating a
+ # Found live (docs/MESHBAY_DESIGN.md §9.9): a root removed and a new
+ # one added for the identical content (an operator renaming/relocating a
# shared folder) pruned the thumbnail here — correctly, the content
# is gone from *this* root — but left the hash in
# `_enriched_attempted`, which is never otherwise cleared. The same
@@ -1480,8 +1483,8 @@ class NodeDaemon:
A group with no video_root set yet does not enrich anything — TMDB
lookups and ffmpeg thumbnailing are real, ongoing per-file cost
- (mediacenter.md §5.2/§10), and running them over an operator's whole
- shared index before they have chosen which folder is actually their
+ (docs/MESHBAY_DESIGN.md §6.5), and running them over an operator's
+ whole shared index before they have chosen which folder is actually their
media library would burn both TMDB's rate limit and the node's CPU
on files that were never meant to be in the Videos app at all. Once a
root is set, `_enrich_video_root_now` (called when it changes)
@@ -1560,14 +1563,14 @@ class NodeDaemon:
async def _enrich_new_audio_entries(self, indexer: DirectoryIndexer, entries: list) -> None:
"""
- Music app (docs/musicbay.md §2.1, §6): fire (never await further)
+ Music app (docs/MESHBAY_DESIGN.md §9.8): fire (never await further)
tag/cover enrichment for unattempted audio entries under the
group's configured audio_root — same gate as
- `_enrich_new_video_entries` above (musicbay.md's original "no root,
- whole shared tree" call turned out wrong against a real messy
- library: everything under every shared folder got mixed together
- with no way to scope it down). `_enriched_attempted` is shared with
- the video path — content-addressed ids never collide across the two.
+ `_enrich_new_video_entries` above (the original "no root, whole
+ shared tree" call turned out wrong against a real messy library:
+ everything under every shared folder got mixed together with no way
+ to scope it down). `_enriched_attempted` is shared with the video
+ path — content-addressed ids never collide across the two.
"""
if not self._audio_enricher or not self._roster:
return
@@ -1596,9 +1599,10 @@ class NodeDaemon:
# not the shared root it lives in — so the ancestor walk
# (enrich_audio._artist_album_from_ancestors) treats a flat
# top-level folder right under the configured Music directory as
- # ambiguous (artist-or-release, musicbay.md §2.1), rather than one
- # level too shallow when that directory is itself a subfolder.
- # With several configured, each file is measured against its own:
+ # ambiguous (artist-or-release, docs/MESHBAY_DESIGN.md §9.8),
+ # rather than one level too shallow when that directory is
+ # itself a subfolder. With several configured, each file is
+ # measured against its own:
# a single shared boundary would be wrong for all but one of them.
self._audio_enricher.spawn(entry, file_path, on_done,
boundaries.get(owner))
@@ -1639,8 +1643,8 @@ class NodeDaemon:
async def _enrich_new_photo_entries(self, indexer: DirectoryIndexer, entries: list) -> None:
"""
- Photos app (docs/photos.md §5): fire (never await further) thumbnail/
- EXIF enrichment for unattempted image entries under any of the
+ Photos app (docs/MESHBAY_DESIGN.md §9.9): fire (never await further)
+ thumbnail/EXIF enrichment for unattempted image entries under any of the
group's configured photo_roots. Same gate shape as
`_enrich_new_video_entries`/`_enrich_new_audio_entries` — no root
configured yet means no work, since thumbnailing every image in a
@@ -1678,8 +1682,9 @@ class NodeDaemon:
so a folder that already had photos in it before it was added to
photo_roots would otherwise never get enriched at all. Also covers
a root being *removed*: nothing un-enriches on removal (the cache
- entry is harmless, just unused — docs/photos.md's cache is
- disposable), so re-sweeping the new set is enough.
+ entry is harmless, just unused — the media cache is disposable and
+ tied to the index, docs/MESHBAY_DESIGN.md §6.5), so re-sweeping the
+ new set is enough.
"""
indexer = self._state.get("indexers", {}).get(group_id)
if not indexer: