worldbox-observer-mod/.cursor/skills/idle-spectator-e2e/reference.md
2026-07-14 18:35:06 -05:00

4 KiB

IdleSpectator harness reference

WorldBox wiki

Use https://the-official-worldbox-wiki.fandom.com/wiki/The_Official_Worldbox_Wiki when designing Spectator priorities or Chronicle events (Units lovers/friends, World History, kings, traits, war, disasters).

Chronicle records life/world events, not spectator watch notes. Watch caption covers live focus context. Vanilla tooltips (Tooltip, TooltipLibrary, tooltips/tooltip_actor) are candidates for future UI polish.

Architecture

scripts/harness-run.sh
  -> starts WorldBox if needed
  -> writes IdleSpectator/.harness/commands.jsonl
  -> touches reset + auto-dismiss
  -> regression: loops named scenarios sequentially
AgentHarness.Update() (in-game)
  -> executes commands on Unity main thread
  -> FreezeDirector unless director_run is active
  -> writes results.jsonl + last-result.json
  -> logs [HARNESS]/[ASSERT]/[SNAP]

Why not OS input?

Wayland makes xdotool/ydotool unreliable. Truth lives in engine state (MoveCamera, tips, settings), so drive the mod API directly.

Timing

InterestDirector and SpeciesDiscovery use Time.unscaledTime. WorldBox 5x game speed does not advance those clocks. Use harness fast_timing + director_run / age_current for scheduling tests.

Hard-won failure modes

Symptom Cause Fix
Welcome closes, idle never starts commands.jsonl rewritten same length; offset at EOF runner writes offset=0 + reset
Steps run before world ready wait_world requeued to back RequeueFront
Tip says crab, focus is angle watch fell back to nearest unit require matching asset; use pick_unit/asset=auto
Spawn then "no unit for asset" miracle spawns die on bad tiles prefer pick_unit for critical paths
Flaky health/no_bad mid-scenario ambient retarget while harness busy FreezeDirector unless director_run
Steam hang after tests Application.Quit leave game running
Director tests take forever production dwell/rotate fast_timing (not game 5x)
Game never opens / Cannot run as root user Shell sandboxed; Steam rejects root-like env re-run launch/harness-run.sh with Shell required_permissions: ["all"]
Old mod still loaded after edit NML caches until restart kill .../common/worldbox/worldbox, bump mod.json, relaunch with all perms

Useful asserts

  • health - idle + focus + power bar hidden + bad==0
  • tip_matches_unit - tip asset equals focus unit asset; if tip starts with New species:, label species must match
  • no_bad - StateProbe bad counter is zero
  • enabled / show_watch_reasons - mod settings
  • current_tier / would_accept_curiosity - director scheduling
  • focus_same - after remember_focus (ghost guard)
  • presented / pending_discovery - species discovery buffer
  • caption_layout_ok - dossier panel size/layout bounds (catches off-panel text)
  • screenshot harness action writes .harness/<name>.png via Unity ScreenCapture

Screenshots

Harness screenshot writes:

  • IdleSpectator/.harness/<name>.png - full frame
  • IdleSpectator/.harness/<name>-dossier.png - exact dossier rect (ReadPixels)

For HUD work:

  1. Prefer reading *-dossier.png (wait ~1s after the run).
  2. Validate with ./scripts/crop-dossier-hud.py --strict IdleSpectator/.harness/hud-*-dossier.png
  3. Do not judge layout from raw 2880p frames.
  4. Player-pasted shots override harness crops.

Extending scenarios

Edit IdleSpectator/HarnessScenarios.cs:

  1. Add steps with Step(id, action, ...).
  2. Register name in Build.
  3. Add the name to REGRESSION_SCENARIOS in scripts/harness-run.sh when it should gate merges.
  4. Run ./scripts/harness-run.sh <name> then --repeat 3 critical_smoke (and regression for suite-level changes).

Keep critical_smoke deterministic:

  • dismiss_windows / wait_world first
  • pick_unit before tip/focus asserts
  • reset_counters after spectator+focus before health (StateProbe only; use value=all only at batch start)
  • simulate_input last for manual-exit coverage