{
 "id": "5.2",
 "title": "Codebase map",
 "department": "Engineering",
 "department_slug": "engineering",
 "direction": null,
 "branded": false,
 "status": "draft",
 "owner": "Param",
 "last_verified": "2026-10-26",
 "holds": "Every top-level module, what it owns, its tests",
 "urls": {
  "html": "https://handbook.joinsquareup.com/engineering/codebase-map",
  "markdown": "https://handbook.joinsquareup.com/engineering/codebase-map.md",
  "json": "https://handbook.joinsquareup.com/engineering/codebase-map.json"
 },
 "other_directions": [],
 "tldr": {
  "headline": "Every module on origin/main, with who owns what and what tests it",
  "points": [
   {
    "icon": "map",
    "text": "The repo holds 1,027 tracked files, 153 of them top level modules."
   },
   {
    "icon": "check",
    "text": "The suite has 215 test files, run free with AI_MOCK and on every push."
   },
   {
    "icon": "warn",
    "text": "13 modules have no test that imports them directly."
   },
   {
    "icon": "book",
    "text": "Find the file that owns a behaviour here before you change anything."
   },
   {
    "icon": "gear",
    "text": "The biggest file, feed-service.js, is 340 KB and wants splitting."
   }
  ],
  "stat": {
   "value": "862",
   "label": "commits on origin/main"
  },
  "decide": "Split the big four files before v2? Proposal: feed-service.js first, one area per week.",
  "mood": "solid"
 },
 "sources": [
  "brew origin/main b91e364: git ls-tree -l (file sizes), first comment of each module",
  "brew origin/main d6154b3: git ls-tree -l for the rows the 26 Oct merge touched: db/, public/, test/, tools/, .github/, product-name.js, public/brief-staff.js, db/brand-wipe.js, db/wipe-cli.js, db/reset-brand.mjs, db/delete-brand.mjs",
  "brew origin/main test/*.test.js: import lines (which test loads which module)",
  "brew origin/main: README.md 'Where things live', Dockerfile, package.json, deploy.sh:8",
  "memory brew-jam-v2, brew-one-stage (Jam v2 screen retired 25 Oct)"
 ],
 "open_questions": [
  "**Should the big four files be split before v2?** Proposal: split `feed-service.js` first (feed, jam routes, Slack in), one area per week, each behind the existing tests.",
  "**Should `jam2/` be renamed now that the v2 screen is gone?** Proposal: rename to `studio/` in v2 with the v2-only routes removed in the same change."
 ],
 "parts": {
  "Answer": "This is every module on brew origin/main (commit b91e364, 26 Oct 2026, 862 commits) with what it owns, the tests that load it and its size, so anyone can find the file that owns a behaviour before changing it.",
  "Today": "How to read the tables:\n- **Tests** lists the files in `test/` that import the module directly. \"none\" means no test imports it; it may still be covered through another module. Test files are named without `.test.js`. Paid probes (`*-probe.mjs`) are marked and never run in the suite. [src: brew/test/]\n- **Size** is the file size on origin/main. [src: git ls-tree -l origin/main]\n- The repo has 1,027 tracked files: 153 top-level modules, 9 folders of code and 4 of data. [src: git ls-tree -r origin/main]\n- The suite has 215 test files and about 1,355 `test()` calls on d6154b3, run free with `AI_MOCK=1`, and on GitHub Actions on every push and pull request. [src: brew/test/] [src: brew/.github/workflows/test.yml:1-37] Counted from source, not from a run.\n- Rows for `db/`, `public/`, `test/`, `tools/`, `.github/` and the files the 26 Oct merge added are counted on d6154b3; the rest stay as counted on b91e364. [src: git ls-tree -l origin/main]\n\n### Folders\n\n| Folder | What it holds | Files | Size | Source |\n|---|---|---|---|---|\n| `reader/` | The read: orchestrator, stages, Ad Library fallback, product reader | 17 | 301 KB | [src: brew/reader/index.js:1-6] |\n| `connectors/` | Read-only accounts: Shopify, Meta, Google Ads and GA4, Klaviyo, Judge.me, Slack, marketplaces (off), the demo simulator | 11 | 193 KB | [src: brew/connectors/index.js:1-8] |\n| `jam2/` | Brew Studio engine (kept after the v2 screen retired): Brand Book store, rules, makers, engines, context, routes | 18 | 381 KB | [src: brew/jam2/studio.js:1-5] [src: memory brew-one-stage] |\n| `db/` | Postgres pool, migrations 001 to 010, ops jobs (status, parity, import, partner copy, clean gate, reset jams, reset brand, delete brand, connector ping) | 24 | 91 KB | [src: brew/db/index.js:1-4] [src: brew/db/brand-wipe.js:1-9] |\n| `pdf/` | Play PDF template, art and Chromium render | 12 | 2.9 MB (mostly fonts) | [src: brew/pdf/render.js] |\n| `public/` | The client: plain JS and CSS, no framework | 164 | 4.2 MB | [src: brew/README.md] |\n| `test/` | The suite, fixtures, paid probes | 228 | 1.9 MB | [src: brew/test/] |\n| `tools/` | Deploy, promote, audits, probes, resets, Slack app, sound build | 28 | 121 KB | [src: brew/tools/] |\n| `.github/` | One workflow, `test`: the deploy test gate on every push and pull request | 1 | 1.6 KB | [src: brew/.github/workflows/test.yml:1-9] |\n| `docs/` | Handover (15 Oct), production runbook, app review notes, Slack manifest, Shopify listing | 52 | 1.9 MB | [src: brew/docs/] |\n| `skills/` | Discipline skill files each Play is written with | 258 files in 52 folders | 2.4 MB | [src: brew/moves-engine.js:1-7] |\n| `sources/moves/` | 51 hand-made Arata Plays used as depth exemplars | 51 | part of 2.5 MB | [src: brew/moves-engine.js:1-7] |\n| `data/` | Play specs (66), studio styles, engines, catalog, families, Sloosh tool schemas | 11 | 506 KB | [src: brew/moves-engine.js:28] |\n| `prompts/` | `move-house.md`, the house prompt for Plays | 1 | 13 KB | [src: brew/moves-engine.js:29] |\n\n### The biggest client files\n\n| File | Size | Lines | Source |\n|---|---|---|---|\n| `public/app.js` | 877 KB | 5,997 | [src: brew/public/app.js] |\n| `public/brew.css` | 267 KB | | [src: brew/public/brew.css] |\n| `public/jam-room.js` | 81 KB | | [src: brew/public/jam-room.js] |\n| `public/live.js` | 61 KB | | [src: brew/public/live.js] |\n| `public/creative-stage.js` | 48 KB | | [src: brew/public/creative-stage.js] |\n\nNo client file has a test of its own. [src: brew/test/]\n\n### Top-level modules\n\n| Module | What it owns | Tests | Size |\n|---|---|---|---|\n| `ai-gap.js` | One specific fix per AI-answers gap card, from what Brew already holds | ai-gap, final-ff | 2.8 KB |\n| `ai-questions.js` | The shopper questions Brew asks the AI tools, each backed by search, listening or sales evidence | ai-questions | 14.7 KB |\n| `ai-standing.js` | Where the brand and its rivals stand in AI answers (the AI answers ring and column) | ai-standing, ai-questions | 8.0 KB |\n| `ai.js` | The shared AI client: one call shape for Claude or Gemini, streaming, schemas, spend metering | cadence-probe (paid probe), build-honesty, cadence-refresh, claims, ideas-probe (paid probe), memory-probe (paid probe), moves-evidence, listen-probe (paid probe) | 8.7 KB |\n| `alerts.js` | Ops alert emails (Vertex billing and quota, AI pause, treg balance, 5xx rate, Sloosh, worker down, stuck queue), once a day each | ops-guards | 8.3 KB |\n| `apify.js` | Apify client: run one actor, read its dataset, meter spend | listen-ideas-wiring | 4.3 KB |\n| `assortment.js` | Whose products a store sells: own label, other brands or both | assortment | 8.3 KB |\n| `auth.js` | Google sign-in, brand claiming, teams, invites, views, admins and team email | claim-rules, ga4-property-guard, ops-auth-connectors, phase3-pg, security-fixes, team-seats | 34.5 KB |\n| `brand-book-read.js` | The Brand Book as the read finds it: chapters from public evidence plus one vision call | brand-book, brand-book-guards | 36.8 KB |\n| `brand-book-routes.js` | Brand Book API: view, team edits, import, refresh, ask | brand-book, brand-book-guards | 31.3 KB |\n| `brand-ctx.js` | Which brand a request, tick or job runs for (AsyncLocalStorage) | another-take, cta-make, film-board, honesty, jam-chips, jam-product-match, jam-story, job-status, landing-draft, jam-team, ops-rows, options, round2-budget, v1-studio | 2.9 KB |\n| `brand-enrich.js` | Fresh Instagram, TikTok and YouTube reads for the Brand Book, capped and saved once | brand-book | 7.0 KB |\n| `brand-kit.js` | The shared Brand Book link and kit download (brand.md, brand.json, llms.txt, kit.zip, PDF) | brand-fonts, brand-book, brand-book-guards | 15.4 KB |\n| `brand-learnings.js` | Learnings from pasted or dropped context: extract, review, then update brief, memory, cards and Plays | brand-learnings, drop-read, evidence-pulse, learned-rank, honesty, stock-and-tried | 65.0 KB |\n| `brand-memory.js` | Brand memory: a versioned markdown repo per brand with search and a consolidate pass | brand-learnings, cadence-probe (paid probe), brand-memory, channel-fit, memory-probe (paid probe), voice-pick | 54.9 KB |\n| `brand-pack.js` | Loading, caching and healing a brand pack; the viewer-specific pack | access, audit-fixes, brand-book, brand-learnings, build-honesty, cadence-probe (paid probe), community-gate, demo-mode, drafts-engagement, fact-truth, feed-gate, first-drafts, facts-desk, health, ideas-probe (paid probe), honesty, image-fallback, listen-probe (paid probe), listen-ideas-wiring, market-money, listen-wider, market, memory-probe (paid probe), lean-cadence, objects-pg, one-count, phase3-pg, live-weekly, product-match, qa-final-access, qv2-cache, qv1-storage, moves-cadence, retention-loops, read-picks, on-connect, rewrite-pot, qa-access, qv1-roles-security, stock-and-tried, stale-sweep, team-views, shopify-catalog | 62.8 KB |\n| `brew-name.js` | Heals old wording in saved data on read (the product's old name becomes Brew, soft role names) | brew-roles-soft, brew-name-address, honesty, no-skill-talk | 9.3 KB |\n| `brief-status.js` | Status of a brief sent to our team: sent, received, in progress, needs info, delivered | brief-reference, brief-staff, brief-tune-drop, jam-team, sent-time-wa | 7.9 KB |\n| `brief.js` | The brand brief every Play is written from, with quote and number checks | audit-fixes, build-honesty, on-connect | 14.2 KB |\n| `budget-match.js` | Checks a Meta budget draft against its card and the connected account | ops-rows, round2-budget | 2.6 KB |\n| `budget.js` | The day AI budget by kind, with a share per brand | finals, jobs-pg, ops-guards | 6.6 KB |\n| `build-events.js` | Build progress lines on Postgres so any instance can stream a build | jobs-pg, qv1-roles-security | 2.5 KB |\n| `build.js` | The per-brand pipeline: read, check, brief, Plays, cards, PDFs, rewrites, connect runs, resume | audit-fixes, brand-learnings, build-honesty, facts-desk, feed-gate, honesty, market, live-weekly, one-count, on-connect, qa-final-access, qa-access, qv1-roles-security, read-picks, retention-loops, qv2-cache, rewrite-pot, shopify-catalog, stale-sweep, stock-and-tried | 211.3 KB |\n| `bus.js` | Messages between instances (Postgres table plus NOTIFY) | phase3-pg | 1.3 KB |\n| `calendar.js` | Holidays and commerce dates per market, with weekly confirmation | calendar-confirmed, honesty, pulse-calendar-video | 16.5 KB |\n| `card-from.js` | The plain \"From\" line at the top of every card | card-from | 7.0 KB |\n| `card-nums.js` | Card counts that follow today's fact sheet | card-rules-nums, fact-truth, round2-truth | 11.1 KB |\n| `card-page.js` | The card page laid out as a decision, kept in the pack | none | 10.4 KB |\n| `card-plan.js` | A card's ground-work plan, the input to its jam | card-plan, code-blocks, jam2, plain-plumbing | 20.8 KB |\n| `cards-gen.js` | Feed cards from a finished Play: words, button, asset, fact gate | audit-server-fixes, audit-fixes, cadence-probe (paid probe), build-honesty, card-medium, card-rules-nums, cta-names, card-asset, claim-kinds, final-ff, first-drafts, creative-catalog, non-shopify, rival-ad | 49.5 KB |\n| `catalog-rank.js` | Order of products on a catalog card, best sellers first | catalog-cards | 2.0 KB |\n| `channel-fit.js` | How a card fits the channels the viewer said they run | channel-fit | 8.7 KB |\n| `claims.js` | Claims Brew cannot back: flags, copy checks, draft cleaning, the writers' claims rule | claims, fact-truth, move-load-fixes, one-stage, qa-checks, round2-claims, writer-slips | 29.8 KB |\n| `closed-gate.js` | Team-only access to a store still behind Shopify's password page | closed-store | 6.9 KB |\n| `code-md.js` | Code inside written words is kept as code | code-blocks | 2.2 KB |\n| `color-cast.js` | Removes the warm cast image models add | claims | 3.6 KB |\n| `community-gate.js` | Which public threads and communities Brew may point a brand at | community-gate, listen-wider | 20.6 KB |\n| `confirm-remind.js` | Reminders when nobody checks the read or opens the feed (3 h, then a day) | confirm-remind | 11.9 KB |\n| `counters.js` | Day counters shared by every instance (Postgres) | jobs-pg | 3.7 KB |\n| `creative-catalog.js` | What Brew can have made: formats, families, the prompt block | creative-catalog | 7.3 KB |\n| `demo-data.js` | Simulated connected-account numbers for the demo, built from the real read (Dummy) | audit-server-fixes, round2-budget | 22.4 KB |\n| `demo-mode.js` | Demo sandbox per visitor, send guard (Dummy) | demo-mode | 4.1 KB |\n| `demo-routes.js` | Demo picker, presenter controls, simulated onboarding (Dummy) | counts-one-source, final-ff, one-count | 13.5 KB |\n| `derive.js` | facts.json and config.json from the read | build-honesty, market-money, market, qa-final-access, qa-checks, sellable | 10.9 KB |\n| `digest.js` | The weekly Monday digest email and Slack post, no AI | retention-loops | 20.8 KB |\n| `draft-mocks.js` | A first draft shown where it will live (inbox, WhatsApp, page) | code-blocks, first-drafts | 12.6 KB |\n| `draft-quality.js` | The free pixel check and look judge on first drafts | draft-quality, statics-layout | 10.3 KB |\n| `drafts-bg.js` | First drafts on cards before anyone opens a jam, plus healing saved drafts | cadence-probe (paid probe), baked-words, draft-same-card, code-blocks, first-drafts, drafts-engagement, image-fallback, moves-cadence, one-stage | 61.4 KB |\n| `drafts.js` | One-tap first drafts inside a jam (image, video, voice, text) | first-drafts | 39.4 KB |\n| `drop-read.js` | Reads a dropped file (text, office, PDF, image) into text | brand-book-guards, brand-book, brand-fonts, drop-read | 9.4 KB |\n| `drop.js` | Drop anything: memory, preferences, once, references | brief-tune-drop, references | 1.9 KB |\n| `evidence.js` | The proof sheet behind every card, no AI | evidence-plain, evidence-pulse, evidence-team, watch-shelf | 23.6 KB |\n| `fact-gate.js` | Every money amount and percent on a card must be in the fact sheet | audit-fixes, facts-desk | 5.8 KB |\n| `facts-desk.js` | The fact sheet: corrections, the daily price check, one truth per viewer | connector-robust, fact-truth, facts-desk, non-shopify, one-count, round2-truth, team-views | 42.5 KB |\n| `feed-service.js` | Workspaces, card store, ranker, seats, stories, watchers, the jam and brief routes, Slack in | audit-server-fixes, cadence-refresh, brand-learnings, brief-tune-drop, festival-past, feed-engagement, jam-chips, qa-access, qv3-guards, one-count, storefront-v1, read-picks, team-views | 340.3 KB |\n| `festival-past.js` | Marks festival Plays as ended after the date | festival-past | 2.3 KB |\n| `film-board.js` | The founder storyboard for a film brief | film-board | 4.8 KB |\n| `finals-routes.js` | Make the final routes: sheet, quote, make, revise | finals-routes | 35.0 KB |\n| `finals.js` | Finals on Sloosh with a Gemini fallback; quote first, never paid twice | finals | 42.7 KB |\n| `font-meta.js` | Reads family, weight and style from a font file | brand-fonts | 5.1 KB |\n| `for-us.js` | The \"For us\" line ending every rival and news story | final-ff, stories-for-us | 2.8 KB |\n| `fx.js` | Converts USD figures into the brand's currency | market-money | 2.6 KB |\n| `gemini-client.js` | Gemini on Vertex behind the Anthropic client shape; price table | gemini-client | 8.6 KB |\n| `gen-store.js` | Generated media copied to the bucket and served from /gen/ | another-take, cadence-probe (paid probe), cta-make, job-status, landing-draft, make-claim, image-fallback, v1-studio-sets, v1-studio, video-finish | 4.4 KB |\n| `handoff.js` | The jam hand-off text and the signed read-only /h/ page | access, honesty | 25.2 KB |\n| `health.js` | Store health rings scored from public data | ai-ring-one-check, build-honesty, health-speed, health, one-count, shopify-catalog | 18.3 KB |\n| `http-zip.js` | Brotli or gzip on text answers over 1 KB, off the main thread | qv2-http | 3.4 KB |\n| `ideas.js` | The ideas stream: ready-to-post social ideas with real places to post | community-gate, listen-wider, ideas-probe (paid probe), team-views | 66.3 KB |\n| `image-guard.js` | Checks every generated picture shows the right product; look judge wiring | draft-quality, drafts-engagement, image-fallback, img-norm, image-guard | 15.0 KB |\n| `img-norm.js` | Normalises pictures for models (format, flattening on white) | draft-quality, img-norm | 6.9 KB |\n| `impact.js` | Projected impact range for a change version, never a promise | jam-chips | 9.2 KB |\n| `instance.js` | One random id per process | qv1-roles-security | 0.3 KB |\n| `jam-answer.js` | Jam chat answers that never make a version by accident | jam-answer, round2-claims | 7.9 KB |\n| `jam-brief.js` | The jam brief document, its edits, ship and freeze (BR-n) | brand-learnings, card-plan, brief-tune-drop, final-ff, jam-answer, jam-team, jam-brief-leak | 49.3 KB |\n| `jam-mail.js` | Jam emails to the team: tags, asks, batched replies, mute links | brief-tune-drop, jam-mail | 17.0 KB |\n| `jams.js` | Team jams shared by the brand's team | jam-team, jams, qv1-storage, phase3-pg | 12.5 KB |\n| `jobs.js` | The Postgres job queue | jobs-pg, qv1-roles-security | 8.6 KB |\n| `learn.js` | Version graph and taste learning for the jam loop | another-take, brand-memory, cta-make, jam-team, landing-draft, options, v1-studio | 18.3 KB |\n| `legal-pages.js` | Privacy, Terms and the 404 page | qa-access | 6.2 KB |\n| `listen-watch.js` | Listening: what people say about the brand, rivals and category across sources | listen-ideas-wiring, listen-probe (paid probe), listen-namesake, listen-signals, watch-shelf | 111.1 KB |\n| `live-watch.js` | Catalog watcher (3 h) and the weekly AI-answers check | cadence-refresh | 25.1 KB |\n| `mail-layout.js` | One layout for every Brew email | brief-tune-drop | 6.7 KB |\n| `market-pulse.js` | Weekly market numbers: shelves, marketplaces, traffic, trends | pulse-calendar-video, watch-shelf | 45.6 KB |\n| `market.js` | Where a brand sells, apart from where it is registered | market, non-shopify, qa-access | 17.9 KB |\n| `measure-families.js` | Action families and how each is judged (measurement is cut; used for impact and copy) | jam-coverage, measure-families, moves-evidence | 23.0 KB |\n| `measure-spec.js` | How we measure it, from the brief (cut feature, kept code) | none | 9.6 KB |\n| `measure-stats.js` | Result maths for launches (cut feature, kept code) | measure-stats | 10.8 KB |\n| `media.js` | Draft media chains: image, video, voice, with fallbacks | media-chain | 5.8 KB |\n| `member-ctx.js` | Who acts on a workspace, per request | private-leaks, security-fixes, team-seats | 4.3 KB |\n| `member-tuning.js` | Your feed: per-member weights, topics, notes, ignored signals | drop-read, feed-engagement, brief-tune-drop, setup-answers | 14.0 KB |\n| `memory-routes.js` | Brand memory routes | access, brand-memory | 3.4 KB |\n| `model-ctx.js` | The composer's model pick for one request | none | 1.1 KB |\n| `move-index.js` | Rebuilds the Play index (Move 00) at load | move-load-fixes | 3.2 KB |\n| `move-label.js` | How a Play number is said to a person | final-ff, move-label, pdf-cover | 2.9 KB |\n| `move-tidy.js` | Tidies saved Plays at load, nothing written back | move-tidy | 4.7 KB |\n| `moved.js` | Which site is a brand's home (MOVED_TO_PROD, STAGING_HOME) | moved | 4.7 KB |\n| `moves-cadence.js` | Weekly listening and automation Plays (1001 and up) | audit-fixes, cadence-probe (paid probe), brand-learnings, moves-cadence, shopify-catalog, team-views | 71.6 KB |\n| `moves-engine.js` | Writes, verifies and fixes each Play; the index; the scheduler | audit-fixes, build-honesty, move-cites, moves-evidence | 77.9 KB |\n| `moves.js` | A brand's Play documents and passages | honesty | 3.9 KB |\n| `notes.js` | Margin notes on cards | final-ff, notes | 6.4 KB |\n| `objects.js` | Stored objects: Postgres rows, parted documents, bucket mirror and read-through | objects-pg, qv2-cache, qv1-storage, qv1-roles-security, retired-pg, partner-copy-pg, phase3-pg | 19.5 KB |\n| `on-connect.js` | What a connected account changes: team view, baselines, health readings | on-connect, ops-guards | 8.0 KB |\n| `ops-rows.js` | Ad account change rows name real campaigns | ops-rows | 7.1 KB |\n| `pack-numbers.js` | One number, one source for headline counts | build-honesty, honest-copy, move-cites, non-shopify, one-count, qa-access | 19.9 KB |\n| `plain.js` | Plain-word rewrite of every card, numbers checked in code | claim-kinds, final-ff, evidence-plain, move-label, plain-plumbing, private-leaks, plain | 20.7 KB |\n| `presence.js` | Who is in a jam right now | none | 2.7 KB |\n| `product-name.js` | The product's public name in one constant, `PRODUCT_NAME`, still \"Brew\", and the head script that hands it to the browser; a rename is one line | product-name, and imported by the email, page and Slack modules | 0.8 KB |\n| `product-match.js` | Which product a piece of copy is about | card-asset, draft-quality, drafts-engagement, film-board, jam-product-match, jam2, jam-story, product-match, sellable | 12.4 KB |\n| `proof-logic.js` | Whether the proof proves the claim | claim-kinds, evidence-pulse, evidence-team, plain-plumbing, proof-logic | 22.1 KB |\n| `publish-pack.js` | The publish pack zip per change version | code-blocks, film-board, jam-chips, jam-closeout, v1-studio | 31.0 KB |\n| `publish-ready.js` | Ready to publish: parts, limits and the final check | jam-closeout, v1-studio, video-finish, v1-studio-sets | 17.0 KB |\n| `recap.js` | The Recap ring: what happened since your last visit | recap | 9.0 KB |\n| `references.js` | Brand references uploaded for the generators | jam2, references | 7.9 KB |\n| `refresh.js` | Keeping Plays current: material changes, triage, rewrite | audit-fixes, live-weekly, stock-and-tried | 11.8 KB |\n| `remix.js` | The studio and jam engine: changes, versions, makes, packs, CTA makes | another-take, card-medium, card-action-map, card-plan, cta-names, cta-make, listen-ideas-wiring, jam-product-match, jam-story, job-status, jam-team, landing-draft, one-stage, options, plain-plumbing, ops-rows, recipe-keys, v1-studio | 305.1 KB |\n| `research.js` | Story rings and watcher research (ads, trends, news, how-to, viral) | cadence-refresh, stories-fallback, stories-life | 62.4 KB |\n| `retire.js` | One live revision on bucket deploys; brand wipe markers | retired-pg, retire | 4.8 KB |\n| `rewrite-pot.js` | The weekly rewrite budget per brand and its order | market, rewrite-pot, stale-sweep | 5.5 KB |\n| `rival-ad.js` | Make our version of a rival ad: read how it is made, then remake | rival-ad | 15.5 KB |\n| `roles.js` | ROLE, the background lease, leaderOnly | lease-child (paid probe) | 3.0 KB |\n| `safe-path.js` | Keeps file paths inside public/ or a pack | safe-path | 0.6 KB |\n| `same-ask.js` | One card per ask across Plays | round2-truth, same-ask | 12.0 KB |\n| `seed-template.js` | The seed for a generated brand; CTA names; connectors per platform | card-action-map, card-plan, cta-names, font-name, honesty, qa-final-access, non-shopify | 22.3 KB |\n| `server.js` | Boot, env, timers, the request chain, builder proxy, shutdown | none | 142.2 KB |\n| `sessions.js` | Revocable sign-in sessions (Postgres) | phase3-pg, qv1-roles-security | 4.0 KB |\n| `shared-doc.js` | Merging a document several instances change at once | shared-doc-merge | 7.0 KB |\n| `shelf.js` | Quick-commerce shelves and marketplace listings, read from outside | watch-shelf | 15.0 KB |\n| `shopify-app.js` | The public Shopify app: install, embedded pages, webhooks | closed-store, shopify-embed-pdf, shopify-catalog, shopify-app | 29.2 KB |\n| `slack-routes.js` | Slack events and buttons, signed | slack-relay, slack | 8.5 KB |\n| `sloosh-auth.js` | Brew's Sloosh workspace connection (OAuth 2.1, PKCE) | sloosh-mcp | 9.4 KB |\n| `sloosh-mcp.js` | Sloosh MCP client over HTTP | sloosh-mcp | 19.2 KB |\n| `sloosh-prompt.js` | One brief for every picture and clip, drafts and finals | finals-routes, rival-ad, sloosh-prompt, statics-layout, veo-reel-clean | 27.9 KB |\n| `sloosh-spaces.js` | Which Sloosh Space fits a creative family | finals | 13.2 KB |\n| `small-page.js` | Small server pages (invite, access, email settings) | none | 2.0 KB |\n| `social-feed.js` | Listening and ideas as cards; their background scheduler | community-gate, listen-ideas-wiring, listen-wider, listen-signals, non-shopify, qv1-roles-security, team-views | 47.9 KB |\n| `source-health.js` | Success rate of every treg and Apify source | watch-shelf | 4.1 KB |\n| `stat-check.js` | A Play cover number must mean what its label says | stat-check | 6.1 KB |\n| `statics.js` | Static Meta ads from Play 21, words set in real type | claims, ops-guards, statics-layout, team-views | 13.9 KB |\n| `store-facts.js` | What a store is on any platform | none | 2.3 KB |\n| `store.js` | Workspace persistence (tagged Maps and Sets) | objects-pg, phase3-pg, qv1-storage, store-flush | 7.9 KB |\n| `studio.js` | Families, fields and knobs for every kind of change | audit-server-fixes, card-action-map, card-plan, jam-closeout, jam-story, jam-chips, jam-product-match, film-board, listen-ideas-wiring, one-stage, ops-rows, round2-budget, ui-audit-r3, writer-slips | 89.9 KB |\n| `team-brief.js` | The team brief per deliverable, its recipients, PDF and AI edits | team-brief | 29.6 KB |\n| `text-check.js` | Spelling check of on-screen words in video finals | text-check | 5.4 KB |\n| `text-fit.js` | Shared wording rules: sentence case, one-take wording | audit-server-fixes, plain-plumbing, title-case, ui-audit-r3 | 11.7 KB |\n| `treg-map.js` | Every outside capability declared once; health-first routing | treg-map, watch-shelf | 22.4 KB |\n| `treg.js` | The shared treg client: cache by signal, metering, day cap | ideas-probe (paid probe), listen-probe (paid probe), pulse-calendar-video, treg-cache | 11.3 KB |\n| `value.js` | Play grades (impact, confidence, effort) and card value | feed-engagement, same-ask, value | 6.8 KB |\n| `vault.js` | Encrypted connector secrets, refresh, protected-connection guard | connector-robust, ops-auth-connectors, phase3-pg, partner-copy-pg, private-leaks, qv1-roles-security | 5.3 KB |\n| `vertex-media.js` | Veo video and Gemini voice on Vertex | veo-reel-clean | 7.9 KB |\n| `video-finish.js` | Captions, burn-in, cover and GIF for a finished video | video-finish | 12.7 KB |\n| `video-read.js` | Scene-by-scene read of a short video | pulse-calendar-video, video-read-youtube | 18.5 KB |\n| `viral-gate.js` | Which viral videos may be remade | viral-gate | 5.6 KB |\n| `viral.js` | Weekly viral video finder | viral-gate | 9.1 KB |\n| `watch-view.js` | The What Brew watches page | watch-shelf | 12.4 KB |\n### reader/\n\n| Module | What it owns | Tests | Size |\n|---|---|---|---|\n| `reader/index.js` | The read orchestrator: stages, deadlines, one retry, heal of saved reads | assortment, audit-fixes, build-honesty, qa-access, reader-retry, site-walk, shopify-catalog | 32.7 KB |\n| `reader/products.js` | Product URLs and product data on any platform | assortment, non-shopify | 18.4 KB |\n| `reader/util.js` | Fetcher, safeFetch, ledger, slug, helpers | honesty, non-shopify, shopify-catalog | 15.5 KB |\n| `reader/adlib.js` | Free headless Ad Library fallback (`adCall`) | adlib-fallback | 6.1 KB |\n| `reader/closed.js` | \"Not checked: behind Shopify's password page\" | shopify-catalog | 0.8 KB |\n| `reader/svg-logo.js` | Inline SVG logos | svg-logo | 1.3 KB |\n| `reader/stages/open.js` | Open the store: platform, market, pages, headless Shopify | market, non-shopify | 23.9 KB |\n| `reader/stages/brand.js` | Logo, colours, fonts, one-liner | font-name, non-shopify, read-picks, svg-logo | 13.6 KB |\n| `reader/stages/catalog.js` | The catalog (`CATALOG_V` 2) | non-shopify, read-picks | 20.5 KB |\n| `reader/stages/reviews.js` | Reviews on site and marketplaces (`REVIEWS_V` 2) | non-shopify | 36.0 KB |\n| `reader/stages/ads.js` | Own and rival Meta ads, rivals (`ADS_V` 5) | build-honesty, read-picks, shopify-catalog, reader-retry | 32.1 KB |\n| `reader/stages/site.js` | Checkout walk, tags, PageSpeed (`SITE_V` 4) | site-walk | 42.3 KB |\n| `reader/stages/answers.js` | AI answers, category, the one-liner | build-honesty, non-shopify, reader-retry | 21.3 KB |\n| `reader/stages/socials.js` | Instagram, YouTube, the Films card (`SOCIALS_V` 2) | socials-search | 13.0 KB |\n| `reader/stages/company.js` | Founders, founding, funding, press (`COMPANY_V` 3) | none | 6.6 KB |\n| `reader/stages/named.js` | Whether AI answers name the brand | named-stage | 3.9 KB |\n| `reader/stages/admin.js` | A closed store read from the Shopify Admin API | closed-store, shopify-catalog | 12.8 KB |\n\n### connectors/\n\n| Module | What it owns | Tests | Size |\n|---|---|---|---|\n| `connectors/index.js` | Connect, sync cadence, backoff, stale rules, protected guard, routes | connector-robust, ga4-property-guard, honesty, ops-auth-connectors, phase3-pg, private-leaks, qv1-roles-security, security-fixes, team-views | 59.6 KB |\n| `connectors/common.js` | Card and ledger shapes, `realRows`, backoff | connector-robust, jam-chips, honesty, meta-connector | 8.9 KB |\n| `connectors/shopify.js` | Shopify Admin API 2026-04, read only | shopify-own-app, shopify-sync | 33.2 KB |\n| `connectors/meta.js` | Meta Marketing API, Graph v26.0, read only | connector-robust, meta-connector, ops-auth-connectors, round2-budget | 36.8 KB |\n| `connectors/google.js` | Google Ads and GA4 (OAuth or service account) | honesty, ops-auth-connectors | 24.8 KB |\n| `connectors/klaviyo.js` | Klaviyo by read-only key | security-fixes | 5.4 KB |\n| `connectors/reviews.js` | Judge.me by OAuth or token | honesty | 6.9 KB |\n| `connectors/slack.js` | Slack posting and channel join; never evidence | slack | 5.3 KB |\n| `connectors/market.js` | Marketplaces (switched off) | none | 7.0 KB |\n| `connectors/sim.js` | Simulated accounts for the demo (Dummy) | demo-mode | 5.1 KB |\n| `connectors/protected.js` | `PROTECTED_CONNECTIONS`, default `arata-in` | none | 0.4 KB |\n\n### jam2/\n\n| Module | What it owns | Tests | Size |\n|---|---|---|---|\n| `jam2/routes.js` | `/api/jam2` routes: Studio make, ask, slide, sketch; v2-only routes still mounted | jam2, make-claim, one-stage, v1-studio-sets | 73.1 KB |\n| `jam2/make.js` | The make layer: writer, cut-out, scene, type, priced edits | draft-quality, jam2 | 72.8 KB |\n| `jam2/studio.js` | Brew Studio: style library, defaults, plan, make, price gate | first-look, jam2, one-stage, setup-tab, v1-studio, v1-studio-sets | 53.6 KB |\n| `jam2/brandbook.js` | The Brand Book store and its views by scope | brand-fonts, brand-book, brand-book-guards, rules | 38.0 KB |\n| `jam2/creative.js` | Art direction, product-locked shoot, critic, layout, extend | jam2 | 33.5 KB |\n| `jam2/engines.js` | Partner adapters: Vertex, Sloosh, Higgsfield, local | none | 19.7 KB |\n| `jam2/catalogue.js` | Recipes and sizes; the button-to-board map | jam2, v1-studio-sets | 19.1 KB |\n| `jam2/ready.js` | Ready-to-post links, signed | none | 11.3 KB |\n| `jam2/core.js` | The v2 jam model and `publicView` | jam2, meta-connector | 10.9 KB |\n| `jam2/rules.js` | The Brand Book rules chapter | rules | 9.8 KB |\n| `jam2/context.js` | What the Studio composer arrives with, and why | setup-tab, v1-studio | 9.6 KB |\n| `jam2/higgsfield.js` | Higgsfield API client | jam2 | 8.7 KB |\n| `jam2/profiles.js` | Cast and place profiles | none | 6.3 KB |\n| `jam2/store.js` | Studio jam storage (`jams-v2.json`) | jam2 | 5.1 KB |\n| `jam2/make-claim.js` | One paid make per board across instances | make-claim | 3.5 KB |\n| `jam2/slots.js` | Posting time slots | jam2 | 2.6 KB |\n| `jam2/ingredients.js` | Product ingredients helper | none | 2.2 KB |\n| `jam2/cutout-worker.js` | Background removal in a worker thread | none | 1.0 KB |\n\n### db/\n\n| Module | What it owns | Tests | Size |\n|---|---|---|---|\n| `db/index.js` | Pool, LISTEN connection, `q`, `tx`, statement timeout | jobs-pg, make-claim, objects-pg, phase3-pg, qv2-cache, qv1-roles-security, qv1-storage, retired-pg | 3.9 KB |\n| `db/migrate.js` | Runs `db/migrations/*.sql` in order | same as above | 1.9 KB |\n| `db/prod-clean.mjs` | The production clean gate | none | 9.9 KB |\n| `db/partner-copy.js` | Copy a partner from staging to production | partner-copy-pg | 14.7 KB |\n| `db/migrate-to-prod.mjs` | Entry for the partner copy job | none | 4.0 KB |\n| `db/import-bucket.mjs` | Import bucket objects newer than their row | none | 5.2 KB |\n| `db/parity.mjs` | Bucket and database parity check | none | 3.0 KB |\n| `db/reset-jams.mjs` | Jam-only reset on Postgres | none | 6.0 KB |\n| `db/brand-wipe.js` | What a brand reset or a data request deletion removes, the partner and protected guards, the dry run, the sweep, the audit row | brand-wipe-pg | 23.3 KB |\n| `db/wipe-cli.js` | Shared start of the two brand tools: arguments, database, bucket, stop marker | brand-wipe-pg | 2.3 KB |\n| `db/reset-brand.mjs` | One brand back to a fresh first run, connections kept | brand-wipe-pg | 1.1 KB |\n| `db/delete-brand.mjs` | A data request: all of a brand's data, one `data_deletions` row kept | brand-wipe-pg | 1.2 KB |\n| `db/status.mjs` | Connection states and table sizes | none | 2.9 KB |\n| `db/connector-ping.mjs` | Read-only check that connectors still read | none | 2.6 KB |\n\n### pdf/\n\n| Module | What it owns | Tests | Size |\n|---|---|---|---|\n| `pdf/template.js` | The Play PDF layout | brew-roles-soft, move-cites, pdf-cover | 26.0 KB |\n| `pdf/render.js` | Chromium render to PDF | first-drafts, move-tidy, video-finish | 7.9 KB |\n| `pdf/brand-art.js` | Cover art from the brand | none | 5.3 KB |",
  "Tomorrow": "| Item | Version | Tag |\n|---|---|---|\n| This map, regenerated from origin/main by a script on every handbook update | v1 | New |\n| `measure-families.js`, `measure-spec.js`, `measure-stats.js` (measurement is cut) | v2 | Changes: keep only what impact and copy use, delete the rest |\n| `jam2/` v2-only routes (boards, concept, approve, `/p`, `/brief`) | v2 | Goes, once no shared v2 links are in use |\n| `feed-service.js` (348 KB), `remix.js` (312 KB), `build.js` (216 KB), `public/app.js` (875 KB) | v3 | Changes: split by area |\n| A test for every module marked \"none\" that holds logic (`company.js`, `engines.js`, `ready.js`, `prod-clean.mjs`) | v2 | New |",
  "How we do it": "1. Before changing a behaviour, find its owner here, then read the module's first comment on origin/main:\n\n```bash\ngit -C /Users/param/Documents/ChatGPT/brew show origin/main:<path> | head -20\n```\n\n2. Find which tests load a module:\n\n```bash\ngit -C /Users/param/Documents/ChatGPT/brew grep -l \"<module>.js'\" origin/main -- test/\n```\n\n3. A new top-level module is copied into the image by `COPY *.js` automatically; a new folder must be added to the Dockerfile and to the folder check in `deploy.sh`. [src: brew/Dockerfile] [src: brew/deploy.sh:10]\n4. `deploy.sh` runs `node --check` on root, `db/`, `reader/`, `connectors/`, `pdf/` and `public/` files, but not `jam2/`. [src: brew/deploy.sh:8]",
  "Numbers": "| Metric | Definition | Where measured |\n|---|---|---|\n| Modules with no direct test | Top-level and folder modules no test imports | This page; 13 such modules today (Proposed to track) |\n| Largest file | Size of the largest server file | `git ls-tree -l`; `feed-service.js` 340 KB |\n| Test files and tests | Files in `test/` and `test()` calls | 209 files, about 1,314 calls |",
  "Open": "1. **Should the big four files be split before v2?** Proposal: split `feed-service.js` first (feed, jam routes, Slack in), one area per week, each behind the existing tests.\n2. **Should `jam2/` be renamed now that the v2 screen is gone?** Proposal: rename to `studio/` in v2 with the v2-only routes removed in the same change."
 }
}