# Live-grid program smoke gate

The final programs gate has two credential-free modes and one explicitly gated
live mode. None of these tests silently skip. `--audit-only` fails unless the
pinned source manifest maps to all nine original native Rust programs and every
`TestClient` source command maps to the generated, implemented, and runtime
registries. `--fake` executes every smoke stage against the deterministic
backend and writes the same JSONL evidence shape as a live run.

```sh
cargo run -p libremetaverse-programs --bin live-grid-smoke -- --audit-only
cargo run -p libremetaverse-programs --bin live-grid-smoke -- \
  --fake --evidence /tmp/metacrate-smoke-fake.jsonl
```

## Credential and side-effect boundary

Live mode is intended for a dedicated test account on OpenSim or another
protocol-compatible grid. It loads these values from the process environment,
falling back to the workspace `.env` file:

```text
GRID_USER=First Last
GRID_PASSWORD=...
GRID_LOGIN_URL=https://compatible-grid.example/login
```

The 19 compatibility cases require an additional explicit opt-in and never
infer consent merely because credentials exist:

```sh
RUN_LIVE_TESTS=1 cargo test --locked -p libremetaverse-compat-tests \
  --test inventory_live_semantics \
  --test appearance_live_semantics \
  --test world_live_semantics \
  --test network_semantics -- --nocapture
```

With the opt-in and all three `.env` values present, every live case is compiled
without `#[ignore]`. The test run must report zero ignored cases. Test bodies do
not print-and-return on missing OpenSim data: a missing inventory item, outfit
link, appearance update, covenant response, current-region lookup, capability,
or object packet is a real failure. Login uses the account's OpenSim `last`
location instead of a hardcoded Second Life region.

`GRID_LOGIN_URL` is used directly as the LLSD login endpoint; the harness does
not substitute a Second Life login host or path. The login request includes the
OpenSim response options for avatar search, classified fee, currency label,
destination guide, profile service, and search, in addition to the standard
inventory and viewer options. Capability readiness is evaluated using OpenSim
core surfaces (`EventQueueGet`, inventory descendants, simulator features,
viewer assets, textures, and avatar search); Second Life voice capabilities are
not required. Agent, object, inventory, and asset packet consumers are installed
before authentication so the harness captures OpenSim's one-time login and scene
bootstrap packets instead of treating a late subscription as an empty region.
After the event queue is live, the harness repeats OpenSim's idempotent
`CompleteAgentMovement` transition request reliably before waiting for the scene
cache. Simulator identity is validated directly from the transport-decoded
OpenSim region handshake, and the return teleport uses its numeric region handle
instead of assuming the mutable Second Life-style simulator-name cache exists.

The complete command deliberately requires a separate flag and literal
confirmation for each permitted side effect:

```sh
cargo run -p libremetaverse-programs --bin live-grid-smoke -- \
  --evidence /tmp/metacrate-smoke-live.jsonl \
  --allow-live-login --confirm-live-login LOGIN \
  --allow-public-chat --confirm-public-chat CHAT \
  --allow-agent-movement --confirm-agent-movement MOVE \
  --allow-reversible-inventory \
  --confirm-reversible-inventory CREATE-MOVE-TO-TRASH
```

This sends one self instant message and one clearly marked local-chat message,
pulses forward movement for 250 milliseconds, teleports back to the starting
simulator and position, and creates one uniquely named folder before moving it
to Trash. The folder is not permanently deleted. The harness has no flags or
code paths for currency spending, asset upload, permanent deletion,
estate/parcel changes, or actions aimed at another user.

OpenSim does not necessarily route a self-addressed instant message back to the
sending avatar. The IM gate therefore requires the encoded
`ImprovedInstantMessage` datagram to cross the client's live UDP packet-sent
boundary and records any inbound self echo as an additional metric. The local
chat gate still requires an exact inbound simulator echo, so both operations are
executed and neither is silently skipped.

## Sanitized evidence

The newly created JSONL file contains exactly nine ordered records:

1. source/program/command completeness;
2. login;
3. event queue, capabilities, simulator, and object cache readiness;
4. self-IM and local-chat echo;
5. movement stop and return teleport;
6. folder creation and move to Trash;
7. object discovery and properties;
8. bounded texture download;
9. clean logout and zero active tasks.

The texture transfer is performed against the live grid and counted in the
sanitized evidence, but the harness disables the library's on-disk asset cache
before login. Asset bytes are held only in memory for validation and are not
retained after the process exits.

Each record contains schema and sequence numbers, a Unix timestamp, the Rust
package version, the source commit embedded at build time, a static status, and
numeric metrics. It contains no account name, password, login/capability URL,
session identifier, simulator name, object or asset UUID, or message text. The
writer scans every serialized record for configured credential values and
secret-bearing URL/token/password markers, flushes each stage, synchronizes at
completion, and refuses to overwrite an existing evidence file.

If an operational stage fails, the harness records that failure and still
attempts and records logout. A successful live gate requires all nine records
to have `status: "ok"`; fake success is evidence for deterministic behavior,
not evidence of a live login.
