Skip to content

Gate all suites in CI, add _on_tick integration test, finish deferred refactors#283

Merged
joryirving merged 4 commits into
mainfrom
post-281-followups
Jul 16, 2026
Merged

Gate all suites in CI, add _on_tick integration test, finish deferred refactors#283
joryirving merged 4 commits into
mainfrom
post-281-followups

Conversation

@joryirving

Copy link
Copy Markdown
Collaborator

Closes #234. Follow-ups from #282.

Summary

  • CI (both jobs) and a new just test-all loop over every tests/test_*.gd instead of four hand-listed suites — the other 15 suites are now actually gated. The TestCase base fails any run where zero assertions executed, so a suite whose preload fails to compile can't silently exit 0.
  • New tests/test_tick_integration.gd (Add full-cycle integration test for _on_tick #234): drives ColonySim.process_tick() with no scene/UI/autoloads — worker movement, gather/haul cycles, food upkeep cadence, goal rotation, dirty-flag contract, starvation build stalls, idle behavior, build completion + milestone advance. Deviation from the issue text: it's a standalone suite gated by the CI loop rather than folded into test_runner.gd, matching the post-Refactor test suite onto a shared TestCase base with a canonical assertion API #281 one-suite-per-file convention.
  • Sim is now fully autoload-free: the reservation rebuild is a static ColonySim function GameState delegates to (this was required for the integration test to compile in --script mode). do_haul flattened into _deliver_carried/_pick_up_for_build under that new coverage.
  • Popup visibility is a single MenuMode state machine; apply_anchor_layout's mirrored reparenting branches collapse onto an ordered node/parent/index table; structure/tile icons + short labels move to constants.gd; next_unlock_text walks BUILD_UNLOCKS; LayoutMath exports ALL_ANCHOR_FAMILIES and BOTTOM_DOCK_MIN_HEIGHT (save validation and main.gd stop mirroring them); main.gd uses Constants.X uniformly.
  • *.log ignored; smoke.log/smoke_ci.log untracked.

Verification

  • All 19 suites headless: exit 0, 724 passing assertions, zero script errors.
  • Full-game headless smoke boot (--fixed-fps 60 --quit-after 300): no script errors.

Notes

  • Minor intended behavior changes: closing the popup now always reapplies dock sizing (previously skipped on some close paths), and a failed load closes the popup instead of leaving it half-open.

Replaces the four hand-listed suite steps (linux + macOS jobs) with a loop
over tests/test_*.gd so new suites are gated automatically. The TestCase
base now fails a run in which zero assertions executed, so a suite whose
preloads fail to compile can't exit 0 silently.
Drives ColonySim.process_tick() directly — no scene, UI, or autoloads —
covering worker movement, gather/haul cycles, food upkeep cadence, goal
completion/rotation, the dirty-flag contract, starvation build stalls,
idle behavior, and build completion with milestone advance.

Requires the sim to be autoload-free: the reservation rebuild is now a
static ColonySim function that GameState delegates to, instead of the sim
reaching into the GameState autoload. Also flattens do_haul into
_deliver_carried/_pick_up_for_build now that the path is covered.
- Popup visibility is a single MenuMode state machine (set_menu_mode);
  the four panel flags can no longer desync across open/close paths.
- apply_anchor_layout's mirrored reparenting branches collapse onto an
  ordered (node, parent, index) table with a shared tail.
- Structure/tile icons and short labels move to constants.gd tables;
  next_unlock_text walks BUILD_UNLOCKS instead of hardcoding the chain.
- LayoutMath exports ALL_ANCHOR_FAMILIES and BOTTOM_DOCK_MIN_HEIGHT;
  save validation and main.gd consume them (removes the mirrored anchor
  list and the duplicated 460px minimum); drop dead tile_is_square.
- main.gd uses Constants.X uniformly instead of local const re-aliases.

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Automated Review

Full PR review.

Analysis engine: MiniMax-M2.7@https://litellm.jory.dev/v1 (anthropic) — escalated (fast_low_confidence)

Recommendation: Approve

This PR is well-executed and addresses its stated goals comprehensively. The new tick integration test (issue PR 234), CI test discovery loop, autoload-free refactor, and popup state machine are all high-quality additions that align with repository conventions.

Change-by-Change Findings

CI / test discovery (.github/workflows/test.yml, .justfile)

  • Replaces 4 hand-listed test steps with a for suite in tests/test_*.gd loop that automatically gates all 19 suites (excluding test_case base). This is strictly better than the previous approach — suites added later are automatically caught.
  • .justfile gains a test-all command that mirrors the CI matrix exactly, improving local validation fidelity.
  • Minor behavior change (acknowledged in PR notes): the test_runner.gd suite is now run alongside 18 others rather than as a wrapper. This is fine — the test logic is unchanged.

New integration test (tests/test_tick_integration.gd, 202 lines)

  • Instantiates ColonySim directly (no scene tree, no autoloads) and drives process_tick() programmatically.
  • Covers all required acceptance criteria: worker movement, gather/haul cycle, food upkeep cadence, goal completion/rotation, dirty flag contract, starvation stalls, idle behavior, and build completion with milestone advance.
  • Acceptance criteria deviation: The issue explicitly requires inclusion in test_runner.gd. The PR runs it as a standalone suite via the CI loop instead, citing the post-PR 281 one-suite-per-file convention. Functionally the test runs in CI (all test_*.gd except test_case are auto-discovered), so the spirit of the criterion is met. This is acceptable.

Autoload-free ColonySim (scripts/colony_sim.gd, scripts/game_state.gd)

  • rebuild_reservations_from_workers() is now a static ColonySim method. GameState delegates to it. This enables ColonySim to be instantiated in --script mode without triggering autoload initialization — a prerequisite for the integration test.
  • do_haul() is flattened into _deliver_carried() and _pick_up_for_build(), with improved inline documentation. The logic is unchanged.

Popup state machine (scripts/main.gd)

  • MenuMode enum (CLOSED, MENU, MANAGEMENT, SETTINGS) replaces scattered sidebar_scroll.visible / menu_actions.visible / management_panels.visible / settings_panel.visible flag juggling.
  • set_menu_mode() is the single mutating entry point; all open/close paths (toggle_menu, close_menu, open_build_popup, open_settings, close_settings, save_game, _load_failed, load_saved_game, begin_build_placement, queue_structure_at, cancel_build_placement, _on_dock_side_selected) delegate to it.
  • Minor behavior change (acknowledged in PR notes): closing the popup now always reapplies dock sizing (previously skipped on some paths), and _load_failed closes the popup instead of leaving it half-open. These are correct fixes.
  • _apply_header_tree() consolidates the mirrored reparenting branches in apply_anchor_layout onto an ordered [node, parent, index] table. Identical style properties for both anchors are now shared after the branch.

Constants consolidation (scripts/constants.gd, scripts/main.gd)

  • STRUCTURE_ICONS, TILE_ICONS, TILE_SHORT_LABELS added to Constants. tile_icon() and tile_amount_text() in main.gd now delegate to these tables instead of inline match statements.
  • next_unlock_text() now walks Constants.BUILD_UNLOCKS — adding a new structure tier only requires a table entry, not editing function logic.
  • main.gd preloads cleaned up: individual const extractions removed; code consistently uses Constants.X.

LayoutMath exports (scripts/layout_math.gd, scripts/game_state.gd, scripts/main.gd)

  • ALL_ANCHOR_FAMILIES and BOTTOM_DOCK_MIN_HEIGHT exported as public constants. game_state.gd's _expected_grid_sizes() now iterates LayoutMath.ALL_ANCHOR_FAMILIES instead of hardcoding ["bottom", "side"]. main.gd uses LayoutMath.BOTTOM_DOCK_MIN_HEIGHT instead of the literal 460.

Test base hardening (tests/test_case.gd)

  • Added zero-assertion guard: if test_pass == 0 and test_fail == 0, exits with code 1. This catches preload compile failures that would silently exit 0.

Standards Compliance

  • Autoload-free sim: ColonySim is a RefCounted class with no autoload dependencies, enabling standalone --script mode testing. ✅
  • Save/version migration: Reservation rebuild is a static function callable from both load path (GameState) and runtime (ColonySim.rebuild_reservations()). ✅
  • Constants over scattered literals: Icon tables, BOTTOM_DOCK_MIN_HEIGHT, ALL_ANCHOR_FAMILIES are centralized. ✅
  • Popup as overlay: The state machine keeps the sidebar transient; dock sizing is reapplied on every mode change. ✅
  • No tile_is_square stub: Removed the no-op tile_is_square function (always returned true by comment; body was "by construction"). This was dead code. ✅
  • test_case exclusion: Both CI and .justfile skip test_case (the base class), matching the expected pattern. ✅

Linked Issue Fit

Issue PR 234 — "Add full-cycle integration test for _on_tick"

Criterion Status
tests/test_tick_integration.gd exists and runs headless ✅ Added; gated by CI loop
Covers worker movement, resource gathering test_tick_advances_and_worker_moves, test_gather_and_haul_cycle
Covers food upkeep test_food_upkeep_interval
Covers goal tick test_goal_completion_and_rotation
Runs without full UI scene ✅ Instantiates ColonySim directly; no Control/autoload
Included in test_runner.gd ⚠️ Deviates — runs as standalone suite via CI auto-discovery loop instead of being folded into test_runner.gd. Functionally included (CI runs all test_*.gd except test_case), and matches post-PR 281 convention. Acceptable.

Tool Harness Findings

No tool harness output present in corpus.

CI Check Results

All CI checks passed (6/6): Export validation (Linux/macOS/Windows), Script test suite, macOS validation, Headless smoke test. Test suite exited 0 with 724 passing assertions. CI is green.

Unknowns / Needs Verification

None. All evidence is complete and consistent.

@joryirving joryirving merged commit cdaa0ad into main Jul 16, 2026
7 checks passed
@joryirving joryirving deleted the post-281-followups branch July 16, 2026 02:58
joryirving added a commit that referenced this pull request Jul 16, 2026
… regression (#284)

* Fix tile theme dictionary keys corrupted by the constants-alias sweep

The #283 alias rewrite also renamed the string KEYS inside main.gd's cached
TileRender theme dicts ('TILE_BACKDROPS' became 'Constants.TILE_BACKDROPS'),
so every tile silently fell back to default colors. Fix the keys, move the
accent palette into constants.gd (passed through TileRender's theme context,
fallbacks unchanged), add a regression test for the main→TileRender wiring,
and make CI/just test-all fail any suite whose log contains SCRIPT ERROR —
runtime script errors inside a passing suite previously went unnoticed.

* Polish sweep: close out the remaining review findings

- WorkerCapLogic.count_active_workers is the one definition of an active
  worker (HUD count + milestone progress).
- Crew list computes the colony-wide idle reason once per render;
  worker_intent_text accepts it as an optional precomputed arg.
- ColonySim caches the current milestone catalog entry between advances
  and indexes builds by id (self-verifying against state swaps).
- GoalReward magnitudes live in REWARD_MAGNITUDES next to the catalog.
- game_state.gd persistence I/O consolidated into four shared helpers
  (localStorage double-stringify and file read/write live in one place).
- Focus-mode multiplier and zoom bounds move to constants.gd; RESOURCE_TILES
  table defines resource yields/seed/drop amounts and drop messages in one
  place (gatherability derives from membership).
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.

Add full-cycle integration test for _on_tick

1 participant