Answer
Every number a brand sees must trace to a fact, an account or a sum, stay fresh, and never pass a dummy or stale value as true; this page sets those gates and how we check them, for every brand at once.
Today
The gates
| Gate | What it stops | Source |
|---|---|---|
| Fact gate | A money amount or percentage on a card that the fact sheet does not back; cards written from Plays also gate multipliers and counts of a thousand or more | brew/fact-gate.js:1-6 |
| Plan numbers | A number in a sentence that says target, estimate, assumption or to confirm never backs a card | brew/fact-gate.js:65-77 |
| Retired numbers | A number that stopped being true, a product gone or a price changed, is cut from Plays before they back a card | brew/fact-gate.js:79-88 |
| One number, one source | The headline numbers are worked out once, the same way for every brand | brew/pack-numbers.js:1-4 |
| The fact sheet | The team corrects it with choices or a pasted link, never a typed number; a free daily check keeps prices and stock in line; each edit is recorded and flags the Plays that quote the old value | brew/facts-desk.js:1-5 |
| Connected truth | For members, a connected number beats the site's; a stale or simulated one never counts | brew/facts-desk.js:34-46 memory brew-connected-facts |
| Not read is not zero | A health part or ring that could not be read is left out, never scored as zero | brew/health.js:5-7 |
| Stories | Quote only numbers in their data; a failed source says so on its ring | memory brew-stories-and-cards |
| Proof sheet | Every card's numbers matched to a fact line, account, rival ad, quote or sum, with link and date; unmatched numbers are named; a Play is never proof | memory brew-proof-plain-make |
| Whole Plays | A Play missing any of its six sections is not saved | memory brew-qa-audit-2026-10-20 |
| Weekly Plays | Marked verified only when every number is backed | brew/SCOPE.md:50 |
| Dummies | Simulated rows keep a demo flag and stay out of Plays, the fact sheet, briefs and stale flags | brew/DUMMY.md:27-30 |
Freshness
| Connector | Read every | Read again when a member opens, if older than | Source |
|---|---|---|---|
| Shopify | 3 h | 1 h | brew/connectors/index.js:37, 40 |
| Meta | 3 h | 1 h | brew/connectors/index.js:37, 40 |
| Google Ads, GA4 | 6 h | 2 h | brew/connectors/index.js:37, 40 |
| Judge.me | 6 h | 2 h | brew/connectors/index.js:37, 40 |
| Klaviyo | 12 h | 6 h | brew/connectors/index.js:37, 40 |
- Stale after 3 failed reads in a row, or no good read for four cadences and at least 24 hours; stale numbers stop being evidence. brew/connectors/index.js:51-61
- A connected number that changes by 10% from the value a Play was written with flags that Play; flagged Plays refresh within a weekly budget. memory brew-move-freshness
- A product out of stock or gone flags every Play naming it at once, with no AI. memory brew-move-freshness
Past failures and the lesson each left
| Date | What went wrong | Lesson | Source |
|---|---|---|---|
| 16 Oct | One 15ml variant out of stock flagged 54 of Arata's Plays: a short name matched the 200ml | Check a matcher against real brand data, variants included | memory brew-move-freshness |
| 16 Oct | Arata's connected ledger held simulated Shopify data with no flag | Simulated rows always carry the demo flag | memory brew-audit-2026-10-15 |
| 16 Oct | Cozy was set to India though it sells in the US, so its Plays were written for India | Country comes from the store, never a default | memory brew-audit-2026-10-15 |
Tomorrow
| Item | Version | Tag |
|---|---|---|
| Every gate above, for every brand | v1 | Stays |
| A nightly data check per brand: unbacked numbers, stale connections, Plays flagged too long | v1 | New, proposed |
| A post never goes out with an unbacked number | v2 | New |
| Results read only from fresh, non simulated account rows | v3 | New |
| Ad rules refuse to act on stale numbers | v4 | New |
How we do it
- Every fix works for every brand, every card and every view, and heals saved data on read. memory feed-for-all-brands memory fix-as-product
- Audit what the product shows against the platform, read only:
cd /Users/param/Documents/ChatGPT/brew
node tools/audit-cards.mjs --bucket
FEED_VAULT_KEY=$(gcloud secrets versions access latest --secret=FEED_VAULT_KEY) node tools/meta-audit.mjs <slug>
FEED_VAULT_KEY=$(gcloud secrets versions access latest --secret=FEED_VAULT_KEY) node tools/shopify-audit.mjs <slug>
node tools/audit-brand-book.mjs <dir with a copy of the brand files>
The two account audits read with staging's vault key; a brand at home on production needs FEED_VAULT_KEY_PROD. All four write nothing. brew/tools/meta-audit.mjs:1-3 brew/tools/shopify-audit.mjs:1-3 brew/tools/audit-cards.mjs:1-6
- Run the honesty and number tests before every deploy:
AI_MOCK=1 node --test test/honesty.test.js test/claims.test.js
- A new connector needs entries in
EVERY_H,OPEN_H,NAMESandPRECEDENCE. memory brew-connected-facts
Numbers
| Metric | Definition | Where measured | Status |
|---|---|---|---|
| Unbacked numbers | Numbers on shown cards with no proof match, per brand | Proof sheet counts | Proposed |
| Stale connections | Connections marked stale | connections.json; db/status.mjs |
Live data, not reported |
| Facts to confirm | Facts marked to confirm and not yet corrected | The fact sheet | Proposed |
| Days flagged | Days a Play stays flagged before its refresh | Updates per brand | Proposed |
Open
- Run a nightly data check? Proposal: yes, one report to hello@ listing each partner's unbacked numbers and stale connections.
- How long may a Play stay flagged? Proposal: 7 days, then it leaves the feed until it is refreshed.