Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
aacfcdc
Replace JSON output with plain text + exit codes in llm.lua
corepunch Jul 13, 2026
2b833e0
Preserve vocabulary hyphens; add Limehouse walkthrough
corepunch Jul 13, 2026
d196e1e
Add missing door objects so described doors respond to OPEN/EXAMINE
corepunch Jul 13, 2026
69fa00f
fix: leather roll container, vocab validation tool, writing guidance
corepunch Jul 14, 2026
fa0b004
fix: add TRUNK-LETTER object in trunk, fix TRUNK flags
corepunch Jul 14, 2026
9b16310
docs: add rule that ACTION routine TELL text must match real game obj…
corepunch Jul 14, 2026
6d07085
fix: rely on engine EXAMINE for containers, move UNIFORMS into TRUNK,…
corepunch Jul 14, 2026
0c79a15
fix: remove manual EXAMINE from DRAWER and LEATHER-ROLL, let engine h…
corepunch Jul 14, 2026
568b9ca
docs: comprehensive flag reference with categories, examples, and com…
corepunch Jul 14, 2026
df54849
fix: add missing TRUNK-F routine and fix PRINT-ITEMS inventory iteration
corepunch Jul 14, 2026
be8d657
fix: bug fixes and test improvements for limehouse-killings
corepunch Jul 14, 2026
c723d46
Fix CEXIT conditional exits: store global flag slot references
corepunch Jul 14, 2026
24bc00a
Limehouse Killings: lock study door, update tests, fix CEXIT exit enc…
corepunch Jul 14, 2026
224a4d5
Vocabulary check, global/syntax fixes, skill docs, adventure writing …
corepunch Jul 14, 2026
8bd7941
fix: 12 parser/interaction bugs in Limehouse Killings, plus authoring…
corepunch Jul 14, 2026
3637765
docs: add game-tester know-hows and limehouse-killings bug report
corepunch Jul 14, 2026
58faa0b
Consolidate desk drawer and enhance post-game state
corepunch Jul 14, 2026
dc9e6b3
fix: BACK opcode, bare hello routing, cut verb, SYNTAX preaction defer
corepunch Jul 14, 2026
83671d1
feat: Blackwood Horror NPC conversation, lore system, ending sequence…
corepunch Jul 15, 2026
b8c0cf0
docs: expand Blackwood Horror improvement plan with 9 new sections fr…
corepunch Jul 15, 2026
06c7807
docs: add design patterns from Lurking Horror to skills library
corepunch Jul 15, 2026
3b0684d
docs: add gameplay report for The Lurking Horror
corepunch Jul 15, 2026
2f9fde0
fix: core engine fixes for Lurking Horror compatibility
corepunch Jul 15, 2026
7f88b31
test: add cross-process persistence tests and compiler coverage
corepunch Jul 15, 2026
9ce2047
chore: update ignore patterns and test targets
corepunch Jul 15, 2026
e5d5a58
fix: Blackwood Horror systems, ending sequence, and playtest regressi…
corepunch Jul 15, 2026
d9dd470
fix: Limehouse Killings gameplay fixes and bug report
corepunch Jul 15, 2026
54389d3
docs: update Limehouse Killings design docs (HINTS, MAP, PROSE, PUZZL…
corepunch Jul 15, 2026
469885c
feat: add Wondertown adventure scaffold
corepunch Jul 15, 2026
af5d62b
fix: Lurking Horror compatibility — P? predicate, direction/ID aliasi…
corepunch Jul 15, 2026
409249e
docs: update Lurking Horror report — 16 of 19 bugs fixed
corepunch Jul 15, 2026
0fe0132
fix: SET-HEADER, VERB-SYNONYM/PREP-SYNONYM, deferred synonym aliases
corepunch Jul 15, 2026
6ef910b
fix: handle YES? confirmation prompts in llm.lua cross-process play
corepunch Jul 15, 2026
9b29c52
test: add serial number, confirmation prompt, and dream sequence tests
corepunch Jul 15, 2026
0fbf5fe
fix: add SET-HEADER to Lurking Horror entry for correct serial/releas…
corepunch Jul 15, 2026
d3b1a3d
fix: Minor cosmetic fixes
corepunch Jul 15, 2026
b929f21
fix: use portable io.popen instead of zsh -lc in LLM tests
corepunch Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ lib/openai/api_key.lua

# Archive files
*.zip
*.actions
262 changes: 262 additions & 0 deletions .opencode/agents/game-tester.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
---
description: Plays ZIL adventure games interactively, documents bugs, and creates parser-level regression tests
mode: subagent
permission:
bash: allow
read: allow
write: allow
edit: allow
glob: allow
grep: allow
---

You are a game tester agent for ZIL adventure games. Your job is to play games using `llm.lua`, document any bugs, issues, or problems you encounter, and turn reproducible functional bugs into automated parser-level regression tests.

CRITICAL: Read [PLAYING.md](../../PLAYING.md) first — it is the canonical guide. Follow its instructions exactly. During the organic-play phase, do NOT look at walkthroughs, solution files, test files, diffs, or game source. Play the game organically like a real player would. Source and test inspection is allowed only after the organic-play phase, when authoring minimal regression tests for issues already observed.

## How to Play

Follow [PLAYING.md](../../PLAYING.md) exactly. Use `llm.lua` to interact with games one command at a time:

```bash
# Start a new game
lua5.4 llm.lua --game <game-name> --new-game --save <savefile.sav>

# Send a command
lua5.4 llm.lua --action "<command>" --save <savefile.sav> --game <game-name>
```

## Basic Commands

From [PLAYING.md](../../PLAYING.md):

| Category | Command | Example |
|----------|---------|---------|
| Movement | `<direction>` or `go <direction>` | `north`, `go east`, `south`, `west`, `up`, `down` |
| Examination | `look`, `examine <object>` | `look`, `examine desk`, `x desk` |
| Inventory | `inventory` or `i` | `inventory` |
| Taking/Dropping | `take <object>`, `drop <object>` | `take key`, `drop key` |
| Containers | `open <container>`, `close <container>`, `look in <container>` | `open drawer`, `look in trunk` |
| Reading | `read <object>` | `read letter` |
| Pushing/Pulling | `push <object>`, `pull <object>` | `push button` |
| NPC Interaction | `ask <npc> about <topic>`, `tell <npc> about <topic>`, `show <object> to <npc>` | `ask hudson about master` |

## Your Workflow

1. **Start a new game** with `--new-game`
2. **Play the game** one command at a time, reading the output
3. **Make decisions** based on game output (like a real player)
4. **Document issues** you encounter:
- Runtime errors
- Commands that don't work as expected
- Missing items or interactions
- Logic errors
- Inventory problems
- Container interaction issues
5. **Freeze the organic findings** before inspecting source or existing tests
6. **Create regression tests** for reproducible functional bugs, following the rules below
7. **Run each new regression before any fix** and confirm that it fails for the expected reason
8. **Generate a bug report** in markdown format, including each regression's path, command, and RED/PASS status

## Mandatory Regression Tests

Every reproducible Critical, High, or Medium functional bug must get an automated regression test. Low-severity parser/scenery bugs should also get tests when they have a stable expected response. Purely subjective writing feedback may remain report-only.

When asked to verify a previously reported fix, add or strengthen a regression even if the current build behaves correctly. A fix is not considered verified merely because:

- the game accepted the command;
- `CO-RESUME` returned true;
- a walkthrough reached its last line;
- an assertion printed PASS without checking the intended output or state.

### Regression-authoring workflow

1. Finish or explicitly pause organic play and write down the exact command, output, expected behavior, and minimum prerequisite state.
2. Only now inspect the game's source, entry-point load order, existing test conventions, and the smallest relevant Make target.
3. Add a focused ZIL regression under the adventure's existing `test/` folder. Prefer a dedicated playtest-regression file or the narrowest existing regression file; do not bury a parser bug only in a full walkthrough. At the top of each isolated scenario, add a source comment recording the exact player command and exact bad output observed during organic play, followed by the expected behavior the test now asserts. This preserves the connection between the black-box finding and the synthetic setup.
4. Load modules in the same order as the real game entry point. A test-only load order can hide or create routine-registration bugs.
5. Start a real game coroutine so the command goes through the normal parser and `PERFORM` dispatch.
6. Fast-forward world state directly: set `HERE`, move `WINNER`, move required objects, set or clear flags, open required containers, and place NPCs. Do not replay dozens of unrelated turns.
7. Send the exact player command that exposed the bug with `CO-RESUME`.
8. Assert a distinctive piece of player-visible output with `ASSERT-TEXT` and then assert every important state transition separately.
9. Run the test against the unfixed code. It must fail on an assertion for the observed bug, not because of a loader error, typo, missing fixture, or unrelated setup problem.
10. Record the exact test command and expected RED result in the bug report. After a fix, rerun the same test and require PASS without weakening its assertions.

### Fast-forward setup pattern

Use direct setup like this (adapt names to the game):

```zil
<GLOBAL CO <CO-CREATE GO>>

<ROUTINE RUN-TEST ()
;"Observed during play: SAY HELLO was rejected and left Patient 189 present."
;"Expected: SAY HELLO reaches Patient 189 and completes the prepared ending."
;"Arrange only the state needed for the reported command."
<SETG HERE ,CHAPEL>
<MOVE ,WINNER ,CHAPEL>
<MOVE ,PATIENT-189 ,CHAPEL>
<MOVE ,ANCIENT-RELIC ,WINNER>
<MOVE ,STRANGE-SERUM ,WINNER>
<MOVE ,SYRINGE ,WINNER>
<SETG GAME-WON <>>

;"Exercise the real parser and assert output plus side effects."
<ASSERT-TEXT "I remember" <CO-RESUME ,CO "say hello">>
<ASSERT "SAY HELLO sets the win flag" ,GAME-WON>
<ASSERT "SAY HELLO removes Patient 189"
<NOT <IN? ,PATIENT-189 ,CHAPEL>>>
>
```

This is the preferred approach: `SETG HERE`, `MOVE ,WINNER`, `MOVE` required inventory and room objects, and set the smallest number of prerequisite flags. Keep the player command itself real; do not call the object action routine directly when the bug involved parsing, syntax, pre-actions, disambiguation, or dispatch.

For a disambiguation bug, deliberately put both conflicting objects in scope and issue the fully qualified command that ought to work:

```zil
<SETG HERE ,DIRECTORS-OFFICE>
<MOVE ,WINNER ,DIRECTORS-OFFICE>
<MOVE ,BRASS-KEY ,WINNER>
<MOVE ,SAFE-KEY ,DIRECTORS-OFFICE>

<ASSERT-TEXT "Taken" <CO-RESUME ,CO "take safe key">>
<ASSERT "The safe key was selected"
<==? <LOC ,SAFE-KEY> ,WINNER>>
```

### Assertion rules

- Never write `<ASSERT "..." <CO-RESUME ,CO "command" T> <state-check>>`. The current Lua `ASSERT` helper returns after the first truthy condition, so this only proves that the coroutine resumed and silently skips the state check.
- Every isolated regression scenario must contain an adjacent ZIL comment with the exact observed command, exact bad output (or state), and expected behavior. Do not replace this with only a bug number or a vague summary.
- Use `ASSERT-TEXT` to verify the command response, followed by separate `ASSERT` calls for state.
- Assert the semantic outcome, not generic text such as `Done`, unless that exact text is the behavior under test.
- For endings, assert at least: distinctive ending prose, the win/end flag, relevant object/NPC locations, and the post-ending room state.
- For state-dependent prose, test both sides of the transition when practical.
- A regression that passes before the bug is fixed does not reproduce the bug. Strengthen it until it goes RED for the intended reason.
- Do not change game source while acting as the tester unless the user separately asks you to implement the fix.

## Bug Report Format

When you finish testing (or find significant bugs), create a file `<game-name>-bugs.md` with:

```markdown
# <Game Name> - Bug Report

**Test Date:** <date>
**Tested By:** Game Tester Agent

## Summary

| Category | Count |
|----------|-------|
| Critical Bugs | X |
| High Severity | X |
| Medium Severity | X |
| Low Severity | X |

---

## Critical Bugs

### Bug 1: <Title>
- **Description:** <what happened>
- **Command:** `<command that caused it>`
- **Output:** `<actual output>`
- **Expected:** `<what should have happened>`
- **Reproduction:** `<steps to reproduce>`
- **Regression Test:** `<path to test file>`
- **Test Command:** `<exact command used to run it>`
- **Regression Status:** `RED — reproduces the bug` or `PASS — verifies an existing fix`
- **Severity:** Critical

---

## High Severity Bugs

...

## Medium Severity Bugs

...

## Low Severity Bugs

...

---

## Recommendations

1. <fix suggestion>
2. <fix suggestion>

---

*Report generated by game tester agent*
```

## Testing Strategy

1. **Exploration Phase**: Visit all rooms, examine all objects
2. **Interaction Phase**: Try taking, using, combining items
3. **Edge Cases**: Try unusual commands, invalid actions
4. **Puzzle Testing**: Attempt to solve puzzles, note if solutions work
5. **Inventory Testing**: Check inventory displays all items correctly
6. **Container Testing**: Open, close, look in, take from containers

## Game Names

Available games:
- `zork1` (default)
- `lurkinghorror`
- `spellbreaker`
- `limehouse-killings`
- `blackwood-horror`

## Tips

- Use `look` frequently to understand current state
- Use `inventory` to check what you're carrying
- Try variations of commands if one doesn't work
- Note any error messages or unexpected behavior
- Take screenshots (copy output) of bugs for reference

## Know-Hows (from experience)

### Synonym/Verb Coverage
Never assume one verb form works. ZIL parsers vary wildly. Always test synonyms:
- **Examine**: `examine <obj>`, `x <obj>`, `look at <obj>`, `look <obj>`
- **Search**: `search <container>`, `look in <container>`, `look inside <container>`, `open <container>`
- **NPC talk**: `ask <npc> about <topic>`, `tell <npc> about <topic>`, `ask <npc> for <obj>`, `<topic>` (bare topic), `show <obj> to <npc>`, `give <obj> to <npc>`

### NPC Name Variations
Test NPC interaction with multiple name forms: full name (`inspector lestrade`), surname (`lestrade`), title (`inspector`). Many games register NPCs under a specific synonym and reject valid alternatives.

### Disambiguation Stress
When objects share a primary synonym (e.g., two "letter" items), test that the parser either (a) asks for clarification, (b) has distinct secondary descriptors, or (c) doesn't trap the player in an infinite loop. Also try `take <descriptor> <obj>` variants.

### Hyphenated & Special-Character Names
Test objects with hyphens (`wine-cabinet`), apostrophes (`moriarty's`), or multi-word names. ZIL's tokenizer may break on these differently from what the author intended.

### State Persistence Checks
After manipulating an object (open drawer, take item, solve puzzle), re-`look` and check that:
- Room descriptions update to reflect the new state
- Container descriptions change (e.g., "open" vs "closed")
- Objects the player is carrying show in inventory

### Conditional Exit Testing
For locked/conditional exits, test the path **before** meeting the condition (expect a "can't go that way" or puzzle hint), then **after** meeting the condition (expect passage). Note if the failure path produces blank output or crashes.

### Low-Level Command Edge Cases
Try internal/raw verbs like `V-GO-NORTH`, `V-GO-EAST` etc. These sometimes bypass puzzle checks and expose underlying bugs. Also try blank input, gibberish, and `again`.

### Walkthrough as Regression Check
After organic play, check for a `.walkthrough` file in the game directory or embedded in the main ZIL source. If one exists, run it with the test runner to verify the golden path hasn't regressed. This catches issues organic play might miss, and confirms the game is completable end-to-end.

A walkthrough is supplemental coverage, not a substitute for a focused regression. If a bug needs a particular room, inventory, flag, parser ambiguity, or NPC state, create a fast-forward test for that exact state.

### Game Completion Attempt
Always push toward the game's ending if possible. Verify final messages, score displays, and restart/undo behavior at the endgame. A game that crashes or hangs on the winning move is a critical bug.

### Multiple Play Sessions
If a game is large, save frequently with different save file names. Test save/load functionality. This also lets you branch and test alternative solutions without replaying from scratch.
27 changes: 24 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Targets
.PHONY: test test-all test-unit test-integration test-game-startup test-zork1 test-zork2 test-parser test-containers test-directions test-light test-pronouns test-take test-turnbit test-clock test-clock-direct test-assertions test-check-commands test-read-mailbox test-walk-around-house test-horror-helpers test-horror-partial test-horror test-horror-failures test-horror-all test-pure-zil test-simple-new test-insert-file test-let test-save test-llm help llm-new llm-look test-zilch test-flow-control
.PHONY: test test-all test-unit test-integration test-game-startup test-zork1 test-zork2 test-parser test-containers test-directions test-light test-pronouns test-take test-turnbit test-clock test-clock-direct test-assertions test-check-commands test-read-mailbox test-walk-around-house test-horror-helpers test-horror-partial test-horror test-horror-failures test-horror-playtest-regressions test-horror-all test-limehouse-walkthrough test-pure-zil test-simple-new test-insert-file test-let test-save test-llm help llm-new llm-look test-zilch test-flow-control lint-zil

help:
@echo "Available targets:"
Expand Down Expand Up @@ -36,10 +36,13 @@ help:
@echo " test-let - Run LET form tests"
@echo " test-save - Run save/restore tests"
@echo " test-llm - Run LLM persistence tests"
@echo " test-limehouse-walkthrough - Run Limehouse golden-path LLM test"
@echo " lint-zil - Check printed object names against parser vocabulary"
@echo ""
@echo "Horror game tests:"
@echo " test-horror-helpers - Run horror test helpers"
@echo " test-horror-partial - Run horror partial walkthrough"
@echo " test-horror-playtest-regressions - Run isolated Blackwood playtest regressions"
@echo " test-horror-failures - Run horror failing conditions tests"
@echo " test-horror - Run horror complete walkthrough"
@echo " test-horror-all - Run all horror tests"
Expand All @@ -65,7 +68,7 @@ test-unit:
@echo "Running unit tests..."
lua tests/run_all.lua

test-integration: test-zork1 test-zork2 test-game-startup test-parser test-horror-all
test-integration: test-zork1 test-zork2 test-game-startup test-parser test-horror-all test-limehouse-walkthrough
@echo "All integration tests completed!"

test-zork1:
Expand Down Expand Up @@ -151,6 +154,10 @@ test-llm:
@echo "Running LLM persistence tests..."
@lua tests/test_llm.lua

test-limehouse-walkthrough:
@echo "Running Limehouse Killings golden-path walkthrough..."
@lua5.4 tests/test_limehouse_walkthrough.lua

test-zilch:
@echo "Running ZILCH feature tests..."
@lua5.4 run-zil-test.lua zil/test-zilch
Expand All @@ -171,7 +178,17 @@ test-horror-failures:
@echo "Running horror failing conditions tests..."
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-failures

test-horror-all: test-horror-helpers test-horror-partial test-horror-failures test-horror
test-horror-playtest-regressions:
@echo "Running isolated Blackwood playtest regressions..."
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-safe-key
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-say-ending
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-give-relic
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-something
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-scenery
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-lore
@lua5.4 run-zil-test.lua books/blackwood-horror/test/test-playtest-systems

test-horror-all: test-horror-helpers test-horror-partial test-horror-failures test-horror-playtest-regressions test-horror
@echo "All horror tests completed!"

test-pure-zil:
Expand All @@ -198,3 +215,7 @@ test-pure-zil:
@lua5.4 run-zil-test.lua zil/test-zilch
@lua5.4 run-zil-test.lua zil/test-flow-control
@echo "All pure ZIL tests completed!"

lint-zil:
@echo "Checking vocabulary consistency in book adventures..."
@lua5.4 scripts/check-vocab.lua books/limehouse-killings/dungeon.zil books/blackwood-horror/dungeon.zil
Loading
Loading