Snapshots

Cards come from seven sources and are fact checked first

Settled
  • Sources: Plays, the read, listening, ideas, stories, watchers, statics and accounts.
  • Fact gate: every money amount and percent must be in the fact sheet.
  • A shield opens Why this, with proof built from facts, no AI.
  • One take per card, then Redo it; six Plays saying one thing show once.
  • Audit result on 22 Oct: no wrong medium or empty asset cards.
Your call

Are the ranking weights right? Proposal: freeze each partner's top 20 as a test, then tune.

Engineering · 5.7

Cards and the feed

DraftLast checked Mon Oct 26Owner Param

Answer

Cards are made from Plays, the read, listening, ideas, stories, watchers and statics, healed as they are read, and ranked per person by one score with fixed first-screen seats; this page settles how a card is made, how the feed is ordered and which knobs tune it.

Today

Where cards come from

Source Maker Source
Plays cards-gen.js: 1 or 2 cards per Play; the title is the point, the body two sentences (25 to 35 words), every number in the fact sheet brew/cards-gen.js:1-3
The read instant cards at read time brew/build.js:601
Listening and ideas social-feed.js heardCards, ideaCards; threads must pass community-gate.js brew/social-feed.js memory brew-community-seat
Stories research.js (ads, trends, news, how-to, viral) brew/research.js:1-5
Watchers catalog every 3 hours, AI answers weekly (live-watch.js) brew/live-watch.js:1-5
Statics Play 21's static ads (statics.js) brew/statics.js:1-4
Connected accounts live-* cards, members only brew/connectors/index.js:324

Rules every card passes

  • Fact gate: every money amount and percent must be in the fact sheet; strict mode also gates multipliers and large counts. brew/fact-gate.js:1-5
  • Claims: a card says only what the brand itself says (claims.js). brew/cards-gen.js:6-7
  • Today's counts: a count row naming one fact takes today's value, never a rival's, never to or from 0, never a jump over 5×. memory brew-card-fit-and-counts
  • The right button: fitCta and fitMedium heal the button and format as the card is read (a Reddit post never gets an Instagram format). brew/feed-service.js:9 memory brew-read-stream-backfill
  • One take: no card promises "3 ads"; one version, then Redo it. memory brew-one-version
  • Plain words: one background pass rewrites title, body, reasons and steps in everyday words, numbers checked in code, cached in plain.json (PLAIN_V 3); PLAIN_OFF=1 stops it. brew/plain.js:1-5, 18 brew/SCOPE.md
  • Proof: a shield with a count opens "Why this, and the proof", built with no AI from facts, accounts, quotes, rival ads and the pages read; a Play is never evidence; the proof must prove the claim (proof-logic.js). brew/evidence.js:1-6 memory brew-proof-plain-make
  • One card per ask: six Plays saying "fix the pack prices" show once (same-ask.js). brew/feed-service.js:27

The score

For each card and viewer, score() adds: brew/feed-service.js:539-568

Part What it is
value the Play's grade (impact 1 to 5, confidence, effort) from value.js, one fast call per 20 Plays brew/value.js:1-6
seat fit to the viewer's role, lane and stated focus words
affinity hearts and clicks by agent, campaign, format, product; minus "Not for me", with near titles sinking by 4
fresh streaming cards decay over 24 hours, others over 72
fatigue days seen, the agent's share of today's screen, quiet jams
feedback "Fewer" minus 2 per step
tune the member's own weights (less −4, more +4 per agent) and topics (+2 each, two at most) brew/docs/handover/engineering/12-ui2-service-api.md
told and lift a Play rewritten on the team's learnings +6; team cards +10, learned up +8
contra the team said it does not work: −40 until "bring back"
extra urgency (sold out, days left), a first draft to look at (+3), statics and ads (+2), live account cards
behind its Play is being rewritten: −8
chan, pace channels the viewer runs and their ad pace

The layout

  • Pins from the "new cards" pill sit on top for 30 minutes. brew/feed-service.js:700
  • Two picture cards for every text card, unless the other kind is more than 2 points stronger. brew/feed-service.js:703-706
  • Social seats: position 3 the best community reply or post, 7 the best picture post, 9 another text card. brew/feed-service.js:708-715
  • Make seats: positions 2 and 6 hold an ad or post the brand can make, from different groups, never a rival's ad; a finished static takes one. brew/feed-service.js:716-722
  • No two cards of the same sort in a row. brew/feed-service.js:723
  • Storefront cards are hidden in v1 (?storefront=1 shows them). brew/SCOPE.md

Stories

Five rings always show: Brand today, Trends, Popular ads, Industry news, How to. Each story lives 24 hours from first seen; an expired one can still rank as a card. A ring whose stories expire reads its source again, at most every 2 hours. Story score is 0.4 freshness plus 0.6 strength. memory brew-stories-and-cards brew/feed-service.js:1312

Tomorrow

Item Version Tag
One score, fixed seats, plain words and proof on every card v1 Stays
Ranking weights checked on fixtures from several brands v2 New
Cards in "we" voice across every writer v1 Changes (open from QA 25 Oct) memory brew-qa-round2-2026-10-24
Storefront cards back in the feed v2 Changes
Ranking tests for score, rank and feed v2 New

How we do it

  1. When "X cards never show", check where the ranker puts them before blaming the source. memory brew-community-seat
  2. Before shipping a card-rule change, compare old and new code on every saved card:
node tools/audit-card-fit.mjs DIR --before

memory brew-card-fit-and-counts

  1. Heal wherever text is read (pack load, pub, jam brief), not only at load; shared jams and workspace copies outlive pack heals. memory brew-one-version
  2. New brand routes must be added to the three path regexes in feed-service.js, or they return "not found". memory brew-drop-learnings

Numbers

Metric Definition Where measured
Cards served per brand Visible cards in a member's feed GET /api/tenants/:t/feed
Wrong-medium and empty-asset cards Cards failing the fit audit tools/audit-card-fit.mjs (0 of 9,540 on 22 Oct) memory brew-card-fit-and-counts
Proof coverage Share of cards whose numbers all match a source evidence.js counts (Proposed to aggregate)
Feed load time Server time for the feed answer Server-Timing, [slow] log over 1.5 s

Open

  1. Are the ranking weights right? Proposal: build fixtures from the five partners and freeze the top 20 per brand as a test, then tune.
  2. Should Storefront come back for v2? Proposal: yes for Shopify brands with a connected store only.
Sources
  • brew origin/main: cards-gen.js:1-30; feed-service.js:1-30, 535-568 (score), 696-725 (feed layout), 1312 (stories); value.js:1-6; plain.js:1-5, 18; evidence.js:1-6; proof-logic.js; card-nums.js; same-ask.js; member-tuning.js:1-6; social-feed.js; community-gate.js; research.js:1-5
  • brew origin/main: SCOPE.md (Feed, Your feed rows)
  • brew origin/main: docs/handover/engineering/02-feature-audit.md section 3, 12-ui2-service-api.md section 2
  • memory brew-stories-and-cards, brew-community-seat, brew-proof-plain-make, brew-card-fit-and-counts, brew-one-version, brew-drop-learnings, brew-qa-round2-2026-10-24

Source file content/engineering/cards-and-the-feed.md · For agents: Markdown · JSON