asteria-bootstrap: idempotent deploy via Provider UTxO query
PR 2: make rerunning bootstrap safe. Antithesis can restart the
asteria-game container at any time; serial_driver_asteria_bootstrap
will re-fire on each restart. The Haskell binary now skips the
mint+lock if the asteria spend address already carries a UTxO with
the asteriaAdmin token.
Defence layers in place after this PR:
1. Haskell-side detection (this PR): Provider.queryUTxOs at the
asteria spend address; presence of (admin_mint_hash,
"asteriaAdmin") = already deployed → exit 0 with
sdk_sometimes("asteria_bootstrap_already_deployed").
2. Antithesis serial_driver scheduling: exclusive access while
bootstrap runs → no concurrent invocations on the same timeline.
KNOWN GAP — defence layer 3 (Plutus one-shot) is still on the
todo list. PR #67's admin_mint validator is the always-true
placeholder, so there is no chain-level uniqueness guarantee yet.
A future PR replaces admin_mint with a parameterised one-shot
that consumes a seed OutputReference; until then the indexer
race window between detection and submission, while small under
serial_driver scheduling, is non-zero. See spec FR-010 / User
Story 4.
New: composer/stub/serial_driver_asteria_bootstrap.sh — exec
/bin/asteria-bootstrap. Antithesis discovers it under
/opt/antithesis/test/v1/stub/ (already mounted via the same
docker-image build).