Local testing for Epok maintainers
START WITH THE BIG PICTURE
What does this part of Epok do?
Epok tests pure editor logic, native runtime kernels, full build pipelines and visual output at different layers. Choose the smallest check that proves your change, then expand for risky paths.
- 01Run focused unit/runtime tests
- 02Run affected integration checks
- 03Compare visual or performance artifacts
What is happening under the hood?
- Rust tests include real ImGui interaction harnesses.
- C++ host tests exercise bounded runtime structures without an emulator.
- Python checks drive tools, MIPS builds, PCSX-Redux and reproducible captures.
Field note: A passing unrelated test is comforting, but it is not evidence. Pick the check that touches the behavior you changed.
Use debug builds for local development and iteration: cargo build --locked --bins.
Development desktop shortcuts must point to target/debug/epok-editor.exe on
Windows (or target/debug/epok-editor on other hosts). Build release only when
explicitly requested for release validation or distribution.
The reusable timeline component library has a dedicated acceptance command:
python tests/integration/verify_timeline_adapters.py. It installs project-owned
adapter source, uses the real Clang extractor and native/Blueprint ancestry,
rejects required missing components, cooks two scene sequences and inspects
actual component values at event time and after restoration in PCSX-Redux.
It also rebuilds the standalone export byte-identically. The retained fixture
and linked section sizes are reported in
artifacts/timelines/phase2-component-adapters.json. This validates component
state, not audible output, pixel parity or physical-console frame rate.
The normal Blueprint runtime harness additionally runs
test_timeline_adapters.cpp against real PsyQo headers and compiles the library
with the pinned MIPS compiler.
The Blueprint feature integration also includes BP_AudioOverrides, derived from
its existing resource-bearing Blueprint. It checks that inherited numeric-default
edits preserve both normal/debug audio banks after source observation and full
staging; inherited AudioClip overrides must invalidate and stage the newly
selected payload while leaving the other destination stale. Restoring source
must rebuild both destinations to their original executable bytes.
The fixture also edits a native numeric default, a scene script value and a
template script value before full MIPS staging; both audio banks must remain
unchanged. Focused Rust tests cover script member IDs/override bookkeeping,
missing-class identity, native metadata failure/repair and independent banks.
Run checks from the repository root. Full validation is performed locally; GitHub Actions enforces the release branch and version policy.
make check runs the editor checks below sequentially and stops on the first failure. Both make check and make test build the companion reflection extractor before running tests. On Windows after setup, use .\.tools\mips\bin\make.exe check if Make is not on PATH. The root Makefile also exposes test, lint, fmt-check, build and release individually; native emulator checks remain separate.
Editor checks
Rustup selects the pinned toolchain. These checks do not launch the emulator:
cargo fmt --all -- --check
cargo build --locked --bin epok-header-tool
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
cargo build --locked
Tests that create Actor projects or stage native classes execute the companion
epok-header-tool binary. cargo test builds that binary's test harness, not
the standalone extractor. Run the explicit build above in a fresh checkout;
the PR and release workflows perform the same prerequisite before testing.
Unit tests cover scene hierarchy, transforms, export generation, lighting, HUD, picking, transport decoding, asset recovery/import transactions, WAV/MP3/ADPCM quality and XA sector spacing and Dear ImGui interaction without a desktop window. Tests requiring a graphics adapter or real emulator are explicitly ignored by the default run.
Dependency checks include PATH discovery, missing SDK files, configuration persistence,
backup preservation, and real ImGui warning/settings interactions. On Windows,
python tests/integration/verify_dependency_setup.py runs offline installer checks
with temporary archives: selected-package isolation, companion-file repair,
checksum rejection, and archive path containment. Capture the settings page with
--project <folder> --screenshot-dependencies --screenshot <file.png>.
Changing the reflected surface of a runtime header (runtime/object_model.hpp in
particular) also changes the generated API reference. Regenerate it with
python3 tools/generate-api-reference.py on a host that has the libclang Python
bindings installed, and commit the regenerated docs/api/ output; the committed
files record declaration line numbers, so even a pure insertion above an existing
member makes --check fail until they are regenerated. Never hand-edit them.
After SDK setup, python tools/extract_hud_font.py --check verifies that the committed editor HUD font matches the pinned PsyQo font. Omit --check to regenerate the bitmap when intentionally updating that resource.
MCP integration
After cargo build --locked, run python tests/integration/mcp.py to launch an isolated editor project and exercise HTTP/stdio negotiation, scene edits, Undo/Redo, camera changes, real Scene/HUD/editor screenshots and audio import. Add --emulator to compile and run the sample in PCSX-Redux, send controller input, Pause/Step, capture Game and Stop. --editor <path> selects an alternate binary, including a release build. These checks need a desktop GPU; the emulator option also requires SDK setup. Preferences and captures stay in the test's .epok/mcp-integration-*/ directory, leaving the user's MCP preference unchanged.
Unit tests also cover disabled defaults, key migration, port conflicts, Host/Origin/authentication rejection, listener shutdown, stale edits, atomic batch failure, file backups and cancelled/expired queued requests. --screenshot-mcp-settings opens the AI / MCP preference page for visual checks.
Native PSX checks
python tests/integration/verify_memory.py builds an isolated project using the
saved serial Play profile without opening a serial port or emulator. It checks
current-scene versus whole-game MIPS outputs, shared texture deduplication, BSS
accounting, SPU residency, exclusion of stale cached payloads and unchanged-build
repeatability. Reports and real editor captures of the analyzer and Play menu are
kept under artifacts/memory/<timestamp>. --screenshot-memory opens an existing
report for visual QA; --screenshot-play-menu opens the toolbar menu.
Default tests also verify treemap area/containment, malformed ELF rejection, symbol alias accounting, complete/fragmented NOTPSXSerial progress records, and the compact modal's size, continued workspace rendering and keyboard/MCP lock.
python tests/runtime/verify_frame_clear.py checks the real PsyQo clear packets
for all ten video modes and both buffer parities. Interlaced rendering clears
with a rectangle at (0,0) and preserves the displayed field; progressive
rendering retains the alternating 240-line buffers. This checks packet contents
and VRAM bounds; field timing still needs testing on physical hardware.
On 2026-09-11, the user tested the isolated Ironwood title through Unirom serial
on a Japanese SCPH-7500 with composite AV into an HDMI converter. The 640 x 480i
build still flickered and turned white after the field-clear fix. The adapted
320 x 240p build (ironwood_menu_240p.exe, SHA-256
7712b6649358ef76c13fec659157974e256c9c4f1257ab9df1ed741ead769da1)
was reported stable, with cropping at the top and bottom. This is evidence for
that title and output chain, not acceptance of all video modes or proof that
the converter caused the interlaced failure. The next comparison moves the
diagnostic counter and help text inside 16-pixel vertical margins while keeping
the same 320 x 240p GPU setup. These isolated title tests omit XA music and other
scene banks. Emulator captures alone do not validate analog output timing.
Safe native iteration is exercised with a real editor state and its existing build/Play worker (no GPU window is needed):
cargo test --locked native_source_edit_restarts_real_play -- --ignored --nocapture --test-threads=1
This creates a separate sample project, edits C++ during Play, verifies a new
emulator process and executable, introduces a compiler error, repairs it, and
checks recovery and Stop. It also edits the in-memory scene during Play, verifies a new process/executable
without changing the saved scene, and checks that the lighting bake does not
cause another restart. It then adds a real external C++ include, changes its
contents while preserving its modification time, checks a changed executable
and new emulator process, deletes the include, and repairs it to verify recovery.
It requires the pinned MIPS tools and PCSX-Redux and
must run alone on port 8077. Retain its printed fixture path for diagnosis.
Default unit tests cover stale graph propagation, unrelated timeline cache
preservation, source removal, reflected-member removal, cache provenance
migration/relocation, invalid-source debounce and deferred unsaved-effect builds.
Staging tests additionally cover reflected-member changes reaching generated
headers, independent rebuild/export destinations, failed and removed outputs,
and conflicting dependency snapshots within one generation batch. The
audio-bank regression uses real imported ADPCM and typed event resource cooking:
it checks first/last clip selection, timing/curve isolation, duplicate resource
references, malformed/ambiguous source observation, repair and independent export
certificates. The combat fixture checks that the actual bank header depends on
the embedded timeline's audio selection instead of its complete playback output.
Blueprint audio regressions compile real graphs and resource banks, covering
scalar-logic isolation, inline/literal-node references, first/last clip changes,
template-only audio, malformed sources and independent output certificates.
verify_blueprint_features.py also edits graph logic and adds a clip through the
CLI, checks bank staleness before staging, and requires byte-identical normal and
debug executables after restoring the source and rebuilding both destinations.
Build-ticket regressions use actual generated Blueprint artifacts and disk edits
at the before/after-compilation boundary, without an editor watcher. They cover
layout-only changes, changed defaults, additions (including the first Blueprint),
removals, unreadable sources, independent export recovery and mixed scene/compiler
membership snapshots. Older staging manifests without class-set provenance are
rejected until regenerated. The feature integration verifies the captured class
set and the source-manifest dependency in both normal/debug MIPS destinations.
The effect source integration verifies stale signatures after an invalid instance override;
the combat integration checks generated effect provenance in both destinations
against the actual written header bytes. On Windows it launches PCSX-Redux's
installed .main directly, so timeout cleanup owns the emulator process.
Scene provenance tests exercise saved versus unsaved inputs, independent exports,
registered-map edit/deletion/parse failure/recovery, document switching and
lighting-cache updates. Combat acceptance verifies the actual generated scene
header hashes and root/additional-map dependencies in both build and export.
Native application input certification has a separate real Make/GCC regression:
cargo test --locked native_make_inputs_detect_timestamp_preserving_edits_and_new_include_resolution -- --ignored --nocapture --test-threads=1
It builds an owned project with spaces in its path and an external header with a
space and # in its name. It verifies target-specific -O2 dependency selection,
unchanged-build reuse, byte-different MIPS output after a timestamp-preserving
header edit, and rejection/recovery when __has_include starts selecting a newly
created file during compilation. Compiler reports must include the SDK archive,
libgcc and linker script. The fixture is retained and does not launch an emulator.
The combat integration checks these actual compiler inputs, including its cooked
effect header, alongside the executable certificate and standalone rebuild.
SDK archive construction has a separate isolated real-tool check:
cargo test --locked sdk_archive_tracks_real_assembly_inputs_source_membership_and_failed_rebuilds -- --ignored --nocapture --test-threads=1
It creates a miniature SDK using the pinned Make rules and real GCC/assembler/ar.
It checks C/C++ and assembly includes, .incbin, preserved-timestamp edits,
unchanged archive reuse, removed archive members, failed-build retention and
recovery, mid-build mutation, new include selection after capture and nonblocking
lock ownership. Pre-existing shared SDK objects and an archive must retain their
exact bytes. All authored mutations remain inside the retained fixture.
Combat and Blueprint feature integration additionally inspect the real SDK
certificate and each build destination's private archive dependency. Standalone
rebuilds use fresh private SDK objects through the exported launchers.
python tests/integration/verify_particle_effect_load.py measures one effect,
eight effects with 64 emitters and 256 particles, deliberate effect/burst/emitter
overflow, and cleanup in a scene containing twelve meshes, textured characters
and HUD. It checks actual MIPS output, an identical standalone rebuild and two
serialized PCSX runs. The retained fixture and artifacts/timelines/phase5-vfx-load.json
contain completed native frame samples, code/data/BSS sizes and pool sizes.
Capacity assertions are correctness checks; measured frame costs and dropped
steps determine the tested workload's performance. Keep the SDK and emulator
free of other native validation runs while executing it.
Blueprint foundation checks after cargo build --locked --bins and SDK setup:
cargo test --locked blueprint_creation_dialog_reflects_inherits_attaches_and_undoes -- --ignored --nocapture
python tests/integration/verify_reflection.py --emulator
python tests/integration/verify_projects.py
python tests/integration/verify_project_registration.py
The ImGui test creates/attaches inherited native classes through production controls using real Clang. Reflection acceptance rebuilds a standalone export and checks inherited behavior, independent properties and scene-bank resets in emulator RAM; do not run it alongside another Play session on 8077. --keep retains its isolated temporary project for diagnosis. Registration tests use a unique HKCU test subtree and do not alter live file associations. Capture the real dialog with --screenshot-script-dialog --screenshot <path>; live Windows click-through and double-click launch still need an unlocked desktop.
For runtime features, run the host C++ suites and emulator acceptance checks:
python tests/runtime/verify_spatial.py
python tests/runtime/verify_sprites_particles.py
python tests/runtime/test_compare_runtime.py
python tests/runtime/test_stream_pool_layout.py
python tests/integration/verify_rpg.py
python tests/integration/verify_streaming.py
python tests/integration/verify_streaming_xa.py
The two host runners cover input, time, collision, transform caching, lifecycle, Memory Card recovery, utility services, palettes, frustum/polygon processing and sprite/particle pools. They require a C++20 compiler and the pinned Nugget sources. Streaming checks use isolated projects on ports 8092 and 8093 and require the configured CD authoring tools. For diagnostic assertions, benchmark methodology and regression gates, see the internal performance validation workflow. All native acceptance checks require a built editor, configured MIPS tools and PCSX-Redux; run them sequentially. The RPG check covers sprite depth/blending, camera projection, resource counters, palette animation, scene transitions, object handles, particle capacity/expiry and input/timing behavior. Feature limits are documented under Sprites and particles, Cameras and resources, Runtime services and Input and collision.
Run dependency setup first. Integration scripts use Python 3.10 or newer and its standard library; no Python packages are required. The scripts default to target/debug/epok-editor.exe. Close a running editor before rebuilding that executable.
cargo run --locked -- --project examples/sample-game --build-psx
python tests/integration/verify_projects.py
python tests/integration/verify_audio_assets.py
python tests/integration/verify_bgm.py
python tests/integration/verify_pipeline.py
python tests/integration/verify_hierarchy.py
python tests/integration/verify_hud.py
python tests/integration/verify_display.py
python tests/integration/verify_lighting.py
python tests/integration/verify_blockout.py
cargo test --locked live_video_input_pause_step_and_cleanup -- --ignored --nocapture
Run these sequentially, with no other Play session using port 8077.
| Check | Evidence |
|---|---|
| Projects | External folders with spaces, creation, version rejection, overwrite protection, relocation, startup scene, cache regeneration and basic/sample builds |
| Audio/assets | Closed-project moves, source/cache loss, UUID conflicts, snapshot reimport, actual SPU decoded samples, loops, stop/play, volume/pitch and 24-voice priority |
| Pipeline | PS-X EXE output, incremental script objects, C++ failure/recovery, animation, pause/resume and cleanup |
| Hierarchy | VRAM comparison of nested and equivalent world transforms, parented cameras and animated parents |
| HUD | Pixel equality for authored and C++-created HUDs; runtime component updates |
| Display | All ten native output modes, default 640 x 480, projection aspect, HUD corners/font and emulator filtering |
| Lighting | Baked/GTE agreement, normals, light budgets, range, shadows, native creation and saved bake caches |
| Blockout | Mesh UUID relocation/conflicts, material slots and instance overrides, window openings, chunk rejection, near-plane clipping, backface rejection and sloped baked/GTE normal agreement measured from native VRAM/RAM |
| Live bridge | Changing video, controller press/release, stable pause, one-VBlank step and process cleanup |
Hierarchy, HUD and lighting accept --exe <path> for an alternate editor build. Verification creates isolated temporary game projects under .epok/; the pipeline check also builds the sample project. Reports, screenshots and memory captures go to ignored artifacts/.
Blueprint acceptance
Build both editor and reflection extractor with cargo build --locked --bins.
The ordinary Rust suite covers schema/IR/compiler, stable identities, linked
templates, typed references, editing transactions, and debug protocol validation.
Additional target and native UI checks are:
python tests/runtime/verify_blueprint_runtime.py
python tests/runtime/verify_blueprint_bridge.py
cargo test graph_canvas_creates_connects_drags_and_undoes_using_imgui_events -- --ignored --nocapture
python tests/integration/verify_blueprints.py --keep --emulator
python tests/integration/verify_blueprint_features.py --keep --emulator
python tests/integration/verify_blueprint_performance.py --keep --emulator
Serialize emulator tests. The runtime harness runs host contract assertions and
compiles actual pinned MIPS/PsyQo/EASTL headers; the Lua protocol harness mocks
emulator services and is not a real-breakpoint acceptance substitute.
For that acceptance, set EPOK_BP_DEBUG_PROJECT to the retained inheritance
fixture's relocated project, then run
cargo test live_blueprint_breakpoint_snapshot_step_resume_and_cleanup -- --ignored --nocapture.
The performance fixture compares equivalent arithmetic at 1/16/64 instances
under common -Os optimization, verifies native RAM results, and reports linked
sections, the measured function's prologue frame, and guest interpreter cycles.
It does not measure peak stack/RAM, hardware timing, or FPS. Native/debug builds
are kept separate. See docs/blueprints.md for reproducible example generation
and design-qa.md for actual desktop evidence.
Lua scripting acceptance
The default cargo test --locked run covers the Lua authoring provider on the
host: declaration extraction and identity rules (lua_asset), the epok-lua v1
profile, type inference and every rejection diagnostic (lua_frontend), the
shared typed IR (script_ir), ordering/registry publication/backend dispatch
(lua_compile), generated C++ and VM bindings (lua_aot), normalized chunk
emission and packaging (lua_vm), the host bytecode cooker (lua_bytecode) and
mode-scoped generation footprints (lua_dependencies).
The cooker tests skip themselves when Nugget's nested third_party/psxlua
submodule is absent — lua_bytecode::available() is false and build.rs does
not set epok_luac. Run the repository setup first if they should really run.
The editor authoring round trip is #[ignore]d because it needs the pinned
libclang, the MIPS SDK and a built epok-header-tool. Build both binaries with
cargo build --locked --bins, then:
cargo test --locked lua_creation_dialog_creates_attaches_and_reports_rejections -- --ignored --nocapture
cargo test --locked lua_creation_dialog_lists_lua_parents_and_respects_the_component_context -- --ignored --nocapture
Target checks
Three Python drivers. All three need the MIPS toolchain
(mipsel-none-elf-gcc/g++/size/nm/ar on PATH), the pinned
third_party/nugget submodule including its nested third_party/psxlua,
and PCSX-Redux plus openbios.bin under .tools/. They also import
tools/epok_documents.py, so the host needs PyYAML from
tools/requirements.txt:
python3 -m pip install -r tools/requirements.txt
| Driver | What it proves | Report |
|---|---|---|
tests/integration/verify_lua_modes.py |
Cross-mode acceptance: 21 checks | artifacts/lua_modes/report.json |
tests/integration/verify_lua_vm_abi.py |
Host-cooked bytecode == on-target luaU_dump |
--output (no default) |
tests/integration/verify_lua_feasibility.py |
Technology benchmark behind the design choice | --output (no default) |
tests/integration/verify_lua_editor_tooling.py |
The generated definitions are enforced: a correct class reports nothing and a broken one reports the same three errors the compiler rejects | artifacts/lua_editor_tooling/report.json |
python3 tests/integration/verify_lua_modes.py
python3 tests/integration/verify_lua_vm_abi.py --output report.json
python3 tests/integration/verify_lua_feasibility.py --emulator --output report.json
python3 tests/integration/verify_lua_editor_tooling.py
verify_lua_editor_tooling.py needs no emulator, but it does need
lua-language-server on PATH (brew install lua-language-server); without it
the script skips with that message instead of failing. It creates one project
through the production CLI, writes one Lua class, builds it once with
--build-psx so the catalog refresh rewrites .epok/lua/epok.d.lua and
.luarc.json, and then proves both halves of the editor claim: the correct
class reports nothing at --checklevel=Error, and a copy with a Bool
written to a Fixed field, a string passed to a Fixed parameter and a read of
an undeclared member reports exactly those three errors on those three
lines — the same three lines the Epok compiler then rejects with its own
diagnostics. The generated .luarc.json is what makes the first half bite: it
raises assign-type-mismatch, param-type-mismatch and undefined-field to
Error!, which LuaLS otherwise reports only as warnings. A class body is
checked only if its local is bound to the generated declaration, which the
---@class <Class> : <Parent> line of the declaration form already does.
verify_lua_modes.py is the cross-mode acceptance script and the slowest of
the three: it creates one real project through the production CLI, builds the
same .lua sources in native_cpp, vm_bytecode and vm_source
(--build-psx), runs each under PCSX-Redux, and reads a 72-slot probe array out
of guest RAM. The probe values must be identical across the three modes and
equal to constants the script derives by reimplementing the numeric contract in
Python — it never compares a run against a previous run. It records 21
checks into artifacts/lua_modes/report.json (override with --output),
along with per-mode ELF sections, epok.ps-exe hashes, arena peaks and tick
cycles. --no-emulator builds every mode but skips the on-target run,
--skip-export drops the standalone make checks, and --keep retains the
generated project for inspection. It pins EPOK_RUNTIME_OPT=-Os itself so the
three modes' sizes compare like for like. Budget well over ten minutes.
verify_lua_vm_abi.py compares the host-cooked bytecode with an on-target
luaU_dump of the same chunk byte for byte, checks the 18-byte header both
sides accept, and runs the VM runtime's numeric/dispatch conformance probes in
both VM modes. --no-emulator builds without running, and --build-dir,
--output and --timeout behave as in the other integration drivers.
verify_lua_feasibility.py is the isolated PsyQo benchmark harness that
compares a native AOT reference against the PsyQo Lua VM variants. It links no
Epok engine code; tests/integration/lua_feasibility/README.md documents its
four variants, seven workloads, correctness gate and — importantly — exactly
what its numbers do and do not mean. Without --emulator it builds and reports
linked sizes only. It copies the pinned Nugget tree into its build directory, so
it never writes into the repository.
Two acceptance properties are not covered by these drivers and live in
cargo test instead: a Blueprint child of a Lua class
(lua_compile::lua_classes_are_blueprint_parents_but_blueprint_classes_are_not_lua_parents,
because the CLI --new-blueprint resolves parents from the reflected C++
registry only) and corrupt-bytecode rejection
(lua_bytecode::lua_bytecode_rejects_a_payload_whose_header_byte_drifted).
Serialize all three with the other emulator checks. None of these ran on
physical PlayStation hardware; emulator results are for reproducible development
comparison only. The recorded results of the acceptance run are in
knowledge/initiatives/lua-scripting/validation-2026-09-14.md.
Screenshots and profiling
TimelineAsset checks (after building both editor/extractor binaries):
rtk cargo test --locked timeline
rtk cargo test --locked timeline_controls_add_undo_redo_validate_and_save -- --ignored --nocapture
rtk proxy python tests/runtime/verify_blueprint_runtime.py
rtk proxy python tests/integration/verify_timeline_assets.py
rtk proxy python tests/integration/verify_timeline_prototype.py --emulator
rtk proxy python tests/integration/verify_timeline_director.py --emulator
rtk cargo test --locked particle_effect
rtk cargo test --locked effect_controls -- --ignored --test-threads=1
rtk proxy python tests/integration/verify_particle_effect_assets.py
rtk proxy python tests/integration/verify_particle_effect_runtime.py --emulator
rtk proxy python tests/integration/verify_blueprint_playback.py
rtk proxy python tests/integration/verify_blueprint_playback.py --direct-assets
rtk proxy python tests/integration/verify_blueprint_playback.py --subscribe-markers
rtk proxy python tests/integration/verify_timeline_combat.py
The runtime runner includes cooked Q12 curve/marker tests. The asset integration
uses real extraction, rename/permission invalidation, explicit stale retention,
deterministic table timestamps, duplicate IDs, and MIPS syntax checking. The
Phase 0 fixture independently rebuilds both standalone exports and compares
Rust host, cooked MIPS, and handwritten MIPS samples and marker counts. It
measures guest cycles and linked sections under common -Os; it is not a
runtime director, effect-pool, or hardware acceptance test. Reports stay under
ignored artifacts/timelines/. Run emulator checks sequentially.
The director fixture cooks a gate/camera sequence with native and Blueprint targets and a particle burst. It rebuilds an identical standalone export and checks event-time values, restoration, inactive-owner freezing, dynamic template components, destroyed/reused targets, owner cancellation, and scene replacement in PCSX-Redux RAM. Its report includes linked sections and bounded pool sizes; completed-frame simulation scanlines include other systems and are not isolated director CPU timing or physical-console performance.
The effect-source check uses the shared Clang catalog and embedded timeline
compiler, verifies typed layer property/event identity, scene effect cooking,
MIPS adapter syntax, stable semantic hashes and unchanged particle limits.
The runtime fixture adds immutable sprite/emitter layers, stable reorder/seed
assignment, a full MIPS build and an identical standalone rebuild. Its optional
PCSX probe checks the production tick path, transient saturation, no entity
allocation, local pause, exactly-once burst/marker delivery and bounded drain.
The report is artifacts/timelines/phase3-runtime.json. These checks do not
constitute Phase 3 fireball/editor or Blueprint bridge acceptance.
The playback bridge fixture uses generated combat graphs with typed component
Play and marker/completion waits. It asserts one damage application at Impact,
stop cancellation, inactivity, owner destruction, graph reentry and scene
replacement on PCSX-Redux, then verifies a byte-identical standalone rebuild.
artifacts/timelines/phase4-bridge.json records MIPS sizes, continuation/frame
storage and completed-frame simulation scanlines. --direct-assets removes all
scene playback components and checks typed required/optional UUID binding pins,
asset-only reachability and independent export rebuilding. --subscribe-markers
checks repeated Impact delivery, a latent reached branch, stop cancellation and
the unchanged eight-slot continuation table. Their evidence is recorded in
phase4-direct-assets.json and phase4-subscriptions.json.
The authored combat fixture copies examples/timeline-spell, then instruments
its real BP_Fireball graph. It verifies captured target identity, one 25-point
Impact hit, completion after particle drain, cancellation before another Impact,
owner destruction, scene replacement and an identical standalone export. It
captures the game HUD and effects for visual inspection; phase4-combat.json
records the fixture, counters and MIPS section sizes. The older Fireball visual
fixture explicitly selects the retained presentation scene (Main.epokmap),
since the example now starts in Combat.epokmap.
The combat check also verifies actual scene, script and executable hashes in the
artifact dependency graph, plus the separate build/export stage manifests. The
staging_files unit tests exercise native-body invalidation, retained stale
exports, unchanged writes, abandoned output files, tampered staged inputs and a
build ticket superseded by changed compiler options. The explicit native Play
restart test additionally checks compiler-error recovery and an unsaved scene
edit without rewriting the saved document.
The certification_rechecks tests use production scene/resource staging and
build tickets without an editor watcher. They cover saved versus unsaved inputs,
registered scene edits and parse failures, map membership, rendering settings,
import settings, equal-length package checksum corruption, duplicate/missing
packages, independent exports and recovery only after restaging. Unimported raw
source edits and unrelated corrupt packages must not reject an independent build.
The explicit linked_refresh_precedes test also exercises Play's prepared-scene
staging entry point: inherited obsolete texture/audio references are removed by
the existing template refresh, while source/audio provenance still matches the
submitted saved scene and the resulting build ticket can be certified.
legacy_metadata_changes stages through the production catalog and covers
.epokscript edits, membership changes, unreadable files, mixed reads in one
capture, old staging without metadata coverage and independent export recovery.
Run rtk cargo test --locked reflection_capture_rechecks -- --ignored --test-threads=1
with the pinned SDK/extractor available. That fixture uses a real external include
and checks extraction/cache-hit provenance, include mutation and removal, captured
tool inputs, SDK selection changes and regeneration after repair. It edits only
its own fixture; it does not modify installed tools or the SDK.
For the dependency viewer, run the isolated interaction check:
rtk cargo test --locked dependency_navigation_uses_real_clicks -- --ignored --test-threads=1
It uses actual ImGui clicks to navigate a missing input and a transitive consumer,
then checks a corrupt graph read preserves only a labeled diagnostic snapshot
and never writes to the graph. The ordinary unit suite checks shortest consumer
paths through cycles and missing nodes. Capture a built fixture with
--screenshot-artifact-dependencies --screenshot artifacts/timelines/dependencies.png;
inspect both columns, full-ID tooltips and stale/error text. The panel is opened
normally through Window > Artifact Dependencies.
The Blueprint compiler regression selected_class_references_invalidate covers
ClassRef defaults, inline literals and literal nodes through actual compilation,
dependency observation, reparenting rejection and repair; unrelated Blueprints
retain their records. The Blueprint feature integration also checks separate
release/debug executable hashes and stage manifests, including the patched
debugger sources.mk signature and its compiler-option dependency.
It also verifies actual audio payload/display header hashes and their precise
provider inputs. The unit test staged_audio_payloads_follow uses full project
staging, two imported clips, native/scene edits, snapshot reimport, a superseded
asset index, missing clips and removal from the stage manifest. It verifies old
exports stay stale and saved scene bytes remain unchanged. The display provenance
test checks real project settings, geometry-only changes, display regeneration
and malformed settings without certifying an old header on repair.
The audio test also checks actual audio-bank.hh hashes and source-selection
dependencies. Native body edits, scene transforms and AudioSource volume/pitch
leave its record unchanged; selected-package reimport or a changed clip assignment
stales it. Saved-scene selection changes affect its export, while the open editor
scene has independent inputs. Repairing the saved source does not certify its old
bank; regeneration is required. The normal/debug Blueprint and streaming/XA
integrations verify these bank records against the actual generated headers.
The Blueprint audio-selection regression also stages real banks after numeric
variable edits, null/changed/removed AudioClip declarations and editor-flag
changes. It checks separate audio-catalog provenance and independent export
staleness. The catalog regression checks inherited null declarations, declaration
order and failed-catalog repair. verify_blueprint_features.py --emulator --keep
checks numeric declaration/default isolation and changed clip defaults through
the production CLI before rebuilding normal/debug MIPS outputs and running PCSX.
Template audio tests also stage real banks after spatial/construction/playback
edits and explicit AudioSource removal. Linked-instance checks apply and refresh
actual overrides, compare effective clip selection, and preserve unknown member
data on failure. Both projections use the existing component applicator.
The required_scene_assets_ignore_unrelated_errors test runs the production
timeline/effect preparation paths with unreadable unrelated files, required
source corruption, duplicate effects and cross-family UUID collisions. It also
checks a missing required timeline leaves an independent preview unchanged.
malformed_effects_and_uuid_collisions covers source observation, retained stale
preview data and recovery; the editor watcher regression checks that other edits
remain observable while an unchanged catalog error persists. The authored combat
integration includes unrelated malformed files during MIPS build and standalone
export, then corrupts its used effect and requires build rejection and stale
stage provenance. playback_watch_uses_selected_stage_edges checks independent
normal/debug targets, unchanged errors, semantic rename stability, removal/repair
and changes published by a preview before the next watcher poll. The playback
picker test checks retained choices, ambiguous-ID exclusion, unchanged authored
nodes and canvas revalidation without repeated requests for an unchanged error.
playback_changes_during_staging_or_compilation changes actual source files at
build-ticket boundaries and before export publication, requiring stale outputs
to be rejected while unrelated malformed files remain harmless.
The explicit real Play restart test now adds malformed unused timeline/effect
files and requires an unchanged live emulator process. It corrupts a used
timeline, verifies Play stops and the replacement fails, then repairs it and
requires a fresh emulator with the original executable before exercising C++
edit/error/recovery and unsaved scene restart.
It also creates all seven editor presets through --preset and cooks their
ordinary timeline/emitter/sprite data in one scene. The explicit ImGui effect
test clicks Add Fire layer, Undo, Redo and Save and checks layer/slot/track IDs,
whole-document restoration, embedded serialization and external-write rejection.
--open-effect plus --screenshot captures the effect editor; inspect the image
for reflection diagnostics as well as layout errors.
For the asset window, use --project examples/timeline-spell --open-timeline assets/Timelines/Cast.timeline.json --screenshot artifacts/timelines/editor.png.
The ImGui interaction test owns a context and is explicitly serialized.
cargo run --locked -- --screenshot artifacts/projects-hub.png
cargo run --locked -- --project examples/sample-game --screenshot artifacts/editor.png
cargo run --locked -- --project examples/sample-game --screenshot-game --screenshot artifacts/editor-game.png
cargo run --locked -- --project examples/sample-game --profile-editor
cargo run --locked -- --project examples/sample-game --profile-scene
cargo run --locked -- --project examples/sample-game --profile-scene-cpu
These commands need a desktop graphics adapter. Game screenshots also need the emulator. Captures are taken from application/emulator rendering. Inspect them before copying selected product images to docs/images/; keep machine paths and logs out of published screenshots.
Add --window-size 1024x720 (or 1280x720, 1440x900) to reproduce compact and wide layouts. Check Scene/Game toolbars, Inspector fields, asset columns, settings footers and floating tools at each size. --screenshot-hud, --screenshot-lighting, --screenshot-imports, --screenshot-import-dialog, --screenshot-project-settings and --screenshot-editor-preferences open their respective views. Audio captures need an imported AudioClip in the project.
The ImGui interaction check includes a real modal regression: it verifies that normalizing reordered draw indices for imgui-wgpu 0.25 preserves each command's geometry, preventing modal dimming from covering dialog controls.
Timing depends on the scene, machine and build mode. GPU preview timings do not measure native PSX game performance.
For a project containing an EditableMesh, add --screenshot-blockout --screenshot artifacts/blockout.png to open and capture its Blockout panel. Unit tests also exercise primitive winding, welded corners, ramp/triangle extrusion and subdivision, validation, stale-write protection, shared editing, extraction Undo/Redo, same-asset baked shadow occlusion and real ImGui editing buttons.
Blockout keyboard tests cover E/Q extrusion, inward displacement, edge picking, Q bevel and navigation shortcut suppression. Topology tests verify watertight bevel/ramp generation and atomic rejection of unsupported cuts. Camera tests check in-place free look, movement directions and frame-rate-independent flight; mouse capture also needs desktop verification on the target window system.
Native runtime profiling
For Timeline/VFX relocation and standalone portability on Windows:
rtk proxy python tests/integration/verify_timeline_relocation.py --emulator
The verifier builds a copy of examples/timeline-spell, copies its caches into
a second project and copies its export into a separate folder. It checks the
resolved fixture paths before renaming its own original folder so the old path
is unavailable. Both rebuilds must produce the original executable byte-for-byte;
authored files and UUIDs must remain unchanged. It also verifies v2 relative
script-manifest paths, fresh build provenance, portable generated/debug sources
and exported guides. --emulator adds a Play startup/stop smoke test from the
copied project; it is not a new RAM, visual or performance measurement. All
fixture folders are retained, and artifacts/timelines/phase5-relocation.json
records the outcome. The host provider unit test covers v1 regeneration,
equivalent manifests in different roots and rejection before partial writes.
The editor now links native/effect_preview.cpp with a host C++20 compiler and
the pinned Nugget headers. Initialize the SDK with setup before Cargo builds;
Windows uses the existing Visual Studio C++ prerequisite. Only host callback
wrapper/display stubs differ; production timeline/effect/particle Q12 kernels
are compiled directly. macOS host preview compilation still needs verification.
python tests/integration/verify_particle_effect_preview.py compares 96 fixed
steps of the editor's C ABI trace with cooked MIPS execution in PCSX. It checks
all live particle state hashes, lifecycle/diagnostic counters, sprite values,
atlas regions, world matrices and deterministic replay. The probe deliberately
executes a bounded trace in one update; do not use its frame duration as a
performance measurement. The report is written to
artifacts/timelines/phase3-preview-parity.json. The regular effect runtime
harness remains responsible for lifecycle, capacity and runtime timing checks.
cargo test --locked particle_effect_preview -- --test-threads=1 exercises the
host bridge ABI, pause, resolver ownership, replay and broken binding behavior.
Add --fireball to verify_particle_effect_preview.py for all 350 steps of the
seven-layer textured example. verify_timeline_fireball.py independently builds
and boots a copy of the example, captures each spell stage, checks marker
revisions and cleanup, records completed-frame simulation costs, and rebuilds
the standalone export byte-identically. It writes phase3-fireball.json and
fireball-stage-*.png under artifacts/timelines. The effect runtime harness
also checks per-instance typed overrides and unchanged unmodified plays;
the asset harness rejects orphaned/type-mismatched overrides without rewriting
the scene. Retiming tests preserve all IDs and reject collapsed curve keys.
For manual visual checks, open an effect with --open-effect <source-path> and
capture it with the normal --screenshot option. Host GPU pixels are not a PSX
rasterization reference, even though simulation and cooked sprite values match.
The included profiler defaults to examples/rpg-2-5d-demo. It uses that project's optional Local.epokconfig, otherwise the engine's local or default tool configuration. Build the editor first and keep the selected project and emulator port free during each run.
cargo build --locked
python tools/profile_runtime.py --output artifacts/performance/demo
python tools/profile_runtime.py --output artifacts/performance/demo-detail --detail
python tools/profile_runtime.py --output artifacts/performance/demo-validation --validate-gte
python tools/compare_vram.py artifacts/performance/demo/vram.bin artifacts/performance/demo-validation/vram.bin --png artifacts/performance/diff.png
Run these commands from the engine checkout. --project selects a different game project; --optimization Os or --optimization O2 compares runtime compilation options. Detail and validation timers add work, so do not interpret their frame times as release performance. The helper invalidates the instrumented runtime object after a run so the next normal build can rebuild it.
The profiler generates profile.json, vram.bin and logs in the requested output directory. VRAM comparisons require matching scene state and display settings; animated effects can differ between captures. See Performance for counter semantics and measurement limits.
python -m unittest discover -s tools -p test_profile_runtime.py checks linked
counter layouts, unavailable services, active gauges, capture deltas, resets and
saturation. Use --project examples/timeline-spell for a native spell capture;
the profiler's playback section reports sequences, effects and particles along
with frame costs. Startup work remains visible in the first/last cumulative
values even when the sampled frames start after the spell has completed.
Clean-checkout verification
python tests/integration/verify_splash.py captures the real 640 × 400 project
splash, a restored 1024 × 720 editor and the Hub after a failed open. It checks
window proportions at the monitor's DPI and keeps captures under artifacts/splash.
Manually check opening from a maximized Hub and on a secondary monitor as well.
Before publishing structural or dependency changes, validate a separate checkout or source snapshot containing only publishable files. Run setup with an empty .tools/, initialize the pinned SDK without nested recursion, and build with a fresh Cargo target directory.
Compile the sample PS-X EXE with no pre-existing SDK objects. Check the standalone C++ export and its README/license files. Finish with the runtime integration checks. Cargo's downloaded dependency cache may be reused, but previous compiled project/SDK outputs must not be needed.
After validation, verify that generated files remain ignored and Nugget source remains clean.
verify_bgm.py imports a generated stereo MP3 as SFX and XA, removes the source/cache and moves the package while closed, then builds/boots BIN/CUE. It DMA-reads the emulated SPU CD capture buffers and checks stereo decoding alongside a sample voice, loops, stop/restart/retrigger, music priority, switching and mono one-shot completion. Evidence is saved as artifacts/bgm-*. It needs the complete setup tools and port 8077. Physical-console XA timing/audio remains unverified.
Skeletal validation: cargo test --locked skeletal_tests compares quantized poses with the FBX evaluator and checks reimport consistency. python tests/integration/verify_skeletal.py compiles for MIPS, compares native poses, verifies changing GPU output in PCSX-Redux and captures the UI.
Python validation and migration tools require python -m pip install -r tools/requirements.txt. See document formats for YAML and the migration to Epok Engine.