---
id: "5.18"
title: "Engineering rules"
dept: engineering
status: draft
owner: Param
branded: false
last_verified: 2026-10-26
sources:
  - "brew origin/main: CLAUDE.md (all sections), SPEC.md 'Hard rules', SCOPE.md, DUMMY.md (three markers, rules that keep a dummy from passing as real)"
  - "brew origin/main: connectors/protected.js; db/prod-clean.mjs:1-6; roles.js:39; jobs.js:4-5"
  - "memory feed-for-all-brands, fix-as-product, prod-clean-only, never-disconnect-arata-meta, brew-qv-process, always-deploy-to-test, no-spend-while-building, keep-all-moves, brew-one-version, brew-external-data-skill, brew-parallel-sessions-deploy, brew-live-stores, brew-name-and-scope, treg-usage-rules"
---

# Engineering rules

## Answer

These are the rules every change to Brew follows, from any person or session, and each one exists because breaking it hurt a brand or cost money before.

## Today

### Truth

1. No invented numbers, quotes, founders, reviews or backstory. Every number traces to a ledger entry or a cited source; otherwise it says "to confirm". [src: brew/SPEC.md]
2. Observed, inferred and implication stay separate; "not observed" never means "absent"; never state a rival's motive; benchmarks are labelled. [src: brew/SPEC.md]
3. An error or a check that did not run is never shown as "none", "not found" or "0". Keep `error` on the item and say the check did not go through. [src: brew/CLAUDE.md]
4. A Play is never evidence; proof is real data, real voice, real numbers. [src: memory brew-proof-plain-make]
5. No disclaimers or AI labels on ad creative. [src: brew/SPEC.md]

### Every brand

6. A fix is done only when it works for any brand Brew could onboard, every card type, every widget and every view: platform, how it sells, market, name, how the site reads, background runs across deploys. Never a per-brand patch, hard-coded id or brand name. [src: brew/CLAUDE.md] [src: memory feed-for-all-brands]
7. Fix as product: shared cause in code, a test or audit that would have caught it, healed saved data, then deploy. A hand patch to a pack is only a stopgap and is said so. [src: memory fix-as-product]
8. Saved data heals itself: `heal()`, a stage or pack version bump, a load-time repair, wherever text is read. [src: brew/CLAUDE.md] [src: memory brew-one-version]
9. Add a case to `test/non-shopify.test.js` for every new kind of brand that breaks; add a check to `tools/audit-brand-book.mjs` and a guard test for every new Brand Book problem class. [src: brew/CLAUDE.md]

### Dummies and production

10. Anything simulated is marked in three places: a Dummy tag in the UI, a `DUMMY:` comment in the code, a row in `DUMMY.md`. Simulated rows are never evidence. [src: brew/DUMMY.md]
11. Nothing dummy, simulated or from testing ever reaches production; the clean gate refuses a promote on any finding. [src: memory prod-clean-only] [src: brew/db/prod-clean.mjs:1-6]
12. Never re-add a cut feature without a product decision. [src: brew/SCOPE.md]

### Partners and money

13. Never disconnect, reconnect or re-select Arata's Meta or Shopify connection; `PROTECTED_CONNECTIONS` guards it in code. Test disconnects on Cozy. [src: memory never-disconnect-arata-meta] [src: brew/connectors/protected.js]
14. Never wipe or reset the five design partners; risky tests run on Cozy or Zenant. [src: memory brew-live-stores]
15. No paid generation while only building; ask before a paid probe; never full reads just to test. [src: memory no-spend-while-building] [src: memory feed-for-all-brands]
16. Every treg call goes through `treg.js`; paid sources fall back to free ones; never repeat a call for data we hold. Load the `brew-external-data` skill before touching outside data. [src: brew/CLAUDE.md] [src: memory treg-usage-rules]
17. Cost cuts never drop Plays; make each Play cheaper. [src: memory keep-all-moves]
18. Every paid action shows its price and waits for a yes; nothing is paid twice (idempotency keys, make claims, saved job ids). [src: brew/jam2/studio.js:1-5] [src: brew/jobs.js:4-5]
19. Paid background work runs only on the lease holder. [src: brew/roles.js:39]

### Product shape

20. Read only in v1: Brew never writes to a brand's accounts or sends to its customers. [src: brew/SCOPE.md]
21. One version, then Redo it; never several options to pick from. [src: memory brew-one-version]
22. Say Plays to people; ids, routes and files may keep "move". [src: memory brew-qa-round2-2026-10-24]

### Shipping

23. Run `AI_MOCK=1 node --test test/*.test.js`, boot locally, then deploy with `./deploy.sh` from a clean tree; deploy right after a change is tested so Param can test on staging. [src: brew/CLAUDE.md] [src: memory always-deploy-to-test]
24. Commit only your own lines, push before deploying, deploy from a clean worktree of origin/main. [src: memory brew-parallel-sessions-deploy]
25. Production only through `tools/promote.sh`. [src: brew/.wt-prod/docs/production.md]
26. Phased work: a full QV round after each phase, three more before closing. [src: memory brew-qv-process]

## Tomorrow

| Item | Version | Tag |
|---|---|---|
| All rules above | v1 | Stays |
| Rule 20 (read only) | v3 | Changes: writes and sends arrive one at a time, each behind a person's yes |
| A CI check for rules that code can test (no undeclared constants, Dummy markers in step) | v1 | New |

## How we do it

1. Before a change, read `brew/CLAUDE.md`, `SCOPE.md` and `DUMMY.md` on origin/main.
2. Before shipping, walk this list and say in the commit which rules the change touched.
3. When a rule is broken, add the incident to the rule's source note and a guard test.

## Numbers

| Metric | Definition | Where measured |
|---|---|---|
| Clean gate findings | Findings per promote | `brew-prod-clean` job logs |
| Dummy markers in step | `DUMMY:` comments, UI tags and `DUMMY.md` rows that match | Proposed: a test that compares them (15 files carry `DUMMY:` today) [src: git grep "DUMMY:" origin/main] |
| Per-brand patches | Commits naming one brand slug in code | Proposed: a grep in CI |

## Open

1. **Should these rules be enforced in CI where possible?** Proposal: yes; start with the Dummy-marker check and a ban on brand slugs in code outside tests and data.
