Skip to content

Accepting a dispatch from a board cached before a map update no longer crashes - #137

Merged
Orinks merged 1 commit into
devfrom
fix/stale-dispatch-board
Jul 29, 2026
Merged

Accepting a dispatch from a board cached before a map update no longer crashes#137
Orinks merged 1 commit into
devfrom
fix/stale-dispatch-board

Conversation

@Orinks

@Orinks Orinks commented Jul 29, 2026

Copy link
Copy Markdown
Owner

What changed and why

Reported against stable 1.8.6.1: the game closes when a player accepts a job
from the dispatch board. No log was available, so both candidate paths were
driven directly.

The dispatch board is cached into the save, so it outlives the world data
the offers were built from.
Accepting a job is the only step that resolves
the pickup facility -- world.facility_approach_route ->
facility_location -- and that raises KeyError for a facility a later
update renamed or retired. Nothing caught it, so Enter on such a dispatch took
the process down:

File "src/freight_fate/states/city_dispatch.py", line 168, in _accept
    route = self.ctx.world.facility_approach_route(job.origin, job.origin_location)
File "src/freight_fate/data/world.py", line 259, in facility_location
    raise KeyError(f"Unknown facility in {city}: {location_name}")
KeyError: 'Unknown facility in buffalo_ny_us: ...'

The board opens and reads correctly first -- every line speaks, including the
job that will fail -- so the crash lands only on Enter. That matches the
report.

Two changes:

  • The board is rebuilt from the current world when any restored job names
    a pickup that is gone, so the unusable dispatch is never listed. Rebuilt
    rather than filtered, so the player still gets a full board.
  • The accept path refuses on its own, since a job detail screen opened
    before the rebuild still holds the old job. It clears the cached board and
    says what happened instead of raising.

What players will notice

Almost always nothing: after an update the first dispatch board they open is
simply built from the current world. A player who reaches a closed pickup
some other way now hears that the dispatch is no longer available and to open
the board again, instead of the game vanishing.

Tests run

  • uv run pytest -- 1410 passed.
  • tests/test_stale_dispatch_board.py is new and fails without the fix
    (verified by stashing the two source files: both cases fail, both pass with
    them restored).
  • A sweep of 855 fresh dispatches across 57 cities accepts cleanly, which
    is what places this on restored boards specifically rather than on dispatch
    acceptance generally.
  • The other candidate path was driven too and is already safe: loading a saved
    career whose in-progress trip names a retired facility, both through
    _world_entry_state and through the Choose career menu.
    DrivingState.from_snapshot already guards the same call, logs "Could not
    resume saved trip", and drops the player at the terminal. A stale
    destination is also harmless -- only the origin is ever resolved.

Accessibility impact

One new spoken line, on the refusal path: "That dispatch is no longer
available. The board was put together before the last update and this pickup
has since closed. Go back to the terminal and open the dispatch board again
for the current loads." It plays the standard ui/error sound first. A test
asserts the wording carries the two facts a player needs and contains no
maintainer jargon -- no "facility", "cache", "world data", or exception names.
Nothing else about menu navigation or the board's spoken content changed.

Changelog

  • I added a player-facing bullet under ## Unreleased in CHANGELOG.md,
    written in plain player language and matching the style of the existing
    entries.
  • This change is not player-facing, and every commit message in this PR
    includes [skip changelog].

…n accept

The dispatch board is cached into the save, so it outlives the world data
the offers were built from. Accepting a job is the only step that resolves
the pickup facility -- world.facility_approach_route -> facility_location --
and that raises KeyError for a facility a later update renamed or retired.
Nothing caught it, so Enter on such a dispatch took the process down.

Reproduced by caching a board, retiring one job's pickup facility, and
accepting it: the board opens and reads correctly, and the crash lands only
on Enter, which matches the report. DrivingState.from_snapshot already
guards the same call, which is why resuming a saved trip degrades to the
terminal instead of crashing.

Two changes. The board is now rebuilt from the current world when any
restored job names a pickup that is gone, so the unusable dispatch is never
listed -- and the player still gets a full board rather than a short one.
The accept path also refuses on its own, since a job detail screen opened
before the rebuild still holds the old job; it clears the cached board and
says what happened in plain language instead of raising.

A sweep of 855 fresh dispatches across 57 cities accepts cleanly, so this
is specific to boards restored from a save.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Orinks
Orinks merged commit a1301eb into dev Jul 29, 2026
5 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