Cleaner forward-facing pad with diagonal corner grips and sticks under
Start/Select, matching the RetComM teal tile.
Co-authored-by: Cursor <cursoragent@cursor.com>
Bumps recomp-net so empty lobby seats no longer block READY/admit; launch
builds the mask from seated members (online + LAN).
Co-authored-by: Cursor <cursoragent@cursor.com>
Conflict: recompiler/CMakeLists.txt. Master gained #134's test registrations
in the same block where #133 added stall_report. Resolved as the union of both.
Also RE-ENABLES aot_overlay_discovery, which is not part of the conflict region
and so would otherwise have survived the merge untouched. #134 registered it
DISABLED with this reason:
"fails in check_real_batched_fragment_publication: that check reaches
MOD.compile_fragment_batch, which spawns psxrecomp-game with cwd set to its
own TemporaryDirectory, so BIOS-profile resolution finds nothing ... it
needs an owner, and DISABLED keeps it counted until then."
This branch is that owner -- resolving BIOS-profile lookup against
--project-root instead of the CWD is exactly that fix. Landing it while leaving
the test disabled would ship the fix with its own proof switched off, which is
the silent-rot class #134 exists to prevent.
Measured on this tree, msys64 toolchain driven from PowerShell:
- pristine origin/master: test_aot_overlay_discovery.py exits 1 at
check_real_batched_fragment_publication, "no BIOS profile found"
- this merge: ALL PASS, and ctest -R aot_overlay_discovery passes in 7.64s
with the DISABLED property removed
- baked codegen hash 0xfbb44d49u on BOTH arms -- the cache tag does not move,
so existing overlay caches keep loading
- full ctest failure set identical to pristine master, no new failures
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Wire lib/retcomm-rbengine beside recomp-net and replace MotK in-tree sched,
hash_confirm, input hist, snap ring, and rb_post with thin PSX shims so the
ecosystem can share invent/pacing policy outside each title facade.
Co-authored-by: Cursor <cursoragent@cursor.com>
tests: repair the standalone snap-ring harness, and make unregistered tests impossible
Alexbeav's harness fix, plus TechnicallyComputers' Linux -Werror/_POSIX_C_SOURCE
nit, plus a configure-time guard that fails on any test file registered nowhere.
Verified: guard fails on an added orphan and passes when removed; runtime ctest
32/32 pass + 3 disabled; recompiler ctest matches the pristine master baseline
exactly (same 5 pre-existing failures); Tomba, Tomba 2 and MMX6 build and were
validated hands-on.
PR #134 fixed test_netplay_snap_ring.c's harness. This addresses why it broke:
its only build instructions were a gcc command line in a header comment, and a
comment cannot fail. 16 of the 41 C/C++ tests in runtime/tests/ were in that
state, plus 3 python guards. Four had already rotted against the runtime API.
Worse, two tests that WERE registered did not link on origin/master --
sio_dualshock_rumble_test (psx_read_word / psx_get_cycle_count / i_mask /
g_debug_last_store_pc) and spu_fidelity_test (crc32_update) -- so `ctest` in a
runtime tree did not build at all.
Registering them fixes the instance. check_test_registration.cmake fixes the
class: it reads both CMakeLists.txt files as text and fails configure on any
test file that is neither registered nor listed with a reason. Reading them as
text (rather than adding a top-level CMakeLists.txt) keeps the BIOS-free
recompiler tree configurable, which is the only tree a newcomer can configure;
both projects call the guard, so each catches orphans in the other.
CONFIGURE_DEPENDS matters: without it, ADDING a test would not re-run configure.
Also incorporates TechnicallyComputers' review of #134. -Werror turns a
pre-existing Linux warning into a hard failure: clock_gettime/CLOCK_MONOTONIC
need _POSIX_C_SOURCE under a strict -std=cNN. Both halves are needed -- the
define in netplay_snap_ring.c fixes a direct compile of that TU, but not the
harness, which includes <stdio.h> first and so has already latched glibc's
<features.h>. Verified on Ubuntu 24.04 / GCC 13.3.
Test-file changes:
* repaired 4 rotted tests (stubs / a changed parameter list), no logic edits
* build recipes replaced with `ctest -R <name>`, so exactly one description
of how a test builds exists and the build executes it
* known-failing tests registered DISABLED, not de-registered -- de-registering
is the mechanism that hid these in the first place; DISABLED keeps them in
`ctest -N` and countable without turning the run red
* sio_card_protocol_test runs in a build-tree scratch dir; it writes
test_dir/card1.mcd, and that is a TRACKED fixture
* removed three committed test binaries and widened the .gitignore rule that
missed them (it only covered *.exe, and these were Linux builds)
Disabled, each with a bead: sio_card_protocol_test (147/309),
sio_dualshock_rumble_test (27), spu_fidelity_test (4 ADSR), aot_overlay_discovery
(cwd), and the 3 pre-existing perf guards.
Verified:
* adding an unregistered test file fails the build with an actionable message;
removing it passes
* runtime ctest 32/32 pass, 3 disabled
* recompiler ctest: same 5 failures as a pristine origin/master baseline
* Tomba, Tomba 2 and MMX6 build against this framework and were each driven
240s of attract + randomised pad fuzz (~195 injections, 47+ combos):
59.6 fps sustained, zero stalls, all three reached real gameplay
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keep dispatch counters as raw event counts, fail closed on malformed or reset evidence, label rolling and censored scopes, retain bounded-ring provenance, and write hash-bound diagnostic artifacts atomically. Add focused protocol tests and register them with CTest.
Retires the legacy generic turbo_loads switch framework-wide. Shipped to players first as MegaManX6Recomp v1.0.6 (built from the same change backported onto that title's older pin); landing on master so every title inherits it and MMX6 can move back onto a master pin.
Load acceleration moved to the Mods catalog in 125d84d
(psx.enhancement.fast-loading "Fast Loading (host pacing)" and
psx.enhancement.cd-speed, both `game_id = "*"` so they ship with every
title, both default-off), and recomp-ui deliberately stopped drawing a
generic Turbo loads row. But the legacy switch was left live here with
`offer_turbo_loads` defaulting TRUE, so any title that had not explicitly
migrated still got turbo forced on — with no UI to turn it back off.
That shipped to players. MegaManX6Recomp v1.0.4 and v1.0.5 both carry
`[runtime] turbo_loads = true` in the game.toml inside the release zip
(verified by extracting the artifacts). Two paths forced it on:
* game.toml [runtime] turbo_loads set g_turbo_loads_enabled directly;
* a stale [video] turbo_loads in settings.toml was restored, and the
seed write persisted it — so one run latched the value permanently
and no later game.toml change could undo it.
Reported as MegaManX6Recomp#14: the WARNING screen self-advances and load
spinners run fast, with Turbo confirmed off in Mods. Tomba 2 hit the same
defect (fixed per-title), and MMX5 is also unmigrated. Third occurrence of
one config default, so fix the class instead of the titles.
Both keys are still PARSED, so existing configs load without error, but
neither is honoured:
* offer_turbo_loads defaults false and turbo_loads_offered becomes a
constexpr false, matching how ws_offered / skip_fmv_offered /
frame_interpolation_offered already model mod-owned features. No title
can offer the generic switch, so forgetting to migrate is no longer
punished.
* game.toml turbo_loads logs a deprecation line naming the Fast Loading
mod and enables nothing.
* settings.toml [video] turbo_loads is neither restored nor written back
out, so the stale row is dropped on the first save — same write-only
latch reasoning already documented for fast_boot, which bit harder here
because there was no UI control at all.
Also fixes a related hole found while auditing: the in-game Settings apply
path wrote both g_turbo_loads_enabled and g_auto_skip_fmv from a launcher
snapshot taken BEFORE mod_runtime_activate_plugins() ran, so the first
in-game Apply silently turned a player's enabled Fast Loading or Tweaks FMV
feature back off. Both are now gated on their offered flags.
The supported surfaces are unchanged: the Fast Loading / CD Speed mod
plugins still enable acceleration (verified: "mod selected 8x load
acceleration"), and the `turbo_loads` TCP debug command still toggles it
for development.
Verified against MMX6 built on this framework: with game.toml
`turbo_loads = true` AND `offer_turbo_loads = true` AND a stale
settings.toml `turbo_loads = true`, both deprecation lines fire and the
debug server reports enabled=0, turbo_frames=0. With the keys removed and
no mods enabled, it boots silently with enabled=0.
test_mod_load_acceleration.py is updated to pin the new contract; it also
had a stale assertion on the old 2..16 multiplier range, which is now
pinned to the symbolic PSX_MOD_LOAD_ACCEL_MAX bound. The guard-test suite
goes from 9 pre-existing failures to 8 (no new failures; this one fixed).
Refs: beads-eio.3.26, MegaManX6Recomp#14
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
phase window as rolling
Both reported by @Alexbeav on PR #131, both confirmed against the runtime
source and a live warm-cache instance.
1. autocompile_status nests every compile field under "compile" (see
handle_autocompile_status in debug_server.c). The report read runs, fails,
the shard counts and the degraded flag off the OUTER object, where none of
them exist, so it always printed zeros and never printed a degradation
reason.
This was the worst possible placement for the bug: section [1] exists to
catch a silently-failing autocompile, and it reported a healthy-looking
row of zeros in exactly that case. It was visible in the validation output
of the original commit -- "autocompile: runs=0 fails=0 shard_ok=0" -- and
was not questioned, which is the same unexamined-quiet-number failure the
tool is meant to prevent.
Measured on a live instance during a 15s window: the fixed version reports
runs=3 fails=3 consecutive_fails=3 last_exit=1 and the full DEGRADED
reason string. The old version reported runs=0 fails=0 and no warning at
all for the same window.
The section now also reports `configured`, `state`, and
`shard_result_seen`, because those are what make a zero interpretable:
not-configured zeros are expected, whereas configured-but-never-saw-a-
PSX_SHARD_RESULT zeros are meaningless rather than healthy, and the report
now says which it is. A missing `compile` object is called out as a
protocol mismatch instead of being silently treated as zeros.
2. phase_profile sums a ring of recent seconds and reports its own window_s;
it is a ROLLING WINDOW, not a since-boot total, and it does not align with
this report's window. It was labelled "cumulative since boot". It now
prints the runtime's reported window and states plainly that the scope
differs from the report's own.
Left deliberately for the follow-up @Alexbeav offered: fail-closed handling
of missing/non-numeric/decreasing counters, the dispatch-counter percentages
being dispatch-event shares rather than coverage or time-share, top-set
censoring in the phase_hot and per-PC deltas, ring metadata for
reproducibility, and artifact schema/tool-hash/atomicity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diagnosing "why is this title spending its time in the interpreter" currently
means issuing eight TCP commands by hand and correlating their JSON. That is
enough friction that it does not get done, and when it is done by someone
without the runtime's internals in their head the numbers get misread -- #72
is a live example: an empty phase_hot was read as a possible bad query when it
in fact meant nothing native was executing at all.
stall_report.py collapses that into one command and one pasteable report,
usable against any title on any port:
[1] Is the overlay cache actually BEING USED, or just present on disk?
dispatch_native vs dispatch_interp_fallback, stale_blocked, the
autocompile degraded channel, and shard ok/fail/skipped counts.
[2] When code IS interpreted, is it chaining or thrashing?
dirty_ram insns_run/blocks_run = instructions per dispatcher
round-trip, with the kernel-window-is-per-block-by-design caveat
stated inline so a low ratio there is not misread as a bug.
[3] Where did the wall-clock actually go?
The largest host_us gaps in the always-on PC-sample ring, each with
the guest cycles that advanced across it. That ratio separates three
failure shapes that look identical in a frame-time graph: CPU kept up
(gap is GPU/present/vsync), CPU-bound but executing, and emu thread
not running at all.
[4]-[6] phase shares, hottest interpreted PCs tagged kernel vs
above-floor, and phase_hot deltas for both the native and static sets.
PASSIVE RING CONSUMER by construction, per the project's observability rule:
it never arms a trace, never pauses, never single-steps. Everything is a
cumulative counter (two snapshots subtract to a window) or a read of a ring
that has been recording since process start, so attaching late still sees the
event. `snap` reports cumulative; `run --secs N` reports deltas.
Two caveats are printed in the output rather than left to be rediscovered:
current_func is a STATIC dispatch stamp and localizes without proving
interpretation, and an empty native phase_hot means nothing native ran rather
than a malformed query.
Validated against a live Tomba 2 debug build (Release + PSX_DEBUG_TOOLS=ON,
port 4515), both modes and the --out JSON artifact. Representative real
output: dispatch_native 3,253,132 (97.16%) vs interp_fallback 95,047 (2.84%),
16,329 instructions per dispatcher round-trip, and one 68 ms gap at 0.46x
realtime flagged in-exception. Development of the tool caught two defects in
itself that way -- snap mode subtracted a snapshot from itself and reported
zeros for everything, and non-ASCII output mojibaked on a cp1252 console --
both fixed before commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
compile_overlays.py spawns psxrecomp-game with cwd = dirname(game.toml),
because the seeds and capture paths in the config are relative to it. That
cwd is also where the recompiler probes for bios/SCPH1001.toml when the
config carries no explicit [recompiler] bios_config -- and --ws-config, the
only config channel overlay compiles use, deliberately does not adopt the
config's paths, so bios_config is never consulted for them.
For a PACKAGED game.toml (packaging/release/game.toml) that directory holds
neither bios/SCPH1001.toml nor a vendored framework one level down. Every
shard then died with "FATAL: no BIOS profile found", ok=0, and the overlay
cache silently failed to build. The run still exits, so the only symptom is
that the title ships with no cache and every player's first session runs
interpreted. Reported as issue #72, and it is what the recipe printed by the
game repos' package_release.ps1 told people to run.
Fix:
- psxrecomp-game takes --project-root <dir> and resolves the profile against
it: the direct bios/SCPH1001.toml probe, the one-level vendored-framework
probe, and a relative [recompiler] bios_config (documented as relative to
the game project root, previously resolved against the CWD). Absent the
flag, behaviour is unchanged.
- Every "no BIOS profile found" / bios_config failure now names the absolute
directory it searched. Without it the message reads as a config error when
it is a CWD error, which is what cost two vault parses on the Tomba 2
v0.0.8 cut.
- compile_overlays.py forwards --project-root to all three recompiler spawn
sites, defaulting it to the framework root derived from the required
--runtime-include. The derivation is used ONLY when it actually locates a
profile, so it can repair a broken invocation but never alter one that
already worked -- and the recipe the packager prints now works as written,
with no game-repo change. Every attribute lookup degrades to "pass no
flag" so the in-process callers that build a partial args object keep
working.
This also un-breaks the framework's own overlay test suite, which was RED on
master for the same reason: test_aot_overlay_discovery.py compiles against
tools/cycle_testrom/game.toml, so the recompiler probed
tools/cycle_testrom/ -- which has no BIOS profile -- and every shard failed.
Measured on this tree with one recompiler binary, changing only the tool and
tests: master exits 1 at check_real_batched_fragment_publication; this commit
reaches ALL PASS.
Two test repairs were needed to get there, both pre-existing and both masked
by the profile failure that stopped the suite before it could reach them:
- check_full_candidate_cli_fastpath stages a SYNTHETIC runtime_include in a
temp dir, so the framework root is not derivable from it and the root must
be named explicitly.
- the same test staged its cache prefill under cg<ver>_<hash>, missing the
_gc<config-hash> component the cache path gained. A prefill one directory
off is not found, so the run compiled for real instead of taking the fast
path the test exists to assert.
The cache tag is unaffected: main_psx.cpp is not in codegen_hash_sources.cmake
(verified -- the baked hash is fbb44d49 before and after), and
--overlay-config-hash returns before any of this code runs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>