You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Five sixths of the file is dead weight. Every read path parses all of it.
src/lib/local-api.js:122-160 reads the entire queue.jsonl with readFileSync, re-parses every line and re-dedups, on every endpoint call. A dashboard refresh hits 6-8 endpoints; auto-refresh defaults to 30s. Nothing ever compacts — the only rewrite in the codebase is a one-off migration (sync.js:1836).
Appends are already deduped per totals-change (rollout.js:1541,1591), which is the right design for an append-only log. The gap is that superseded rows are never reclaimed.
This is not urgent today. It is monotonic, it is on the hot path of every render, and the fix carries close to zero design risk because the readers already define what the output must be: keep the last row per key. Compaction only has to produce what every reader already computes.
Proposal
sync --compact, and an automatic trigger when the superseded ratio crosses a threshold.
Write to a temp file and rename — the atomic-replace pattern already used for the project queue at sync.js:2040-2043.
Nothing enforces it at runtime. A miswritten or corrupt row is aggregated and rendered, not flagged — and a parser bug of this shape is exactly the class CLAUDE.md:169-172 records at 1.6-7× magnitude.
Add a doctor check validating every row against it, plus bucket alignment (30-minute UTC) and non-negative counts. Same conversion as the curated expiry in #91 and the version lockstep in #96: a rule that lived in a document starts running.
Definition of done
sync --compact reduces this install's 34,492 lines to ~5,595 with byte-identical API responses before and after — that equality is the real test, not the line count
Compaction is safe against a concurrent append (test with the sync lock held)
doctor fails on a fixture with a column-sum violation, a misaligned bucket, and a negative count
Interrupted compaction leaves the original intact (kill between write and rename)
Measured on a real install
Five sixths of the file is dead weight. Every read path parses all of it.
src/lib/local-api.js:122-160reads the entirequeue.jsonlwithreadFileSync, re-parses every line and re-dedups, on every endpoint call. A dashboard refresh hits 6-8 endpoints; auto-refresh defaults to 30s. Nothing ever compacts — the only rewrite in the codebase is a one-off migration (sync.js:1836).Appends are already deduped per totals-change (
rollout.js:1541,1591), which is the right design for an append-only log. The gap is that superseded rows are never reclaimed.This is not urgent today. It is monotonic, it is on the hot path of every render, and the fix carries close to zero design risk because the readers already define what the output must be: keep the last row per key. Compaction only has to produce what every reader already computes.
Proposal
sync --compact, and an automatic trigger when the superseded ratio crosses a threshold.rename— the atomic-replace pattern already used for the project queue atsync.js:2040-2043.mkdirmutex and heartbeat from fix: correct expired DeepSeek prices, enforce curated expiries, harden Host + sync lock #91 exist precisely so a long-running writer cannot be robbed mid-write; this is the second real user of that.catis the wrong default.Second half — enforce the schema invariant
CLAUDE.md:56-63states the column invariant in prose:Nothing enforces it at runtime. A miswritten or corrupt row is aggregated and rendered, not flagged — and a parser bug of this shape is exactly the class
CLAUDE.md:169-172records at 1.6-7× magnitude.Add a
doctorcheck validating every row against it, plus bucket alignment (30-minute UTC) and non-negative counts. Same conversion as the curated expiry in #91 and the version lockstep in #96: a rule that lived in a document starts running.Definition of done
sync --compactreduces this install's 34,492 lines to ~5,595 with byte-identical API responses before and after — that equality is the real test, not the line countdoctorfails on a fixture with a column-sum violation, a misaligned bucket, and a negative count