{
 "id": "8.4",
 "title": "Wipe data and reset jams",
 "department": "Ops and infrastructure",
 "department_slug": "ops-and-infrastructure",
 "direction": null,
 "branded": false,
 "status": "draft",
 "owner": "Param",
 "last_verified": "2026-10-26",
 "holds": "What each wipes, what it never touches",
 "urls": {
  "html": "https://handbook.joinsquareup.com/ops-and-infrastructure/wipe-data-and-reset-jams",
  "markdown": "https://handbook.joinsquareup.com/ops-and-infrastructure/wipe-data-and-reset-jams.md",
  "json": "https://handbook.joinsquareup.com/ops-and-infrastructure/wipe-data-and-reset-jams.json"
 },
 "other_directions": [],
 "tldr": {
  "headline": "Three ways to start over, and none of them touch connections",
  "points": [
   {
    "icon": "gear",
    "text": "Jam reset, brand reset and full flush each remove different things; all run as brew-ops jobs."
   },
   {
    "icon": "lock",
    "text": "Both brand tools are dry runs until --yes, and refuse while a job is running."
   },
   {
    "icon": "people",
    "text": "The five design partners are refused in code unless a partner override is given."
   },
   {
    "icon": "link",
    "text": "Resets keep connections byte for byte; Arata's are never deleted by the tool."
   },
   {
    "icon": "warn",
    "text": "There is no Postgres full flush; flushing means a brand reset per slug."
   }
  ],
  "stat": {
   "value": "5",
   "label": "Design partners protected from resets"
  },
  "decide": "May a brand reset run on production, and what clears cache and media?",
  "mood": "waiting"
 },
 "sources": [
  "brew origin/main d6154b3: db/reset-jams.mjs:1-30, db/reset-brand.mjs:1-13, db/delete-brand.mjs:1-12, db/brand-wipe.js:1-32, 155-185, 214-241, db/wipe-cli.js:9-22, tools/reset-jams.sh:1-30, tools/reset-brand.sh:1-20, tools/flush-live.sh:1-26, retire.js:1-40, tools/prod-env.sh:9, docs/production.md:66-110, test/brand-wipe-pg.test.js:46-142",
  "brew commit e3e0fb4; deploy state 26 Oct: staging deploying, production unchanged",
  "memory brew-wipe-data, brew-jam-reset, brew-pro-switch-and-flush, brew-live-stores, never-disconnect-arata-meta, brew-storage"
 ],
 "open_questions": [
  "**May a brand reset run on production?** The code allows it, with no archive. Proposal: no; production runs only `db/delete-brand.mjs` for a data request.",
  "**What clears the cache and made media on Postgres?** Proposal: add it to `db/reset-brand.mjs` behind a `--with-cache` flag, so \"wipe data\" is one job."
 ],
 "parts": {
  "Answer": "There are three ways to start over, a jam reset, a brand reset and a full flush, plus a deletion for a data request; this page says what each removes, what it never touches and which tool to run now that both sites keep their records in Postgres.",
  "Today": "### What each one does\n\n| | Jam reset | Brand reset, \"wipe data\" | Data request deletion | Full flush |\n|---|---|---|---|---|\n| Tool | `db/reset-jams.mjs` as job `brew-ops` [src: brew/db/reset-jams.mjs:1-19] | `db/reset-brand.mjs` as job `brew-ops` [src: brew/db/reset-brand.mjs:1-4] | `db/delete-brand.mjs` as job `brew-ops`, or `brew-prod-ops` on production [src: brew/db/delete-brand.mjs:1-4] | `tools/flush-live.sh`, bucket era, refuses on Postgres [src: brew/tools/flush-live.sh:17-26] |\n| Removes | v1 jams, Studio jams, jam and remix state in workspaces [src: brew/db/reset-jams.mjs:1-19] | rows under `brands/<slug>/`, the brand's workspaces, build progress, its queued and finished jobs, bus messages, the brand folder's bucket files [src: brew/db/reset-brand.mjs:5-6] | all of the brand: rows with our stored tokens, workspaces, `_deleted/` copies, build progress, jobs, bus, counters, access log, every bucket version, media only it points at [src: brew/db/delete-brand.mjs:5-7] | every brand, every workspace, made and research media [src: brew/tools/flush-live.sh:6-9] |\n| Keeps | cards, Plays, drafts, learnings, connections [src: brew/db/reset-jams.mjs:1-19] | `private/connections.json`, `private/vault/`, `live/`, `private/live/`, `private/live-base.json`, `private/connected-ledger.json`, checked byte for byte afterwards [src: brew/db/reset-brand.mjs:8-9; brew/db/brand-wipe.js:17, 235] | one `data_deletions` row [src: brew/db/delete-brand.mjs:7-8] | `brands/_brew/`, `_cache/`, `control/live.json`, `backups/` [src: brew/tools/flush-live.sh:10-12] |\n| Copy kept | `_deleted/jams-<time>/` [src: memory brew-jam-reset] | `_deleted/brand-<slug>-<time>/` on staging, none on production [src: brew/db/wipe-cli.js:18-20] | none [src: brew/db/wipe-cli.js:19] | `_deleted/<time>/` unless `NO_ARCHIVE=1` [src: brew/tools/flush-live.sh:6] |\n| Never calls a platform | yes | yes | yes, and prints the grants the brand revokes itself [src: brew/db/brand-wipe.js:7, 240] | yes |\n\n- Both brand tools are dry runs until `--yes`, and print every row, workspace, job and file they would remove. [src: brew/db/brand-wipe.js:2, 135-149, 218]\n- Both refuse while a job for the brand is running. [src: brew/db/brand-wipe.js:219]\n- `tools/reset-brand.sh` and `tools/flush-live.sh` now exit 3 unless `STORAGE=gcs`, and print the `brew-ops` commands instead. [src: brew/tools/reset-brand.sh:11-19; brew/tools/flush-live.sh:17-26]\n- There is no Postgres full flush. A flush is a brand reset per slug. [src: brew/tools/flush-live.sh:21; brew/docs/production.md:73-77]\n- The brand reset does not touch the treg and Apify cache or made media, which the \"wipe data\" steps also clear. [src: brew/db/reset-brand.mjs:5-6; memory brew-wipe-data]\n\n### How a reset stops the live instance writing back\n\n- The live instance holds jams and workspaces in memory and flushes them, so editing records alone gets overwritten. [src: memory brew-jam-reset]\n- A `stop` marker in `control/live.json` with a `wipe` list makes every instance of the live revision exit; a fresh one never reads, writes or builds those brands. A second marker with an empty list ends the hide. [src: brew/retire.js:1-9]\n- On Postgres the marker is a row. The brand tools write it themselves, which is why staging needs `--rev-n <n>`. [src: brew/retire.js:29-30; brew/db/brand-wipe.js:220-225]\n- Production sets `RETIRE_OFF=1`, so there is no marker: the tool removes, waits and sweeps three times for anything an instance wrote back, then verifies. [src: brew/tools/prod-env.sh:9; brew/db/brand-wipe.js:228-234; brew/docs/production.md:95-96]\n\n### Who may be reset or deleted\n\n- The five design partners, Arata, Nutrova, Mana, PUMA India and Scrubroom, are refused in code unless `--partner-override --confirm-slug <slug>` is given. Only if the partner asked. [src: brew/db/brand-wipe.js:28-30; memory brew-live-stores]\n- A brand in `PROTECTED_CONNECTIONS`, Arata by default, is never deleted by the tool. A reset keeps its connections. [src: brew/db/brand-wipe.js:27; brew/connectors/protected.js:3]\n- Risky tests run on Cozy Snugglet or Zenant. [src: memory brew-live-stores]\n- Tests cover a dry run, the partner refusal, a reset that leaves every connection as it was, the stop marker, a deletion with its audit row, and the bucket era scripts refusing. [src: brew/test/brand-wipe-pg.test.js:46-142]\n\n### Where it runs\n\n- Staging: `brew-ops`, with the code on origin/main once this deploy lands. [src: brew/docs/production.md:83-93; deploy state 26 Oct]\n- Production: no `brew-prod-ops` job yet, and the `data_deletions` table arrives with the next promote. [src: brew/docs/production.md:95-106; deploy state 26 Oct]",
  "Tomorrow": "| Item | Version | Tag |\n|---|---|---|\n| Jam reset as a `brew-ops` job | v1 | Stays |\n| Postgres brand reset, `db/reset-brand.mjs`, with archive, stop marker and partner refusal | v1 | Stays |\n| Data request deletion, `db/delete-brand.mjs`, with an audit row | v1 | Stays |\n| A `brew-prod-ops` job on production, made once after the next promote | v1 | New |\n| A cache and media sweep for \"wipe data\" on Postgres | v1 | New, proposed |\n| Bucket wipe scripts | v1 | Goes; they already refuse on Postgres |\n| A brand's own \"Delete my data\" done in the product, not by email | v2 | Changes |",
  "How we do it": "### Jam reset on staging\n\n1. Find the live revision number `n`, from the name `shopos-feed-<n>-xxx`.\n2. Run:\n\n```bash\ngcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-jams.mjs,--all,--rev-n,<n> --wait\ngcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-jams.mjs,--slug,<slug>,--rev-n,<n> --wait\n```\n\n3. Check with `db/status.mjs` through `brew-ops` that Arata's connections still read.\n\n[src: memory brew-jam-reset] [src: brew/db/reset-jams.mjs:3]\n\n### \"Wipe data\" on a test brand\n\nWhen Param says \"wipe data\", every step runs, without asking. [src: memory brew-wipe-data]\n1. `/api/ops/busy` on staging is 0.\n2. Dry run the brand reset and read every line:\n\n   ```bash\n   gcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-brand.mjs,--slug,<slug> --wait\n   ```\n\n3. Run it, with `n` from `shopos-feed-<n>-xxx`. It hides the brand, removes it, sweeps three times and lifts the hide. Repeat for old or misspelt slugs.\n\n   ```bash\n   gcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-brand.mjs,--slug,<slug>,--rev-n,<n>,--yes --wait\n   ```\n\n4. The treg and Apify cache, made media and saved video reads have no Postgres tool yet; stop and ask Param before touching them.\n5. Verify: the run ends with `VERIFY: <slug> holds nothing to reset any more` and the kept connection rows unchanged; landing 200, busy 0.\n6. Tell Param to test in a private window; the browser remembers onboarding per brand.\n\n[src: brew/docs/production.md:83-93; brew/db/brand-wipe.js:234-235]\n\n### A data request\n\nFollow data requests, 12.9. The tool is `db/delete-brand.mjs`, dry run first.",
  "Numbers": "| Metric | Definition | Where measured |\n|---|---|---|\n| Resets run | Jam and brand resets, with date, site and brands | Proposed: one line each in this page |\n| Deletions run | Data request deletions, finished and unfinished | the `data_deletions` table, `done_at` |\n| Protected brands touched | Runs that changed a partner or Arata's connections | Proposed; must stay 0 |",
  "Open": "1. **May a brand reset run on production?** The code allows it, with no archive. Proposal: no; production runs only `db/delete-brand.mjs` for a data request.\n2. **What clears the cache and made media on Postgres?** Proposal: add it to `db/reset-brand.mjs` behind a `--with-cache` flag, so \"wipe data\" is one job."
 }
}