Repository navigation
v2.1.2 — hero-suite wipe made whole; v2.1.1 attribution corrected
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:
- The
TRUNCATESQL isformat!-built from a table-name list, so greppingDELETE FROM crm.customerfinds nothing. Searching for the literal instead of the capability was the actual error. audit.domain_eventis deliberately spared, socustomer.createdevents survive for customers that no longer exist — which reads exactly like an out-of-band delete.- Having exonerated
seed-demo --resetandmake reset-db, it concluded "therefore nothing in-tree" rather than "therefore some other in-tree path", stopping one query short ofWHERE 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.