Answer
This is the known debt in Brew on 26 Oct 2026, each item with its source, its risk and the fix, ranked so the riskiest is paid first.
Today
Risk: High can hurt a partner or cost money now; Medium slows us or breaks under growth; Low is tidiness.
Security and access
| # | Debt | Risk | Fix | Source |
|---|---|---|---|---|
| D-1 | The default compute service account holds project-wide secret access and run.admin, affecting about 15 other services |
High | Remove those grants from the default account; every service its own account | memory brew-prod-backend |
| D-2 | Shared jam and brief links never expire and cannot be revoked; the signature is 12 characters | Medium | Expiring, revocable links | brew/handoff.js:18-20 brew/docs/handover/engineering/09-security-and-access.md |
| D-3 | No route registry: about 150+ routes matched by regexes across modules, with no test of who may call each | High | One route table with an auth level per route and one test | brew/docs/handover/engineering/04-api-routes.md |
| D-4 | Seats filter cards, not server data | Medium | Enforce views on every route | brew/docs/handover/engineering/09-security-and-access.md |
| D-5 | The URL reader and photo fetch: private-range blocking on every redirect hop and Chromium --no-sandbox were flagged; photo fetch moved to safeFetch on 15 Oct, the rest is unverified |
Medium | Verify, then block private ranges on every hop | brew/docs/handover/engineering/09-security-and-access.md memory brew-audit-2026-10-15 |
| D-6 | A personal Gmail is on the admin list on staging (kept by choice) | Low | Already decided; production has one admin | memory brew-access-rules brew/tools/prod-env.sh:9 |
Architecture and storage
| # | Debt | Risk | Fix | Source |
|---|---|---|---|---|
| D-7 | Only objects and doc_parts hold brand data; no domain tables for connections, jams, finals or spend |
Medium | Real tables, connections first | brew/db/migrations/ memory brew-prod-backend |
| D-8 | One worker for every brand's builds | Medium | Per-brand build leases | memory brew-prod-backend |
| D-9 | Staging still mirrors every row to the bucket and reads through it | Low | Turn off after a clean month | brew/deploy.sh:39 |
| D-10 | The demo runs on the bucket with retire.js, a second storage path to maintain |
Medium | Demo on Postgres, then remove retire.js |
brew/tools/deploy-demo.sh brew/retire.js |
| D-11 | tools/reset-jams.sh is bucket era and still runs against the bucket on a Postgres site. Partly paid 26 Oct: db/reset-brand.mjs and db/delete-brand.mjs replace the brand tools, and tools/reset-brand.sh and tools/flush-live.sh exit 3 unless STORAGE=gcs |
Low | Give tools/reset-jams.sh the same guard, then delete all three |
memory brew-jam-reset brew/tools/reset-jams.sh:1-6 brew/tools/reset-brand.sh:11-19 brew/tools/flush-live.sh:17-26 brew commit e3e0fb4 |
| D-12 | Workspace ids are short random hex and act as the bearer key | Medium | 128-bit ids tied to their owner | brew/docs/handover/engineering/09-security-and-access.md |
Code health
| # | Debt | Risk | Fix | Source |
|---|---|---|---|---|
| D-13 | Giant files: public/app.js 877 KB and 5,997 lines, feed-service.js 340 KB, remix.js 305 KB, build.js 211 KB, brew.css 267 KB |
Medium | Split by area behind existing tests | git ls-tree -l origin/main |
| D-14 | No lint or type checks; the demo deploy runs no tests. Partly paid 26 Oct: GitHub Actions runs the suite on every push and pull request | Medium | Lint and node --check in the Action; tests in deploy-demo |
brew/.github/workflows/test.yml:1-37 brew/docs/handover/engineering/08-testing-and-qa.md brew commit fccf3cb |
| D-15 | No client tests; no ranking fixtures | Medium | Headless smoke of feed and jam; ranking fixtures from five brands | brew/test/ |
| D-16 | Cut-feature code still in the tree: measurement modules, rollback and "irreversible" fields in the studio, the Pro cap lift | Low | Delete what impact and copy do not use | brew/remix.js:1-6 brew/measure-spec.js brew/docs/handover/engineering/10-dummy-to-real.md |
| D-17 | Jam v2-only routes still mounted after the screen retired; header comments still say "?v=2 only" | Low | Remove after checking shared links | brew/jam2/routes.js:1 memory brew-one-stage |
| D-18 | Comments that contradict settings: Arata's home in deploy.sh and moved.js |
Low | Fix the comments | brew/deploy.sh:51 brew/moved.js:5-6 |
| D-19 | deploy.sh runs node --check on everything but jam2/ |
Low | Add jam2/*.js |
brew/deploy.sh:8 |
| D-20 | brew-name.js rewrites old names on every read instead of a one-time data migration |
Low | Migrate saved data once, then remove | brew/docs/handover/engineering/10-dummy-to-real.md |
| D-21 | Two Claude stacks and treg calls that bypass treg.js were flagged on 15 Oct |
Medium | Recheck; route all through ai.js and treg.js |
brew/docs/handover/engineering/05-ai-and-external-data.md |
| D-22 | The external-data audit.py lived outside the repo and lagged stage versions |
Low | Keep it in the repo and read versions from code | brew/docs/audit-2026-10-24-design-partners.md |
Product correctness
| # | Debt | Risk | Fix | Source |
|---|---|---|---|---|
| D-23 | Most Plays never reach "verified"; flagged claims stay until rewritten | High | Converge the claims check and fix; show claims to review | brew/moves-engine.js:620-626 brew/docs/handover/engineering/11-known-issues-and-debt.md |
| D-24 | The same ask repeats across Plays ("fix the pack prices" on about six cards) and is deduped only at serve time | Medium | Dedupe at write time | memory brew-arata-reload-2026-10-20 |
| D-25 | The read is proven mostly on Shopify; custom, bot-protected and size-picker stores are partly untested | Medium | A 15 to 20 store batch read on mocks and cheap partial runs | memory brew-checkout-walk brew/CLAUDE.md |
| D-26 | Cards in "we" voice; team named three ways; first look still in the panel; review-quote attribution | Low | Fix in the writers | memory brew-qa-round2-2026-10-24 memory brew-qa-audit-2026-10-20 memory brew-jam-rca-2026-10-26 |
| D-27 | A PUMA statics picture with drawn placeholder text; maker not traced | Low | Trace and add a look check | brew/docs/audit-2026-10-24-design-partners.md |
| D-28 | The Meta budget card can judge campaigns still learning; old shared pages and plain words for team cards need a one-time cleanup | Medium | Learning-phase rule; cleanup with Param's OK | memory brew-meta-connector-qa |
Ops
| # | Debt | Risk | Fix | Source |
|---|---|---|---|---|
| D-29 | No record of which sha production serves, except revision labels | Medium | Show the sha on /api/config and log each promote |
brew/tools/promote.sh:119 |
| D-30 | The first load after a release is slow | Medium | Warm more before the probe passes | memory brew-qa-round2-2026-10-24 |
Tomorrow
| Item | Version | Tag |
|---|---|---|
| D-1, D-3, D-23 paid before more partners onboard | v1 | New |
| D-14 finished: lint and checks in CI | v1 | Changes |
| D-7, D-8, D-10, D-12, D-13 | v2 | New |
| D-11, D-16 to D-20 | v1 | Goes |
How we do it
- Every new debt found goes here with a source, risk and fix the day it is found.
- Fixing a debt item means the shared cause, a test or audit, and healed data; then strike it here with the commit. memory fix-as-product
- Review this list at the start of each phase of work.
Numbers
| Metric | Definition | Where measured |
|---|---|---|
| Open debt by risk | Count of High, Medium, Low items | This page: 3 High, 16 Medium, 11 Low today |
| Debt paid per week | Items struck with a commit | This page (Proposed) |
Open
- Which High item first, now that CI runs? Proposal: D-1 this week, then D-3.
- Can D-1 be fixed without breaking the other services? Proposal: list the 15 services and give each its own account first, then remove the default grants.