Problem
GET /{project}/api/customizations (app.py:1011) returns all three customization registries by calling list_stats, list_display_klasses, and list_post_processings (app.py:1022–1024). Each helper read_text()s every file in its registry on every call — active and disabled alike (summary_stats.py:92/103, display_klasses.py:136/145, post_processing.py:92/103); there is no caching or mtime check. On the client, CustomizationsPage refetches the whole payload whenever the SSE version changes, and version increments on every server event, not just customization edits (SSEContext.tsx:29). So an unrelated event — an entry build, a notebook reorder, an alias change — triggers a full re-read of every summary-stat, display-klass, and post-processing source file from disk.
Impact
Negligible at current scale: a handful of small Python files per registry, on a page few people keep open. But the cost is O(files × events) disk reads with no caching, the entire payload reloads when only one registry — or none — actually changed, and it grows with both registry size and overall event volume.
Suggested fix
Gate the client refetch on customization-relevant events. lastEvent.kind is already exposed (SSEContext.tsx:29) and the mutating MCP tools emit summary_stat_changed / display_changed / post_processing_changed (server.py:909/991/1073), so the page can refetch only on those kinds instead of the raw version counter. The per-request disk reads are cheap enough to leave as-is; if they ever aren't, an mtime-keyed cache inside the list_* helpers would cover every caller.
Context
Identified during review of #26 (the read-only customizations page). Demo-scale projects are unaffected; flagging as the growth vector if registries or event volume grow.
Problem
GET /{project}/api/customizations(app.py:1011) returns all three customization registries by callinglist_stats,list_display_klasses, andlist_post_processings(app.py:1022–1024). Each helperread_text()s every file in its registry on every call — active and disabled alike (summary_stats.py:92/103,display_klasses.py:136/145,post_processing.py:92/103); there is no caching or mtime check. On the client,CustomizationsPagerefetches the whole payload whenever the SSEversionchanges, andversionincrements on every server event, not just customization edits (SSEContext.tsx:29). So an unrelated event — an entry build, a notebook reorder, an alias change — triggers a full re-read of every summary-stat, display-klass, and post-processing source file from disk.Impact
Negligible at current scale: a handful of small Python files per registry, on a page few people keep open. But the cost is O(files × events) disk reads with no caching, the entire payload reloads when only one registry — or none — actually changed, and it grows with both registry size and overall event volume.
Suggested fix
Gate the client refetch on customization-relevant events.
lastEvent.kindis already exposed (SSEContext.tsx:29) and the mutating MCP tools emitsummary_stat_changed/display_changed/post_processing_changed(server.py:909/991/1073), so the page can refetch only on those kinds instead of the rawversioncounter. The per-request disk reads are cheap enough to leave as-is; if they ever aren't, an mtime-keyed cache inside thelist_*helpers would cover every caller.Context
Identified during review of #26 (the read-only customizations page). Demo-scale projects are unaffected; flagging as the growth vector if registries or event volume grow.