Until now this repo was an export of a private tree, pushed as squashed snapshots. From here on it is the working tree itself, and the private repo is archived. The root holds AGENTS.md and the Rust and GitHub files only. Everything an agent needs to orient is in docs/: METHOD.md (the rules and how the project is built, 123 lines, project method only), MAP.md (generated from the code at every land) and CONTRIBUTING.md (what gets in and how a change is judged). One skill, `probe`, holds the procedure for running the client unattended against the local server. Brought over because the project needs it: reference/ (the 1.12 name catalogues 34 source files read; the export failed its own tests without them), the gate chain and the pool (scripts/), the hooks that enforce the install rule and the worktree rule, the full .gitignore, the `cargo play` alias, and the original wording of eleven source files the export had reworded. Left out: the decision records (archived with the private repo), the export tooling, the operator's Discord and triage loop, the lab-laptop scripts and the instruments nothing references, which live outside the repo now. What read the records is gone from the tooling: no corpus lint, no records index, no `reserve` verb, no number-collision check. Three hooks are gone: fmt-at-commit and the file-size nudge were redundant with the gates, and the assets/ui guard is now a test (`assets_ui_does_not_grow`) that fails for everyone, not only for a Claude Code session. The remaining pool hooks stand down on a machine without a pool. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
120 lines
5.6 KiB
Bash
Executable File
120 lines
5.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# cine.sh — play one cinematic on the probe and print what happened, as a timeline.
|
|
#
|
|
# Every cinematic question is the same shape — "what did the client do to the world while the
|
|
# camera was away?" — and answering it by hand costs four environment variables, a GM command, a
|
|
# move trace and a fistful of greps. Assembled by hand three times in one session (decisions
|
|
# 1701/1707/1708), it produced two WORTHLESS runs before a usable one:
|
|
#
|
|
# * the first parked the body wherever the character was saved, which was inside Thunder Bluff's
|
|
# geometry — the body was wedged, sent nothing, and the trace said "held" for reasons that had
|
|
# nothing to do with the cinematic;
|
|
# * the second read "no movement packet" as proof that input was suppressed, when the body was
|
|
# simply in free fall and had no movement to send.
|
|
#
|
|
# Both are avoidable by construction, so this parks the body on known-flat ground first and always
|
|
# prints the control facts (did it fall? did it move?) beside the thing under test.
|
|
#
|
|
# THE SILENT-BUT-LIVE TRICK, which is the other half of why this exists: `$WOW_NOSOUND` opens no
|
|
# audio device, so `zone::start_music_stream` returns before it logs and a silent run can tell you
|
|
# NOTHING about music. Instead this points `$BENILLA_HOME` at a throwaway config with
|
|
# `MasterVolume = "0"` — the device opens, every stream starts and logs its file, and the room
|
|
# stays quiet. That is what made "the Stormwind city-intro stinger is what plays under the human
|
|
# narration" a readable fact rather than a guess.
|
|
#
|
|
# scripts/cine.sh # the human intro (81), parked in Stormwind
|
|
# scripts/cine.sh 41 # the dwarf intro
|
|
# scripts/cine.sh 81 --key W # …and hold W mid-shot: does the body move?
|
|
# scripts/cine.sh 81 --at "-8913,554,94,0"
|
|
# scripts/cine.sh 81 --keep # keep the raw log and trace paths, printed at the end
|
|
#
|
|
# The probe identity is SLOT-KEYED off this worktree's path (`docs/METHOD.md`): pool-N logs in as
|
|
# probeN. Never the director's account.
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
id=81
|
|
park="-8913,554,94,0" # Stormwind Trade District: flat, solid, and a zone with music
|
|
key=""
|
|
keep=0
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--at) park="$2"; shift 2 ;;
|
|
--key) key="$2"; shift 2 ;;
|
|
--keep) keep=1; shift ;;
|
|
-*) echo "cine.sh: unknown flag $1" >&2; exit 2 ;;
|
|
*) id="$1"; shift ;;
|
|
esac
|
|
done
|
|
|
|
# Slot-keyed probe identity (docs/METHOD.md, "The local vmangos server").
|
|
slot="$(basename "$PWD")"
|
|
n="${slot#pool-}"
|
|
case "$n" in
|
|
0) word=zero ;; 1) word=one ;; 2) word=two ;; 3) word=three ;; 4) word=four ;;
|
|
5) word=five ;; 6) word=six ;; 7) word=seven ;; 8) word=eight ;; 9) word=nine ;;
|
|
*) echo "cine.sh: not in a wt.sh pool slot ($slot) — claim one first (docs/METHOD.md)" >&2; exit 2 ;;
|
|
esac
|
|
char="Probe$word"
|
|
|
|
work="$(mktemp -d)"
|
|
cfg="$work/cfg"
|
|
mkdir -p "$cfg"
|
|
printf '[cvars]\nMasterVolume = "0"\n' > "$cfg/config.toml"
|
|
log="$work/run.log"
|
|
trace="$work/move.trace"
|
|
|
|
IFS=, read -r px py pz pmap <<< "$park"
|
|
|
|
# The schedule, in probe-clock seconds. Generous rather than tight: a cold slot streams a city
|
|
# slowly, and a measurement taken before the world arrived is the wedged-body run all over again.
|
|
park_at=8
|
|
play_at=20
|
|
key_at=$((play_at + 8))
|
|
# Shots run 25-102 s; leave room for the end, the resume and the cover to settle.
|
|
exit_at=$((play_at + 120))
|
|
|
|
echo "cine.sh: cinematic $id as $char, parked at $px $py $pz (map $pmap)"
|
|
[ -n "$key" ] && echo "cine.sh: holding $key for 3 s at t=${key_at}s"
|
|
echo "cine.sh: this takes about $((exit_at + 20)) s — the shot is played in full so the END is measured too"
|
|
|
|
env BENILLA_HOME="$cfg" WOW_UNATTENDED=1 \
|
|
WOW_USER="probe$n" WOW_PASS="pprobe$n" WOW_CHAR="$char" \
|
|
WOW_PROBE_CHAT=".go xyz $px $py $pz $pmap;.debug play cinematic $id" \
|
|
WOW_PROBE_CHAT_AT="$park_at" WOW_PROBE_CHAT_EVERY="$((play_at - park_at))" \
|
|
${key:+WOW_PROBE_KEY="$key@$key_at:3"} \
|
|
WOW_MOVE_TRACE="$trace" WOW_MOVE_TRACE_TAGS="move,snd" \
|
|
WOW_PROBE_EXIT_AT="$exit_at" \
|
|
cargo run -q -p benilla > "$log" 2>&1 || true
|
|
|
|
strip() { sed -E 's/\x1b\[[0-9;]*m//g'; }
|
|
|
|
echo
|
|
echo "── timeline ────────────────────────────────────────────────────────────────"
|
|
strip < "$log" | grep -E \
|
|
"cinematic:|screen fade:|cinematic voice:|zone music:|ambience:|loading screen:|body held|probe-key:" \
|
|
| sed -E 's/^[0-9-]+T([0-9:.]+)Z +INFO +[a-z_:]+: /\1 /' || true
|
|
|
|
echo
|
|
echo "── the two control facts ───────────────────────────────────────────────────"
|
|
if [ -s "$trace" ]; then
|
|
# Everything before the park is the login/teleport arc and says nothing about the cinematic.
|
|
after=$(awk -v t="$park_at" '$1=="t=" || $2+0 >= t' "$trace" 2>/dev/null || cat "$trace")
|
|
low=$(printf '%s\n' "$after" | grep -oE 'pos=\[[-0-9.]+,[-0-9.]+,[-0-9.]+\]' \
|
|
| sed -E 's/.*,//; s/\]//' | sort -n | head -1)
|
|
echo "did it FALL? lowest z after the park: ${low:-<none>} (park z was $pz)"
|
|
verbs=$(printf '%s\n' "$after" | grep -oE 'snd [A-Za-z_]+' | sort | uniq -c | tr '\n' ' ')
|
|
echo "did it MOVE? wire verbs sent: ${verbs:-<none>}"
|
|
echo " (a StartForward means the body walked; only Heartbeats means it did not)"
|
|
else
|
|
echo "no move trace written — the run did not reach the world"
|
|
fi
|
|
|
|
echo
|
|
if [ "$keep" = 1 ]; then
|
|
echo "log: $log"
|
|
echo "trace: $trace"
|
|
else
|
|
rm -rf "$work"
|
|
fi
|