Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
51 changes: 51 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Validate

# Every pull request, and every landing on main. The push trigger is not redundant with the pull
# request one: a squash merge produces a commit nothing has ever run against, since what CI checked
# was the branch rather than the result of collapsing it onto main.
on:
pull_request:
push:
branches:
- main

# a second push to a branch makes the first run's answer irrelevant, so it is cancelled rather than
# left to finish. main is deliberately not cancelled: every commit that lands there gets its own
# verdict, because that is the history someone will later bisect.
concurrency:
group: validate-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
validate:
name: validate
runs-on: ubuntu-latest

steps:
# the validator reads the database, the plugin list and the mirrored plugins, and nothing else.
# img/ and audio/ are most of the working tree, so they are left out of the checkout entirely;
# git still tracks every file, which is what the committed-backup check reads.
- name: Checkout
uses: actions/checkout@v7
with:
sparse-checkout: |
chef-adventure/data
chef-adventure/js
tools

# Bun is the only runtime this repository uses, pinned to match rmmz-plugins.
- name: Install Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13

# proves every check still catches the bug it exists for, by planting each one in memory against
# this very tree. A validator that reports clean is indistinguishable from one that is broken, so
# the proof runs first and on every commit, not once when the check was written.
- name: Selftest
run: bun run validate:selftest

# parse floor, committed backups, plugin drift against the rmmz-plugins manifest, every id a
# notetag names, and every id a plugin config names in an MZ table.
- name: Validate
run: bun run validate
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ node_modules
*~

# database backups taken before a risky edit; keep them locally, never in history.
# Classes.old.json predates this rule and stays tracked, since it is the copy that
# recovered 282 aptitude tags after the clobber and is worth keeping findable.
*.backup.json
*.backup-*.json
*.old.json
*.backup*
*.bak*
# generated maps awaiting review; tools/mapgen/install.js is what moves them into data/
tools/mapgen/.staging/
26 changes: 26 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,32 @@ erroring, which makes a missing tag look like a targeting bug.

---

## Validating the data

**`bun run validate` checks the seams between the three things that write `chef-adventure/data/`** -
RPG Maker MZ, jmz-data-editor and the scripts in `tools/` - and CI runs it on every pull request. It
takes well under a second. Run it after any bulk edit to the data, and before committing one.

| Check | Fails when |
|---|---|
| parse floor | any `data/**/*.json` does not parse |
| housekeeping | a `*.old.json`, `*.backup*` or `*.bak*` file is committed |
| plugin drift | `js/plugins/j/` holds a file the rmmz-plugins build did not produce, or one it changed |
| notetags | a tag names a row that is blank or missing, or matches no pattern any J plugin declares |
| config references | a `config.*.json` names a blank or missing row in an MZ table |

What every tag means - its patterns, and which payload values are ids into which table - comes from
`js/plugins/j/manifest.json`, which the rmmz-plugins build writes and `hotfix` mirrors in with the
plugins. **It is generated; never edit it.** A tag the validator wrongly calls unknown, or an id it
resolves against the wrong table, is fixed upstream in `rmmz-plugins/src/build-tools/`
(`notetag-declarations.js`, `notetag-id-targets.js`), never by teaching the validator an exception.

`bun run validate:selftest` plants each kind of bug in memory - a drop aimed at a blank armor, a
typo'd `<sght:5>`, a stray plugin file - and fails unless every one is caught. Run it if a green
result ever seems too good to be true.

---

## Git and pull requests

- **Never push directly to `main`.** Feature branch and a PR, always.
Expand Down
126 changes: 13 additions & 113 deletions chef-adventure/data/Armors.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions chef-adventure/data/Classes.json

Large diffs are not rendered by default.

27 changes: 0 additions & 27 deletions chef-adventure/data/Classes.old.json

This file was deleted.

12 changes: 6 additions & 6 deletions chef-adventure/data/Enemies.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion chef-adventure/data/Map001.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion chef-adventure/data/Map107.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ null,
{"id":3,"name":"bloodtrap","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"m_monsters2","direction":2,"pattern":1,"characterIndex":5},"list":[{"code":108,"indent":0,"parameters":["<motion:[swing]>"]},{"code":108,"indent":0,"parameters":["<enemyId:302>"]},{"code":408,"indent":0,"parameters":["<sight:3>"]},{"code":408,"indent":0,"parameters":["<pursuit:10>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:3.6>"]},{"code":408,"indent":0,"parameters":["<jabsConfig:noIdle>"]},{"code":108,"indent":0,"parameters":["<alertedSightBoost:8>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:2>"]},{"code":408,"indent":0,"parameters":["<alertDuration:240>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":15,"y":20},
{"id":4,"name":"megataur","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"m_minotaurs","direction":2,"pattern":1,"characterIndex":7},"list":[{"code":108,"indent":0,"parameters":["<motion:[breathe]>"]},{"code":108,"indent":0,"parameters":["<enemyId:452>"]},{"code":408,"indent":0,"parameters":["<sight:4>"]},{"code":408,"indent":0,"parameters":["<pursuit:9>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:3.8>"]},{"code":108,"indent":0,"parameters":["<alertDuration:600>"]},{"code":408,"indent":0,"parameters":["<alertedSightBoost:4>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:10>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":8,"y":7},
{"id":5,"name":"sign","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":true,"image":{"tileId":0,"characterName":"$sign","direction":8,"pattern":1,"characterIndex":0},"list":[{"code":101,"indent":0,"parameters":["",0,1,1,""]},{"code":401,"indent":0,"parameters":[""]},{"code":401,"indent":0,"parameters":["Into Cave: Forlorn Basin, Forest of Dreams"]},{"code":401,"indent":0,"parameters":["Right: Outer Cliffs"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":4,"y":9},
{"id":6,"name":"skeletor","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"m_undead","direction":2,"pattern":1,"characterIndex":1},"list":[{"code":108,"indent":0,"parameters":["<motion:[breathe]>"]},{"code":108,"indent":0,"parameters":["<enemyId:131>"]},{"code":408,"indent":0,"parameters":["<aiTrait:smart>"]},{"code":408,"indent":0,"parameters":["<aiTrait:leader>"]},{"code":408,"indent":0,"parameters":["<sight:2>"]},{"code":408,"indent":0,"parameters":["<pursuit:8>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:4.1>"]},{"code":108,"indent":0,"parameters":["<alertDuration:600>"]},{"code":408,"indent":0,"parameters":["<alertedSightBoost:6>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:10>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":23,"y":4},
{"id":6,"name":"skeletor","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"m_undead","direction":2,"pattern":1,"characterIndex":1},"list":[{"code":108,"indent":0,"parameters":["<motion:[breathe]>"]},{"code":108,"indent":0,"parameters":["<enemyId:131>"]},{"code":408,"indent":0,"parameters":["<aiTrait:careful>"]},{"code":408,"indent":0,"parameters":["<aiTrait:leader>"]},{"code":408,"indent":0,"parameters":["<sight:2>"]},{"code":408,"indent":0,"parameters":["<pursuit:8>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:4.1>"]},{"code":108,"indent":0,"parameters":["<alertDuration:600>"]},{"code":408,"indent":0,"parameters":["<alertedSightBoost:6>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:10>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":23,"y":4},
{"id":7,"name":"skeledoggo","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"$m_undeadDog","direction":4,"pattern":1,"characterIndex":0},"list":[{"code":108,"indent":0,"parameters":["<motion:[stretch]>"]},{"code":108,"indent":0,"parameters":["<enemyId:132>"]},{"code":408,"indent":0,"parameters":["<aiTrait:follower>"]},{"code":408,"indent":0,"parameters":["<aiTrait:reckless>"]},{"code":408,"indent":0,"parameters":["<sight:1>"]},{"code":408,"indent":0,"parameters":["<pursuit:5>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:4.2>"]},{"code":108,"indent":0,"parameters":["<alertDuration:300>"]},{"code":408,"indent":0,"parameters":["<alertedSightBoost:2>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:4>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":21,"y":5},
{"id":8,"name":"prince cobra","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"m_cobra","direction":2,"pattern":1,"characterIndex":7},"list":[{"code":108,"indent":0,"parameters":["<motion:[swing]>"]},{"code":108,"indent":0,"parameters":["<enemyId:151>"]},{"code":408,"indent":0,"parameters":["<sight:2>"]},{"code":408,"indent":0,"parameters":["<pursuit:8>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:4.1>"]},{"code":108,"indent":0,"parameters":["<alertDuration:600>"]},{"code":408,"indent":0,"parameters":["<alertedSightBoost:6>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:10>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":28,"y":13},
{"id":9,"name":"prince cobra","note":"","pages":[{"conditions":{"actorId":1,"actorValid":false,"itemId":1,"itemValid":false,"selfSwitchCh":"A","selfSwitchValid":false,"switch1Id":1,"switch1Valid":false,"switch2Id":1,"switch2Valid":false,"variableId":1,"variableValid":false,"variableValue":0},"directionFix":false,"image":{"tileId":0,"characterName":"m_cobra","direction":2,"pattern":1,"characterIndex":7},"list":[{"code":108,"indent":0,"parameters":["<motion:[swing]>"]},{"code":108,"indent":0,"parameters":["<enemyId:151>"]},{"code":408,"indent":0,"parameters":["<sight:2>"]},{"code":408,"indent":0,"parameters":["<pursuit:8>"]},{"code":408,"indent":0,"parameters":["<moveSpeed:4.1>"]},{"code":108,"indent":0,"parameters":["<alertDuration:600>"]},{"code":408,"indent":0,"parameters":["<alertedSightBoost:6>"]},{"code":408,"indent":0,"parameters":["<alertedPursuitBoost:10>"]},{"code":0,"indent":0,"parameters":[]}],"moveFrequency":3,"moveRoute":{"list":[{"code":0,"parameters":[]}],"repeat":true,"skippable":false,"wait":false},"moveSpeed":3,"moveType":0,"priorityType":1,"stepAnime":false,"through":false,"trigger":0,"walkAnime":true}],"x":29,"y":14},
Expand Down
Loading
Loading