Skip to content

The doctor's arc walk respects locks: a key must be reachable without passing its own door - #378

Merged
calebl merged 1 commit into
mainfrom
fm/ta-doctor-lock-reachability
Nov 2, 2026
Merged

calebl merged 1 commit into
mainfrom
fm/ta-doctor-lock-reachability

Conversation

@calebl

@calebl calebl commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

What

G1 from the design research report: the doctor's "the arc can complete" check (P3) ignored locks. It walked every connection row, so a world whose key lay behind its own door passed as completable.

  • Story::Doctor#reachable_from_the_opening is now lock-aware. A keyed door opens only once its key, or any lockpick (the engine's pick choice), lies somewhere already reached. The walk repeats until the set of keys in hand stops growing, so chained keys are followed and a key behind its own lock, or a cycle of keys behind each other's locks, opens nothing. A jammed door always counts as passable, because force needs no tool. Where a door has rows in both directions, each direction follows its own row; where only one row is recorded, the walk uses that row both ways, as before.
  • New warning lock_whose_key_lies_behind_it (remedy manual). It names each door the walk leaves shut with its far side out of reach, and says where the key is: on the far side of that same door, behind another lock whose key is also out of reach, or nowhere reachable. Any arc target behind such a door is still reported as the fatal quest_target_unreachable. A door whose near side is itself out of reach is not reported; the lock in front of it is the one to fix.
  • New sweep world lib/engine_sweep/worlds/a-key-locked-in-with-its-door.yml trips both findings: one key behind its own door, and two keys behind each other's doors. EngineSweepTest lets this world, and only this world, carry those two findings. No sweep script walks it, because scripts play against engine-vendored goldens.
  • Story::DoctorLocksTest covers passing and failing cases: a key on the near side, a key in the protagonist's starting hands, a chain of keys, a reachable lockpick, a jammed door, a key behind its own lock, a two-key cycle, and the sweep world. SeededWorldsTest's arc findings now include the new code.

The doctor still only reads and reports. It never changes a world.

Idea source: Scouten2/LevelDesignSkill graph_check.py (MIT). This is a Ruby reimplementation over the doctor's own records; no code was copied.

Every world doctored

The doctor was run over every hand-made world in db/seeds/worlds/ and every sweep world. No hand-made world fails. The only world with either finding is the new one. a-key-for-the-other-door keeps a key behind its own lock but passes, because a lockpick lies in the opening room.

Checks

The full suite passes except two ViewportPinControllerTest cases that failed on the second run with a headless Chromium/dbus error. They are unrelated to this change, and they passed on the first full run. rubocop, zeitwerk:check and brakeman are clean. bin/rails engine:rust_gates passes on all 114 scripts. No model calls were made: the model keys were unset.

… passing the door it opens

Story::Doctor#reachable_from_the_opening now opens a keyed door only once
its key (or any lockpick) lies somewhere already reached, iterated to a
fixed point; a jammed door can always be forced. A new warning,
lock_whose_key_lies_behind_it, names each door that walk leaves shut with
its key behind it, behind another unopenable lock, or nowhere; a target
stranded behind one is quest_target_unreachable (fatal) as before.

Adds the sweep world a-key-locked-in-with-its-door, which trips both, and
Story::DoctorLocksTest. Graph idea from Scouten2/LevelDesignSkill
graph_check.py (MIT), reimplemented over the doctor's own records.
@calebl
calebl merged commit 606a478 into main Nov 2, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant