Skip to content

tech-debt sweep: nothing states what 'paused' means, so 9 timers, 18 tweens and 47 input surfaces each decided for themselves (due 2026-09-04) #1343

Description

@PipFoweraker

Tech-debt sweep, scoped and measured in docs/PAUSE_SEMANTICS_SWEEP.md.
Requested by Pip on 2026-08-30 after #1341 was found on a shipped build.

Due by Friday 2026-09-04, for the league patch. Declared in the calendar:

COMMITMENT: 2026-09-04 -- Sweep the pause-semantics family ... -- owner: pip -- kind: deadline

The one-sentence problem

Nothing in this repository states what "paused" means, so every site that
could observe SceneTree.paused decided for itself -- usually by inheriting an
engine default that says to ignore it.

#1341 is one member: SceneTree.create_timer() defaults process_always to
true, so the month-playback loop ticked straight through the pause menu. Six
day-ticks and a month boundary ran while Pip had the menu open to change the
volume. That is fixed, narrowly, at the two gameplay-advancing sites. This is the
part that is not narrow.

Measured surface, 2026-08-30

Timers that ignore pause -- 9 remaining sites.

grep -rn "create_timer(" godot/scripts/ --include=*.gd | grep -v ", *false" | grep -v ", *true"

None advances game state, which is why the #1341 fix stops at two. But "does not
advance state" is not "is correct" -- plan_screen.gd:58 lets a 4s error toast
expire while you are reading the pause menu, and conference_vignette.gd paces a
mid-run sequence you can press ESC during. Nobody has decided which of these
should stop.

Tweens -- 18 sites, none of which say anything about pause.

grep -rc "create_tween()" godot/scripts/ --include=*.gd   ->  18
grep -rc "set_pause_mode|TWEEN_PAUSE" godot/scripts/      ->   0

Every tween inherits pause behaviour from its creating node and no site has
examined that. This family already has a known latent member: #1034, which
records that the fade transition awaits a pausable tween and "would deadlock ALL
navigation if called while paused"
. It has never fired only because nothing has
yet called it from a paused state.

Input capture by things you cannot see -- 47 mouse_filter sites.

The second half of what Pip hit: the pause menu was open, drawn under the Month
Review dialog, and still eating clicks. Fixing the timer removes the common path
into that state; it does not answer which overlay owns input when two are up.
Related: #603 (events leak under the fanfare popup), #1028 (ESC/pause disables
all diagnostic surfaces -- root cause is process_mode).

Definition of done

  1. A written statement of what pausing means, in one place, covering the
    simulation, presentation beats, audio, input and navigation. Likely an ADR --
    the answer is a design decision, not a bug fix.
  2. Each site above conformed to it, or explicitly excepted with the reason
    next to the code.
  3. A guard so the next one cannot land silently. Cheapest honest version: flag
    get_tree().create_timer( with no explicit second argument under
    godot/scripts/, forcing the author to state intent either way. Greppable,
    gateable, same family as check_scene_nav.py. Should ship with a self-test and
    be wired into guards.yml, per the doctrine already established there.

Why sweep rather than wait for the next report

This class does not announce itself. Every member is a default nobody chose, and
each stays invisible until a player does something ordinary -- opens a menu,
changes the volume, presses ESC at the wrong moment. #1341 sat in a shipped build
and reached players. #1034 is sitting in this one now, waiting for the first
navigation call from a paused state.

The fix per site is usually one argument. The expensive part is knowing which
sites, and that is what this sweep buys.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    technical-debtTechnical debt that needs addressing

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions