diff --git a/sandbox/README.md b/sandbox/README.md index 1984db34..608c45a8 100644 --- a/sandbox/README.md +++ b/sandbox/README.md @@ -93,14 +93,21 @@ connection pools, and both reconnect by themselves — the api on its next reque next poll a quarter-second later. Each logs one `OperationalError` as its in-flight connection dies; that is expected, and it is the price of not paying ~9 seconds of container restart on every reset. -The cost of a snapshot is that it can go stale. Two guards: +The cost of a snapshot is that it can go stale. Three guards: - **Per-mode template names**, so a mock-seeded template can never be restored into a real-mode run. - **A fingerprint recorded inside each template** — the Alembic revision it was seeded at, a hash of `fixture.json` + `seed.py`, and the provider mode. `reset` compares and refuses with a "reseed" message rather than silently restoring a state that predates a migration. +- **A provider check against the running stack.** Neither `seed` nor `reset` recreates containers, so + `--provider` on either cannot change what the stack actually talks to — only what gets recorded. + `up` writes the provider it created the stack with to `sandbox/.state.env`, and `seed`/`reset` + refuse a mismatch and tell you to run `up --provider ...` first. Without it, + `seed --provider mock` against a running real stack would spend money on non-deterministic + conclusions and label them `mock`, and every later `reset` would restore those as the + deterministic baseline. -If you hit that refusal: `sandbox/sandbox.sh seed`. +If you hit the staleness refusal: `sandbox/sandbox.sh seed`. ## What's in the fixture diff --git a/sandbox/sandbox.sh b/sandbox/sandbox.sh index f87ef0a0..475efa2f 100755 --- a/sandbox/sandbox.sh +++ b/sandbox/sandbox.sh @@ -74,6 +74,22 @@ elif [ -f "$STATE" ]; then fi export HONCHO_SANDBOX_IMAGE +# The provider the running stack was actually created with, read on its own because +# the source above is skipped under --build. Empty means nothing has been started +# through `up` since the last `down`. +RUNNING_PROVIDER="" +if [ -f "$STATE" ]; then + RUNNING_PROVIDER="$(sed -n 's/^SANDBOX_RUNNING_PROVIDER=//p' "$STATE")" +fi + +write_state() { + cat > "$STATE" < "$STATE" + # Recorded before the seed/reset below, so their provider guard sees the stack + # that was just created rather than the one it replaced. + write_state if db_exists "$TEMPLATE"; then say "template $TEMPLATE already present — resetting to it" @@ -177,6 +220,7 @@ cmd_up() { cmd_seed() { preflight + require_running_provider # Seeding an already-seeded database appends to it — the fixture would land a # second time and the "expected 6 messages, found 12" check in seed.py would # (correctly) fail. Start from an empty, freshly migrated database every time so @@ -215,6 +259,7 @@ cmd_seed() { cmd_reset() { preflight + require_running_provider db_exists "$TEMPLATE" || die \ "no template for $PROVIDER mode. Run: sandbox/sandbox.sh seed --provider $PROVIDER" @@ -242,7 +287,11 @@ cmd_reset() { cmd_status() { compose ps echo - echo "provider: $PROVIDER" + if [ -n "$RUNNING_PROVIDER" ] && [ "$RUNNING_PROVIDER" != "$PROVIDER" ]; then + echo "provider: $RUNNING_PROVIDER (running) — this command asked for $PROVIDER" + else + echo "provider: $PROVIDER" + fi echo "image: $HONCHO_SANDBOX_IMAGE" echo "api: http://127.0.0.1:${SANDBOX_API_PORT:-18000}" for mode in mock real; do