All notes
Architecture

The score is the signal

An Intelligence board ranked content with a composite of engagement proxies, recency decay, and source weights that couldn't explain itself. Moving scoring to an LLM that returns a number and a one-sentence reason deleted 719 lines and produced a table curators can actually argue with.

The Intelligence board started as a signal stack: engagement proxies, source weights, recency decay, assembled into a composite score that couldn’t explain itself. Moving the scoring to Gemini Pro — 0-100 plus a one-sentence justification — removed 719 lines and produced a table curators can actually argue with.

Signals without ground truth are speculation

Engagement metrics, recency, and source authority are reasonable proxies when you don’t have a judge. In a curation product, the judge exists. Ranking content by proxy signals when you can ask directly for a score and a reason is building complexity for its own sake. The original intelligence-board.tsx was doing exactly that. So I deleted it.

Idempotency matters more than you think

The scoring pipeline runs per item, upserts on conflict, and guards with WHERE item.curated IS NULL to avoid re-scoring already-processed content. When an LLM call fails or the job re-queues, nothing scores twice. This is the kind of defensive invariant that disappears from view once it works, but without it, reprocessed items accumulate score drift that confuses the ranker.

The table earned its 3 columns

Content, origin metrics, score. The pruned surface doesn’t hide data it doesn’t have: items without a score show n/a, not a fabricated proxy. Sort order persists in localStorage so curators don’t re-rank on every page load. The interface is narrow because the signal is now precise enough not to need supplementation.

Simpler when the model is the layer

The same logic applies anywhere the codebase maintains a hand-rolled ranking function approximating an LLM’s native capability: delete the function, store the score, display the justification. The model is the layer. The application’s job is to act on its output, not reproduce the reasoning.