Implementation Spec · July 9, 2026

Per-Lens Hot-Takes — The Build Plan

The approved design, turned into a precise, plain-language spec: exactly what changes, why it's safe, and how we'll know it works. Copy only — no grades move.

the-drop-score · slice 17 · spec · branch design/brick-drop-app-slice-17-per-lens-takes
What this spec delivers

A hot-take written for each of the four buyers, so when you view a set through the investor lens, the words match the grade — the take leans on resale, and it cites the C, not the overall B−. Six small, well-bounded changes; nothing about it can make the site look worse while it rolls out.

6
small changes — contract, writer, two call sites, storage, rendering
1
new database column, and one line changes what the card shows
0
grades, layouts, or existing takes broken — it's copy-only and fail-soft

01 The six moving parts

Each piece has one job and a clear boundary. Read top to bottom — it's the order we'll build in.

  1. The take grows a new pocket

    src/lib/contracts/take.ts

    Every set's "take" today holds a universal hot-take, three read blurbs, and four short per-lens reasons. We add one optional field: four full hot-takes, one per lens. Optional is the magic word — a take without it is still perfectly valid, so nothing already saved breaks.

  2. The writer learns to write four more

    src/lib/app/generateTake.ts

    The single AI call that writes each set's copy now also produces a full hot-take for each buyer — same voice, same hard rules (no emoji, never price-per-piece), just aimed at one reader. We give it a little more room to write (a higher token budget) and tell it, per audience, what to lean on: display → the shelf, builder → the build, parent → play, investor → resale.

  3. The two places that make takes hand over the grades

    scripts/generate-takes.ts · scripts/grade-set.ts

    For the writer to cite the right letter, it needs each lens's grade (see §2). The backfill script fetches the four lens grades it already has stored; the live grading script already computes them a few lines earlier — it just passes them along. Small, mechanical.

  4. A column to keep them in

    Supabase · takes table

    One new nullable column (hot_takes) holds the four paragraphs as JSON. The row mapper and reader learn to write and read it. "Nullable" means every existing row is instantly valid with the column empty.

  5. The card quietly swaps its copy

    src/lib/app/storedResult.ts

    One line: when a lens is active and it has a hot-take, use it; otherwise use the universal one. The result card, the shareable image, and the link preview all already show "the take," so they pick up the lens-specific words automatically — no redesign, no new code in any of them.

  6. We prove it, then refresh everything once

    tests · scripts/generate-takes.ts --force

    Unit tests lock the behavior (see §4), then a single regeneration pass fills in the new hot-takes for all 28 existing sets. Every future set gets them for free the moment it's graded.

02 The key idea: tell the writer each grade

Here's the subtlety that makes the whole thing coherent. The universal take's charm is that it name-drops the grade — "the B− tells you…". For a per-lens take to do the same, the writer has to know that lens's grade, not just the overall.

So we pass it the report card

The writer already gets the overall grade and the three read grades. We add one thing: each lens's own letter. Then the prompt lists the audiences with their grades — "investor (grade: C)…" — and asks for a take grounded in that grade. Now the investor take can honestly say "a C for a flip" instead of contradicting itself.

Before · the universal take, seen as an investor

"…8278 pieces and 12 minifigs for $649.99 is a lot to ask fam. The B− drop score tells you it's impressive but not without its receipts…"  — clashes with the big C on the card

After · written for an investor, citing the C

"Real talk investor — that D+ on hold value is the whole story. Gorgeous Gondor, no doubt, but a C for the flip means the market won't bail you out on a $649.99 buy-in. Grail for the shelf, hard pass for the portfolio."

03 Why nothing can break

The design is deliberately fail-soft — every path has a safe fallback, so there's never a moment where the site looks worse than it does today.

old rows
A saved take with no per-lens hot-takes stays valid — the reader simply omits the field and shows the universal take.
a missing lens
If one lens's hot-take is empty or malformed, that one entry is dropped; the rest are kept, and that lens falls back to the universal take.
before regeneration
We can merge the code before refreshing the 28 sets — cards keep showing the universal take until each one is refreshed. No blackout.
a bad AI reply
The existing fail-closed validator still applies: a malformed reply never persists, so a set keeps its previous good take.
The blast radius

Copy only — no grade, number, layout, or existing take changes. The one new column is nullable, the one new field is optional. The worst case at any point is "shows the universal take," which is exactly today's behavior.

04 How we'll prove it works

Three tiny, focused test sets — each checks one unit in isolation, the way the rest of the codebase is tested:

Plus the usual green gates — both typecheck passes and the full test suite — and a live check that a real investor card/OG no longer cites the overall letter.

05 Rolling it out

In one sentence

Add an optional four-paragraph pocket to each take, teach the writer each buyer's grade so it fills that pocket coherently, swap it in with a single line, and refresh the 28 sets once — low risk, high polish, and it completes the personalization we just shipped.

The Brick Drop · Drop Score · implementation spec · July 9, 2026