Skip to content

v2.1.2 — hero-suite wipe made whole; v2.1.1 attribution corrected

Choose a tag to compare

@chiam-ck chiam-ck released this 22 Jul 21:22
· 14 commits to main since this release

The hero suite's data wipe is made whole, and v2.1.1's account of what happened is corrected.

What actually deleted the customers

v2.1.1 said the missing crm.customer rows were removed "out-of-band" and that the cause was unexplained. Both were wrong. The operator rejected the claim — they hadn't touched those customers — and they were right.

18 of the 19 hero scenarios declare setup.reset_operational_data: true, which fans admin.reset_operational_data out to 7 services. CRM's ResetPlan TRUNCATEs every row of customer, party, contact_medium, individual, interaction, customer_identity, case and ticket — not scenario-scoped, no "only rows this run created" filter, gated only by BSS_ALLOW_ADMIN_RESET=true. make scenarios-hero ran during v2.0.0 release verification on 2026-07-21; the last CRM admin.operational_data_reset marker is 02:37:38.853Z, 0.4s before the final hero scenario created its own customer.

Why the first investigation missed it, recorded so it isn't repeated:

  1. The TRUNCATE SQL is format!-built from a table-name list, so grepping DELETE FROM crm.customer finds nothing. Searching for the literal instead of the capability was the actual error.
  2. audit.domain_event is deliberately spared, so customer.created events survive for customers that no longer exist — which reads exactly like an out-of-band delete.
  3. Having exonerated seed-demo --reset and make reset-db, it concluded "therefore nothing in-tree" rather than "therefore some other in-tree path", stopping one query short of WHERE event_type='admin.operational_data_reset'.

The wipe was half-done

It cleared customers but left portal_auth logins pointing at them. That half-ness is precisely what produced the orphaned identities behind v2.1.1 — a partial wipe is a broken state, not a conservative one.

The reset now also truncates identity, session, login_token, login_attempt, email_change_pending and step_up_pending_action. portal_action is deliberately kept — it's the portal's audit trail, spared by the same rule that spares audit.domain_event.

It runs through the scenario runner's existing scenario-only BSS_DB_URL seam, not as a new admin endpoint: portal_auth is owned by the portals, which are public customer-facing web apps with no API-token middleware, and a "delete every login" route on port 9001 would be a worse hazard than the one being fixed.

Still live, by design

Running the hero suite against a database holding real customers destroys them. Nothing stops that, and per the operator's call it stays that way — resetting the world is what a scenario suite is for. A follow-up commit adds a disclaimer at both entry points (make scenarios* banner + make help, and a stderr warning from the reset itself for the direct bss scenario run-all path) rather than a guard.

Compatibility

SemVer patch. Scenario-runner and docs only — no product verb, wire contract, event, payload or DB schema change, and no change to any service or portal binary. BSS_RELEASE 2.1.1 → 2.1.2.

Gate

cargo fmt --all --check · clippy -D warnings (0) · cargo test --workspace --no-fail-fast 541 pass / 0 fail · 14 doctrine guards.

Also regenerates the bss-knowledge chunker golden, which v2.1.1 shipped broken (96 chunks vs 95) because its full-suite run predated its own DECISIONS.md edit. Unlike that cut, this gate was run on the final tree.

The TRUNCATE was validated inside BEGIN … ROLLBACK against a live DB — identities 11→0, sessions 17→0, portal_action untouched, all restored on rollback. The real reset was deliberately not run: doing so would have repeated the harm under investigation.