Files
security-game/MEMORY.md
T
zwitschi 39a80f39f9
Full build / Import + headless tests (push) Successful in 27s
Full build / Full desktop build + optional release (push) Failing after 3m10s
Bump to v0.2.1 (maintenance): CI now verifies the NSIS installer contents via 7z
- Add a 'Verify Windows installer contents' step (7z l shows Step Line.exe +
  uninstall.exe) so the TODO verification items are proven by CI output
- Rebuild 0.2.1 binaries (embedded PCK) and AppImage locally; smoke clean;
  57/57 tests
2026-10-31 14:05:12 +01:00

11 KiB
Raw Blame History

MEMORY

Session memory for durable decisions, state, and gotchas. Keep concise, remove obsolete entries.

Decisions

  • Engine: Godot 4.3 stable (official editor build, ~/.local/bin/godot). The system's preinstalled godot-runner (4.7.2, Fedora) cannot load projects from arbitrary paths because it was compiled without path overrides; use the official editor binary instead.
  • Language: GDScript. All cross-file references use explicit preload() constants (not class_name globals) so scripts compile in headless --script runs without the editor's class cache.
  • Test framework deviation: the project uses a custom minimal headless test runner (src/test/test_runner.gd) instead of GUT, because GUT needs the editor plugin. CI runs it with --headless.
  • Eventing: no autoload signal bus. ShiftCoordinator owns an EventBus instance (src/core/event_bus.gd) passed to subsystems; subsystems emit only when a bus is assigned. Autoloads at parse time are unreliable under --script.
  • Static signals are not available in Godot 4.3 GDScript ("Expected func or var after static") — do not use them.
  • GDScript lambdas capture local variables by value; mutating a captured local inside a lambda does not affect the outer variable. Use member functions for accumulators in tests.
  • Prototype shift duration defaults to 300 s for testing; production targets 10-15 minutes per PLAN.md.
  • RNG: NPC reactions and event scheduling are seedable for deterministic tests.

Current State

  • Release v0.2.0 is LIVE: pushing the v0.2.0 tag made Gitea Actions run the build job and publish automatically (host has the GITEA_TOKEN secret). Tag page and /releases are public (HTTP 200). Caveat: anonymous asset downloads redirect to login on this host (host setting — tracked in TODO). Future releases = bump config/version, git tag vX.Y.Z, push. No local token needed.
  • Core simulation, three scenarios, headless tests (57 passing), and a first-person prototype with interaction HUD, access inspection, radio (assist + emergency hold-to-confirm), debug overlay, and shift review are implemented and green.
  • NPC avatars now walk to per-intent waypoints (VenueScenario.waypoint_for_intent): enter/trespass/deliver/arrive → entrance, photo/film/perform/wander/roam → sidewalk, sit → steps_end. NpcAvatar.setup takes an explicit door_position.
  • Returning-trespasser behavior: NpcProfile.return_probability (trespasser 0.6, mental-crisis 0.4, others 0). NPCController._maybe_schedule_return() moves a directed-away NPC to LOITERING_DISTANT; tick_return(delta) fires after 20-60s and transitions back to APPROACH. NpcAvatar._advance_fsm re-targets the door on return.
  • Perception pass: NPCController.perceive_guard(distance) returns {noticed, band, reaction} with bands unaware (>6m), aware (2-6m), near (<2m). Near + temperament ≥0.6 → ARGUE, else COMPLY. GameManager._perception_pass() feeds real guard distance each physics tick and logs first-time notice.
  • Responder dispatch: RadioSystem tracks pending_calls and decrements arrival_delay_s in tick; emits responder_arrived when a call's delay elapses. RadioSystem.responder_outcome(call) maps danger/weapons → command/restraint/evacuation/arrest. GameManager._on_responder_arrived spawns a RESPONDER avatar at the entrance and logs the outcome. HUD shows an emergency-radio cooldown label via _update_radio_cooldown.
  • Wand screening (Joke Shop): WandScreener (new src/core/wand_screener.gd) classifies carried items as prohibited (weapon/knife/gun/blade) vs false-alarm (keys/belt/phone/coins/watch/buckle) vs clear. NpcProfile.carried_items holds guest items. GameManager binds W to _toggle_wand_screening and A/D to decide_wand; decide_access blocks admission at wand venues until controller.screened is true. VenueScenario.door_staff_lines holds venue-specific door-staff dialogue (Joke Shop has id/ticket/wand/refusal/prohibited lines).
  • Design change (2026-10-31): the selectable dialogue tone-of-voice system was removed. Rules.Tone/TONE_NAMES, NpcProfile.tone_modifiers, and the tone param on NPCController.roll_reaction/apply_player_action no longer exist; NpcProfile.dialogue_lines is a flat Array[String]; GameManager uses _apply_interaction(level, action_name); the T key is gone. HUD tone_label removed and hud.tone_prefix string deleted from JSON.
  • Polish/accessibility: venue cycling (V cycles VENUE_ORDER and restarts the shift), aim-free targeting (Tab cycles nearby NPCs within NEARBY_RADIUS), color-coded escalation indicator (Hud.set_escalation), procedural audio (AudioFeedback node generates sine tones for confirm/radio/escalation/deny), and a centralized Strings table (src/core/strings.gd, lookup/fmt) backed by content/strings.en.json. NOTE: Strings.get was renamed to Strings.lookup because get collides with Object.get.
  • Newly added: LATE shift phase (start 700s) with a reachability test; PROTESTER archetype + events + colors; CALL_SOMEONE reaction; DoorState core class + L binding + visual indicator; flashlight (G, SpotLight3D, perception bonus at evening/late); persistence wired (Save.save_shift_result on shift end, history + best score on the review screen); NavigationRegion3D flat navmesh + NavigationAgent3D NPC paths (steps now visual-only); strings moved to res://content/strings.en.json (41 keys, loader keeps lookup/fmt); export_presets.cfg (Linux/Windows/macOS) + tools/build_releases.sh + docs/RELEASING.md; README Downloads section.
  • Run tests: godot --headless --path . --script res://src/test/test_runner.gd
  • Boot check: godot --headless --path . --quit-after 120
  • Screenshot tools: godot --path . -s res://src/test/take_screenshot.gd (single shot to user://screenshot.png); godot --path . -s res://src/test/capture_screenshots.gd (staged README gallery shots to user://screenshots/, copied to docs/screenshots/).
  • Release build verified locally: export templates for 4.3 installed at ~/.local/share/godot/export_templates/4.3.stable/; ./tools/build_releases.sh produced Linux/Windows/macOS artifacts for 0.1.0 in build/ and the Linux binary passed a headless smoke test. Publishing to Gitea still needs a token (see tools/publish_release.sh, docs/RELEASING.md).
  • CI: the repo now carries a Gitea Actions workflow at .gitea/workflows/build.yml (checks on push/PR; full export + artifact upload + optional release publish on tags and workflow_dispatch). A repo secret GITEA_TOKEN is required for tag releases. The old .github/workflows/ci.yml was removed so hosts scanning both paths do not double-run.
  • Venue cycling: V switches Hollywood Blvd → The Joke Shop → TV Studio and restarts the shift.
  • Venue door-staff dialogue: VenueScenario.door_staff_line(context, rng) and GameManager logging (id/ticket/wand-check, refusal, prohibited-item) — Joke Shop flavor.
  • CI cache: .gitea/workflows/build.yml no longer uses actions/cache (the runner can't reach the GitHub cache service; import is fast). GODOT_SILENCE_ROOT_WARNING=1 set on jobs. Logs live in .gitea/logs/ after each run.
  • Visual polish (v0.2.0): phase lighting (GameManager.PHASE_LIGHTING + ProceduralSkyMaterial), street lamps + night mode in WorldBuilder.set_night_mode, marquee Label3D, crosswalk/planters/ trees, NPC per-seed variation. capture_screenshots.gd shoots day + fast-forwarded LATE night (6 shots in docs/screenshots/). Version bumped to 0.2.0; binaries rebuilt.
  • Assets pipeline: python3 tools/generate_textures.py produces all authored PNGs under assets/textures/ (≤1024px, pow2); regenerate after changing the script, then run godot --headless --import before tests. 57 headless tests guard the pipeline.
  • AI texture mode: python3 tools/generate_textures.py --ai generates textures via the OpenRouter image API (POST https://openrouter.ai/api/v1/images, model bytedance-seed/seedream-4.5 by default, base64 PNG in data[].b64_json). Requires OPENROUTER_API_KEY (a gitignored .env in the repo root holds it locally; source it with set -a && . ./.env && set +a). --prompt/--name/--model/--size override the default batch. Output is downscaled to ≤1024px. NOTE: seedream rejects sizes below 3,686,400 px (1920×1920), so the script requests GEN_SIZE=2048 and downscales — do not lower GEN_SIZE below 1920. Verified end-to-end 2026-10-31 (3 textures generated). AI_TEXTURES now covers all 15 game textures (world surfaces, awning, skyline, vignette, 4 HUD icons, 5 access cards) with a transparent flag per entry. NOTE: seedream-4.5 ignores background: transparent and returns fully opaque images (alpha=255), so the ai/ icons/vignette/skyline are opaque — they are NOT drop-in replacements for the authored transparent PNGs. Use a transparency-capable model (or post-process) if alpha is needed.
  • Detailed graphics: textured facade/awning/skyline, humanoid NPC rigs + props + walk bob + attention head-turn, inspection artifact cards, mode icons, escalation vignette, body-cam overlay (REC + shift clock). Screenshot set regenerated (docs/screenshots/, day + night).
  • Polish: wand scan cooldown (WAND_COOLDOWN_S + wand.recharge message).
  • NOTE: collaborators occasionally add uncommitted work to this shared tree (e.g. the radio easter egg); check git status before committing and leave foreign changes untouched unless asked.

Known Issues / Notes

  • Reference cycles are fixed: FSM holds its owner via WeakRef, ShiftCoordinator is RefCounted, and persistence tests free the Save node — the suite exits with no "resources still in use" warnings (was ~13). If a future subsystem introduces a cycle, repeat the WeakRef pattern.
  • Shift length: GameManager uses the scenario's shift_duration_s (900s ≈ 10-15 min); tests and the screenshot tool override elapsed time directly.
  • Headless (dummy renderer) logs "Parameter m is null" from mesh_get_surface_count; it does not occur with a real GL driver and does not affect logic.
  • Steps are visual-only (no collider) so NPCs can path to the entrance; the guard spawns on the landing so it never needs to climb.
  • Persistence tests write into the real user://shift_results.json (harmless local pollution of the demo history).
  • macOS export required rendering/textures/vram_compression/import_etc2_astc=true in project.godot (universal build demands ETC2 ASTC enabled).
  • Joke Shop door_staff_lines authored but not yet surfaced in the prototype UI (tracked in TODO).

Open Questions

  • Whether the responder avatar should be playable/controllable or purely scripted.
  • Localization target languages beyond English.
  • macOS notarization approach for broad distribution.

Plan vs TODO Gaps (evaluated 2026-10-31, all resolved)

All previously identified gaps are now implemented and covered by tests/smoke items: PROTESTER archetype, door lock/secure, flashlight, CALL_SOMEONE reaction, LATE phase fix, shift-result persistence, NavigationAgent3D movement, and JSON-backed localization. Remaining backlog lives in TODO.md.