Module: catalog · Dimension: perf · Severity: medium · Location: apps/server/src/catalog/service/user-mirrors.ts:143
Problem
appendMirrorRows reads the entire existing events JSON blob for a user (userHistoryMirror/userRatingsMirror.events, schema at apps/server/src/db/schema/catalog/catalog.ts:96, mode 'json', no size cap), merges via uniqBy([...prior, ...next]) (mergeHistory/mergeRatings, lines 157-163), and writes the full merged array back as one JSON column on every run of the every-6-hours user_mirror_sync job (apps/server/src/catalog/jobs/user-mirror-sync.ts, schedule '0 */6 * * *').
Why it matters
For a long-lived user with years of watch history (thousands to tens of thousands of events), every sync does an O(n) dedupe scan over the full history and rewrites the entire growing blob to SQLite every 6 hours forever — cost per sync increases monotonically with account age and there is no trimming/pagination of the events array.
Suggested fix
Cap or archive old events (e.g. keep only last N events or events within a retention window) when merging, or move to an append-only events table instead of a single JSON blob column so writes are O(new events) not O(total history).
Fable-panel validated: 2/3 votes.
Filed from automated per-module audit workflow (Opus/Sonnet research → Fable-panel decision). Unverified by a human — triage before acting.
Module:
catalog· Dimension: perf · Severity: medium · Location:apps/server/src/catalog/service/user-mirrors.ts:143Problem
appendMirrorRowsreads the entire existingeventsJSON blob for a user (userHistoryMirror/userRatingsMirror.events, schema at apps/server/src/db/schema/catalog/catalog.ts:96, mode 'json', no size cap), merges viauniqBy([...prior, ...next])(mergeHistory/mergeRatings, lines 157-163), and writes the full merged array back as one JSON column on every run of the every-6-hoursuser_mirror_syncjob (apps/server/src/catalog/jobs/user-mirror-sync.ts, schedule '0 */6 * * *').Why it matters
For a long-lived user with years of watch history (thousands to tens of thousands of events), every sync does an O(n) dedupe scan over the full history and rewrites the entire growing blob to SQLite every 6 hours forever — cost per sync increases monotonically with account age and there is no trimming/pagination of the events array.
Suggested fix
Cap or archive old events (e.g. keep only last N events or events within a retention window) when merging, or move to an append-only events table instead of a single JSON blob column so writes are O(new events) not O(total history).
Fable-panel validated: 2/3 votes.
Filed from automated per-module audit workflow (Opus/Sonnet research → Fable-panel decision). Unverified by a human — triage before acting.