The estate has three layers with different lifetimes (docs/DEMO.md §2.6). Each has a script; all read .env.local at the repo root and are idempotent.

What demo:reset does, in order

  1. Re-asserts fixtures (runs the seed): RFC-004 back to proposed, canonical statuses everywhere, statements re-pointed at revision 1. If a revision-1 body_md has drifted from the fixture, it is replaced (delete dependent statements → delete row → re-insert) because versions are immutable to UPDATE.
  2. Deletes detection artifacts for the ACME org: violations, service_checks, pending_checks, pending_scans, llm_calls, rfc_comments.
  3. Deletes live-demo revisions (revision > 1) and live-extracted statements (RFC-004’s, plus any strays a re-extraction minted).
  4. Closes open demo PRs on GitHub (branches are kept — they are canonical).
  5. Stamps a demo.reset audit row — the reporting baseline marker.
The demo-api Edge Function’s Reset button covers steps 2–5 plus canonical statuses (it cannot re-assert fixture content — the fixture files live in the repo), so pnpm demo:reset is the full-fidelity version.

What reset can never do

Audit rows are never deleted. The log is append-only by trigger and hash-chained — that is the product’s own guarantee, and the demo deliberately keeps it (“even our own demos can’t rewrite history” is a talking point). The clean-slate effect for Reporting → History comes from the demo.reset baseline marker instead: the timeline starts at the org’s latest one. Settings → Audit always shows everything.

demo:github setup — two rules learned the hard way

  • It closes open demo PRs before force-pushing. GitHub pins a PR’s recorded base sha; force-pushing new history under an open PR leaves its diff computed against the old base (stale, multi-file diffs that confuse the compliance model).
  • It suspends the ruleset around the push — the estate’s own ruleset blocks direct pushes to main, including the setup script’s.

Provisioning notes (rarely needed)

  • Replicates what codex.bootstrap_org writes, using the service role — the RPC itself needs a live Clerk session a script doesn’t have.
  • Clerk API quirks: bare .example/.test email TLDs are rejected (hence acme.example.com); the instance has legal consent enabled so API-created users need legal_accepted_at.
  • Secrets are printed exactly once (API key, shared password). If lost: OTP 424242 always signs test users in; revoke the Demo key in Settings → API keys and re-run provision to mint a new one. No secrets live in the repodemo/CREDENTIALS.md lists accounts and where the secrets are, never the values.

opencode (S8) wiring

~/.config/opencode/opencode.json has the policycodex MCP entry pointing at https://mcp.policycodex.cloud/mcp with the ACME Demo key (plaintext at ~/.config/opencode/.policycodex_acme_key, chmod 600). Always pass a model explicitly — opencode run -m openrouter/anthropic/claude-sonnet-4-6 "…" — or opencode errors on a stale last-used local model.