Repository navigation
Grow an overdue arc step only in ground nobody has written - #96
Merged
Merged
Conversation
VISION principle 7: the engine does not change the world after it is generated. The quest deadline hung a new doorway, and could lay a thing, on a room the world had already written (the old anchor, the deepest reachable room). It now grows what the step needs off the way on (deadline::way_on): the deepest reachable room nobody has written yet, or, with none, the room whose writing is finishing, which nobody has seen written. A person may still be brought into a written room (the principle's exception) and needs no free doorway when one exists. A thing laid in an unwritten room standing on its own first gets the box its writing would give it, and the writing keeps box and spot. With no ground to grow in, nothing is placed until the next room is written. The new sweep a-deadline-leaves-written-rooms-as-they-were places all three of the yard's steps and walks to each; tests/deadline.rs plays it step by step and asserts no room written before a step changes during it, and covers the fallback and a thing in a plain stub. a-deadline-places-what-the-arc-waits-for walked through the door bolted onto the loft, so its tail now walks through the wash house; its golden and records are re-blessed. No other golden, records file or vector moves, and the reference fights agree.
…ten ground (renderedstep/server b2a4523) The game's pin PR (renderedstep/server#372) carries the Ruby mirror of deadline::way_on, both deadline scripts and their goldens, records and checks, all byte for byte this repository's. No golden moves here.
calebl
added a commit
to renderedstep/server
that referenced
this pull request
Oct 30, 2026
calebl
added a commit
to renderedstep/server
that referenced
this pull request
Oct 30, 2026
…ted-once-server Pin renderedstep/engine#96's head (d57d7f9): grow an overdue arc step only in ground nobody has written
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
VISION principle 7 says the engine does not change the world after it has generated it. The quest deadline broke that rule. When an overdue story goal came due, it hung a new doorway on a room the world had already written (
open_the_dooroffdeadline::anchor, the deepest reachable room), and it could drop the goal's thing onto that room's floor. This is section 8, rows 1 and 2, of the dungeon-stage4-c2c audit.The deadline now grows what the goal needs only in ground nobody has written yet:
deadline::way_on). It picks the deepest room the party can reach that is still unwritten. The order is the old one: lowest storey, then farthest, then lowest id, among rooms that are not places and have a doorway to spare. That is "a doorway the world already has that leads somewhere not yet written". If no such room exists, it uses the room whose writing is finishing, which is the room that runs the deadline. That room's writing ends in this same turn and nobody has seen it written, so whatever grows off it is part of its own writing. This is the "next room written" fallback.lay_out_alone, seeded on the room), so the thing gets a spot. The later writing keeps both the box and the spot.story_cannot_progressfinding names it ("a world past that with nothing bound is one that has stopped growing"). This takes four doorways into one stub from already-written rooms with nothing else unwritten. The old rule could also find no anchor once every reachable room was full, so this is not a new kind of failure, and I did not treat it as a product decision. If it should be one, the options are: (a) keep the wait (this PR); (b) let the room being written exceedMAX_EXITSby one for the arc; (c) allow a door on a written room in that one case, which breaks principle 7.deadline::anchoris unchanged and nothing places from it any more. It stays becausevectors/deadline.jsonis exported by the game from Ruby's#anchor. It can be removed together with that vector.No prompt changes. No model calls. The moving city and the dungeon stages are untouched.
Proof
a-deadline-leaves-written-rooms-as-they-were(yard world, inPASSING, with a records file). Three rooms are written past the grace period, and each places one goal. The walk then goes to all three: the warden in the place built off the Wash House before it was written, the Salt Stair laid out off the bottom of that place, and the iron seal lying in an unwritten room of the stair, which it picks up. All three beats end bound and two are reached.tests/deadline.rs:a_deadline_lands_without_changing_a_room_already_writtenplays that sweep one step at a time. After each step it asserts that every room written before the step is identical: its row (lesslast_protagonist_visit), every doorway into or out of it, and every world thing lying in it.with_nothing_left_unwritten_the_step_grows_off_the_room_being_writtencovers the fallback.a_thing_lies_in_a_room_nobody_has_written_and_its_writing_keeps_itcovers a thing in a plain stub, including its box and spot.src/deadline.rsforway_on.cargo fmt --check,cargo clippy --workspace --all-targets --locked -- -D warnings,cargo test --workspace --locked,parity --check parity(105 of 109 agree; the 4 left are the unchanged runner-only scripts), andfight --check sim(10 fight goldens agree, so the reference fights are unchanged).Goldens re-blessed (only those this change moves)
parity/goldens/a-deadline-places-what-the-arc-waits-for.jsonandparity/records/a-deadline-places-what-the-arc-waits-for.json. The script changed with it: its old last three steps walked Kitchen → Loft → the warden's door bolted onto the Loft. That door no longer exists, so the walk now goes back into the Wash House, which was written after the door was laid on it, and through that door. From step 3 the Wash House's ways out includewhere Warden Hesk is room 1, and the Salt Stair and the iron seal land in unwritten ground.parity/goldens/a-deadline-leaves-written-rooms-as-they-were.jsonandparity/records/a-deadline-leaves-written-rooms-as-they-were.json.No other golden, records file or vector moved. The four runner-only scripts write no room under an arc, so they cannot move.
What the server pin PR must change (renderedstep/server)
app/models/quest/deadline.rb(the Ruby mirror):after_realizing!(location)keeps passing the realized room.#run!places fromway_on(anchor_hint)instead of#anchor.#way_on(written): amonghops.keysrooms that are not realized, notlaid_out?, not a place with a footprint and no box (Location#interior?with no box: the engine'sis_place), and with fewer thanMAX_EXITSdoorways out, take the minimum of[z.to_i, -hops, id]. If there are none, usewrittenwhen it is reached, not such a place, and has a doorway to spare. Otherwise nil.#place_a_place!and#build_somewhere_to_keep_them!open their door off that room.#place_a_person!triesdeepest_room_of_a_place_we_can_reachfirst even whenway_onis nil, and builds a place only whenway_onhas a room.#place_a_thing!admits into the way on, afterLocation::Layout's own-box step for a stand-alone room with no box yet (the engine'slay_out_alone).#anchorcan stay as it is forlib/engine_vectors/deadline.rb.test/engine_vectors/deadline.jsondoes not change.test/models/quest/deadline_test.rb:open_roomsbuilds a chain of realized rooms with no stubs, so every placement goes off the room passed toafter_realizing!, the fallback. These tests must change:below(z: -2) should still be chosen, now as the way on. Rename it and assert that the cellar gains no door.deepestis the realized room, so it still holds as the fallback.data/ta-quest-deadline-generated-once/server/lib/engine_sweep/scripts/. Both re-emit through the README's Ruby YAML command byte-identical to this repo's copies.lib/engine_sweep/scripts/a-deadline-places-what-the-arc-waits-for.yml(changed tail and header)lib/engine_sweep/scripts/a-deadline-leaves-written-rooms-as-they-were.yml(new)test/engine_parity/.bin/rails engine:checksfor both scripts and committest/engine_parity/a-deadline-places-what-the-arc-waits-for.checks.json(it moves: the warden's place now hangs off the Wash House, and the iron seal lies in a stub) and the newa-deadline-leaves-written-rooms-as-they-were.checks.json. The doctor's own code does not assert the old shape. It reads onlyQuest::Deadline.overdue?andGRACE_ROOMS, which are unchanged, and its wording still holds. Expectcharacter_in_a_stub-style warnings for the placed targets, as today.EngineSweep::Invariantscould add the same check this repo'stests/deadline.rsmakes: no room realized before a step gains or loses a doorway or a world thing during it.SERVER_COMMITtogether.CI at the current pin (
SERVER_COMMIT6b85c8f): thefmt, clippy, testjob and the sweep and fight checks pass here. The extension still builds against this checkout (it does not usedeadline). Therunnerjob'sengine:rust_gatesandrunner.shplay the server's own copy ofa-deadline-places-what-the-arc-waits-for, whose old Loft route no longer exists, so that one script is expected to fail there until the server branch carrying step 3 above exists andSERVER_COMMITpoints at it.runner.shskips the new script until the server has it.