---
id: "8.4"
title: "Wipe data and reset jams"
dept: ops-and-infrastructure
status: draft
owner: Param
branded: false
last_verified: "2026-10-26"
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"
---

# Wipe data and reset jams

## 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

| | Jam reset | Brand reset, "wipe data" | Data request deletion | Full flush |
|---|---|---|---|---|
| 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] |
| 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] |
| 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] |
| 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] |
| Never calls a platform | yes | yes | yes, and prints the grants the brand revokes itself [src: brew/db/brand-wipe.js:7, 240] | yes |

- 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]
- Both refuse while a job for the brand is running. [src: brew/db/brand-wipe.js:219]
- `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]
- 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]
- 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]

### How a reset stops the live instance writing back

- The live instance holds jams and workspaces in memory and flushes them, so editing records alone gets overwritten. [src: memory brew-jam-reset]
- 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]
- 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]
- 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]

### Who may be reset or deleted

- 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]
- 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]
- Risky tests run on Cozy Snugglet or Zenant. [src: memory brew-live-stores]
- 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]

### Where it runs

- Staging: `brew-ops`, with the code on origin/main once this deploy lands. [src: brew/docs/production.md:83-93; deploy state 26 Oct]
- 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 |
|---|---|---|
| Jam reset as a `brew-ops` job | v1 | Stays |
| Postgres brand reset, `db/reset-brand.mjs`, with archive, stop marker and partner refusal | v1 | Stays |
| Data request deletion, `db/delete-brand.mjs`, with an audit row | v1 | Stays |
| A `brew-prod-ops` job on production, made once after the next promote | v1 | New |
| A cache and media sweep for "wipe data" on Postgres | v1 | New, proposed |
| Bucket wipe scripts | v1 | Goes; they already refuse on Postgres |
| A brand's own "Delete my data" done in the product, not by email | v2 | Changes |

## How we do it

### Jam reset on staging

1. Find the live revision number `n`, from the name `shopos-feed-<n>-xxx`.
2. Run:

```bash
gcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-jams.mjs,--all,--rev-n,<n> --wait
gcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-jams.mjs,--slug,<slug>,--rev-n,<n> --wait
```

3. Check with `db/status.mjs` through `brew-ops` that Arata's connections still read.

[src: memory brew-jam-reset] [src: brew/db/reset-jams.mjs:3]

### "Wipe data" on a test brand

When Param says "wipe data", every step runs, without asking. [src: memory brew-wipe-data]
1. `/api/ops/busy` on staging is 0.
2. Dry run the brand reset and read every line:

   ```bash
   gcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-brand.mjs,--slug,<slug> --wait
   ```

3. 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.

   ```bash
   gcloud run jobs execute brew-ops --region=asia-south1 --args=db/reset-brand.mjs,--slug,<slug>,--rev-n,<n>,--yes --wait
   ```

4. The treg and Apify cache, made media and saved video reads have no Postgres tool yet; stop and ask Param before touching them.
5. Verify: the run ends with `VERIFY: <slug> holds nothing to reset any more` and the kept connection rows unchanged; landing 200, busy 0.
6. Tell Param to test in a private window; the browser remembers onboarding per brand.

[src: brew/docs/production.md:83-93; brew/db/brand-wipe.js:234-235]

### A data request

Follow data requests, 12.9. The tool is `db/delete-brand.mjs`, dry run first.

## Numbers

| Metric | Definition | Where measured |
|---|---|---|
| Resets run | Jam and brand resets, with date, site and brands | Proposed: one line each in this page |
| Deletions run | Data request deletions, finished and unfinished | the `data_deletions` table, `done_at` |
| 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.
2. **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.
