Repository navigation
Split engine.rs into modules (pure move, stacked on #31) - #32
Merged
Merged
Conversation
shpwrck
force-pushed
the
claude/engine-module-split
branch
2 times, most recently
from
September 25, 2026 17:44
095a9bf to
3e0eedc
Compare
src-tauri/src/engine.rs had grown to 14.7k lines. It is now the directory module src-tauri/src/engine/, one file per concern. engine/mod.rs keeps the shared imports, WIDTH/HEIGHT/FRAME_BYTES/NATIVE_RGB_BYTES, the module list and the crate-facing re-exports, so every path the rest of the crate uses (crate::engine::GameEngine, EngineRuntime, Button, CartridgeSpec, ...) is unchanged. engine/transcript.rs and engine/bench.rs are untouched. The split was generated by a script (split_engine.py), not by hand. It moves top-level items and the tests of `mod tests` by name, fails on any item it does not know, and checks that the token multiset is preserved except for the use/mod/visibility tokens it adds and the include_bytes!/include_str! paths that gain one `../` per directory level. An independent checker agreed: no token lost apart from those 25 paths, no declared name lost, 148 #[test] functions before and after. Private items and fields that now cross a file boundary are pub(super) (pub(in crate::engine) under render/), and each file starts with `use super::*`, so name resolution is what it was. The plate cache's thread_local! stays private to framebuffer.rs, and draw_screen, which outside render/ only the test-only engine/bench.rs calls, is imported into engine/mod.rs under cfg(test). The engine's only platform-gated items are two quest-process tests (cfg(unix) and cfg(target_os = "linux")). They sit in runtime.rs next to handle_effect, which they drive, and runtime.rs's test module carries cfg(any(unix, target_os = "linux")), the one added token that is not an import or a visibility. Every other emitted import is used by code that compiles on every target, so none goes unused on Windows or macOS. The node contracts that read engine.rs now read every engine file through tests/engine-source.mjs, and the README module map points at engine/. | Module | Lines | Tests | Contents | |---|---:|---:|---| | mod.rs | 101 | 0 | imports, frame constants, module list, re-exports | | text.rs | 91 | 2 | wrap_text, text_width, truncate, title_lines | | palette.rs | 28 | 0 | Color and the named colors | | assets.rs | 115 | 1 | embedded sprite and scene-plate bytes | | framebuffer.rs | 492 | 2 | UiBox, Framebuffer drawing primitives, the plate cache | | cartridge.rs | 123 | 1 | CartridgeSpec, QuizQuestion, QuestSpec, loader types | | progress.rs | 160 | 1 | thresholds, InsightStage, PresentationTier, streak scoring | | oracle.rs | 351 | 4 | datafall drops, oracle line, recall, failure reasons | | lesson.rs | 446 | 2 | lesson card layout and copy | | state.rs | 1033 | 11 | Screen, OpeningBeat, GameState and its core impl | | codex.rs | 165 | 2 | GameState's journal, mastery and Codex page methods | | quiz.rs | 1510 | 25 | QuizRun, RunLedger, retry scheduling, answer commit | | deck.rs | 828 | 16 | question batches, prefetch, rebatching | | commands.rs | 595 | 11 | EngineCommand, EngineEffect, apply_commands | | input.rs | 562 | 8 | Button, handle_press, hero setup controls | | advance.rs | 472 | 9 | advance_game, the per-tick step | | audio_snapshot.rs | 474 | 9 | audio_snapshot, direct_audio | | quest_process.rs | 125 | 0 | quest shell process and polling | | runtime.rs | 365 | 2 | GameEngine, EngineRuntime, handle_effect and its quest tests | | render/mod.rs | 784 | 2 | render system and draw_screen dispatch | | render/widgets.rs | 196 | 1 | runes, meters, wards, focus frames | | render/sprites.rs | 265 | 1 | hero, crab, boss, sigils, drops | | render/opening.rs | 435 | 4 | boot, chronicle, awakening, title, fanfare | | render/menu.rs | 213 | 2 | quiz menu, gateway menu | | render/atelier.rs | 230 | 2 | character creation | | render/datafall.rs | 788 | 7 | Oracle sanctum and datafall HUD | | render/trial.rs | 792 | 6 | quiz trial screen and feedback banners | | render/ascension.rs | 340 | 3 | level-up screen | | render/aftermath.rs | 576 | 4 | game over and debrief rows | | render/codex.rs | 1497 | 10 | Codex lens, lesson and self-test pages | | render/quest.rs | 65 | 0 | quest select, battle, result | | test_support.rs | 891 | 0 | shared test fixtures and drivers (cfg(test)) | Verified on the WSL mirror: cargo fmt --check, clippy --all-targets -D warnings, cargo test (411 lib tests listed before and after with identical leaf names; 400 passed, 11 ignored, as on the unsplit tree), npm test, and both CODEQUEST.toml validations all pass. No behavior change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guide's module map, its note on line numbers, and its list of where the Rust tests live still named engine.rs. They now name engine/ and the files that own each part. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shpwrck
force-pushed
the
claude/engine-module-split
branch
from
September 25, 2026 19:31
3e0eedc to
8e66049
Compare
shpwrck
changed the base branch from
claude/codequest-opus-improvements-0069d2
to
main
September 25, 2026 19:31
shpwrck
marked this pull request as ready for review
September 25, 2026 19:51
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.
Stacked on #31. Merge this after #31 lands; its base is #31's branch (
claude/codequest-opus-improvements-0069d2at 9a3bd58, which includes the review-3 fixes).What this does
src-tauri/src/engine.rs(14,714 lines) becomes the directory modulesrc-tauri/src/engine/, one file per concern. This is a pure move with no behavior change:mod/uselines, visibility qualifiers, and onecfgattribute onruntime.rs's test module (see Platform-gated tests). Private items and fields that now cross a file boundary becomepub(super), orpub(in crate::engine)underrender/. Each file starts withuse super::*.include_bytes!/include_str!paths, which gain one../per directory level.engine/mod.rsre-exports everything the rest of the crate uses (GameEngine,EngineRuntime,Button,CartridgeSpec,QuizQuestion, ...), so nocrate::engine::path outside the engine changes.engine/transcript.rsandengine/bench.rsare byte-identical.engine.rsnow read all the engine files through the newtests/engine-source.mjs(the production-only check still stops each file at its#[cfg(test)] mod tests).docs/architecture.md, now point atengine/.Module table
mod.rstext.rswrap_text,text_width,truncate,title_linespalette.rsColorand the named colorsassets.rsframebuffer.rsUiBox,Framebufferdrawing primitives, the plate cachecartridge.rsCartridgeSpec,QuizQuestion,QuestSpec, loader typesprogress.rsInsightStage,PresentationTier, streak scoringoracle.rslesson.rsstate.rsScreen,OpeningBeat,GameStateand its core implcodex.rsGameState's journal, mastery and Codex page methodsquiz.rsQuizRun,RunLedger, retry scheduling, answer commitdeck.rscommands.rsEngineCommand,EngineEffect,apply_commandsinput.rsButton,handle_press, hero setup controlsadvance.rsadvance_game, the per-tick stepaudio_snapshot.rsaudio_snapshot,direct_audioquest_process.rsruntime.rsGameEngine,EngineRuntime(Bevy app),handle_effectand its quest-process testsrender/mod.rsrendersystem and thedraw_screendispatchrender/widgets.rsrender/sprites.rsrender/opening.rsrender/menu.rsrender/atelier.rsrender/datafall.rsrender/trial.rsrender/ascension.rsrender/aftermath.rsrender/codex.rsrender/quest.rstest_support.rscfg(test))transcript.rsbench.rscfg(test))How it was made and verified
The split was generated by a deterministic script, not written by hand. The script moves top-level items, inherent-impl methods, and the
#[test]functions ofmod testsby name from explicit placement lists. It fails on a listed name that is missing, and on any item it does not know. It was first proven on 320ed4e, re-run on ea032da, and has now been re-run on 9a3bd58. None of the output was edited by hand. The script is not committed: once this merges,engine.rsno longer exists, so there is nothing left for it to re-run on.For 9a3bd58, the placement lists gained the items the later merges added: 3 constants, the 6 plate-cache items and
draw_screenfrom the engine-performance stream, and 20 tests. The two quest-process tests also moved fromquest_process.rstoruntime.rs(see below). The script's logic needed four small changes:thread_local! { ... }) as one item that ends at its closing brace. Before this change it classified the item by thestaticinside and read past the brace.transcript.rs. The newengine/bench.rsis declared#[cfg(test)], so everything it uses counts as test use.render/mod.rs's own items are imported intoengine/mod.rsby name only where something outsiderender/uses them: plainly for production use, and under#[cfg(test)]for test-only use. That applies todraw_screen, which outsiderender/onlybench.rscalls.#[cfg(..)]gets the union of those predicates on the module itself.With the ea032da placement lists, the changed script writes the same output on ea032da as before, except for one line: the
#[cfg(unix)]that the last change adds toquest_process.rs's test module. So the ea032da split had the same Windows problem.cargo fmt: no token was lost apart from the 25 include paths, which reappear with one more../.#[test]functions before and 148 after.cargo test --lib -- --listlists 411 tests before and after, with identical leaf names (only the module paths change). The results are 400 passed and 11 ignored, the same as the unsplit tree at 9a3bd58.rustfmtof a fresh run matches the committed files.cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test,npm test(node contracts), and theCODEQUEST.tomlvalidator for both manifests all pass.Platform-gated tests
The previous head of this PR failed
Rust on windows-latestwith two unused imports:use super::*;inquest_process.rs's test module, and#[cfg(test)] use self::runtime::*;inengine/mod.rs. Both were used only by the two quest-process tests, and Windows compiles both tests out.The engine's only platform-gated items are those two tests:
aborting_a_quest_stops_its_whole_process_tree_and_frees_the_slot(#[cfg(unix)]) anda_surviving_quest_helper_forwards_nothing_after_the_quest_is_done(#[cfg(target_os = "linux")]). I checked this by searchingengine.rsat 9a3bd58,bench.rs, andtranscript.rsfor everycfg(,cfg_attr(andcfg!(. The only other hit is acfg!(debug_assertions)expression inbench.rs, which compiles on every target.Both tests call
handle_effectdirectly, so they now live inruntime.rsnext to it. That module's test module is#[cfg(test)] #[cfg(any(unix, target_os = "linux"))]. With the tests there, no other module needsruntime's private names, soengine/mod.rshas nouse self::runtime::*;.Every import the script emits, checked against the platform gates:
use self::<module>::*;), the explicituse self::render::render;, and each module's file-leveluse super::*;are all production imports. No engine production code is platform-gated, so each one is used on every target. No module has a test-only file-leveluse super::*;.#[cfg(test)] use self::render::draw_screen;and#[cfg(test)] use self::test_support::*;.bench.rsusesdraw_screenin ungated code, and every module's tests usetest_support.use super::*;is used by at least one ungated test in that module. The exception isruntime.rs, whose test module is compiled only where one of its tests is.I can't compile for Windows locally, so I simulated the Windows and macOS builds on Linux. In a scratch export of 9a3bd58, I turned the gated tests off with
#[cfg(any())]before splitting: both tests for Windows, and only the Linux one for macOS. I then ran the script andcargo clippy --all-targets -- -D warnings. Both simulations pass.Review tips
The move commit deletes one file, adds 33 (32 engine files and
tests/engine-source.mjs), and edits four (README and three node contracts). To check a module, open it next to the same items inengine.rsat 9a3bd58. Only visibility and imports should differ, plus the onecfgattribute onruntime.rs's test module. The native Windows/macOS jobs (verify-native) are the check to watch on this PR.🤖 Generated with Claude Code