MW3VC launcher maintenance record
Updated: 2026-10-09 (America/New_York)

Purpose
Preserve the reasons for the Wii startup repairs and the checks that catch
regressions. Read this alongside AGENTS.md. Historical candidate notes describe
their own versions; the current behavior below takes precedence as a record
of what is implemented. The user confirmed rc4 boots and connects to the server
on the affected physical Wii. See relocation-rc4-physical-result.json.

0.2.1: native save setup, ES metadata, IOS selection and disc errors
The old forced selector could bypass native save/banner validation. Change
only the selector's successful result; all native failure/setup paths remain.
Read installed regional TU130 metadata with ES after partition identity is
established, distinguishing missing title from permission/metadata failures.
Native IOS reload must succeed. Retain a USB cIOS only after installed d2x
metadata proves the required base IOS57; keep the USB disc mapping intact.
Bound failed disc operations and preserve their actual status/error numbers.
Regression: tests/test_hardware_preflight.py and test_regional_preflight.py.
Evidence: research/hardware-021-summary.json; README's 0.2.1 repair section.

0.2.2-rc1: historical network handoff candidate, superseded by rc2
The launcher's former libogc network setup left KD state active even after
net_deinit. Rc1 added cleanup and tested call order. The user subsequently
requested CoDN's local validation flow, so rc2 removed launcher networking
entirely. Do not restore rc1 cleanup or a compatibility cache as current flow.
The native 50120 investigation remains useful: startup fails before auth,
and multiple IOS/network failures map to that number. It does not identify
a server rejection or prove that no traffic reached the server host.
Evidence: research/50120-findings.txt and native-50120-analysis.json.
Native fault analysis: research/analyze_50120.py (requires local retail inputs).

0.2.2-rc2: local checks and correct timeout ownership
A disc-worker file timer started before SD setup/preflight could let module
loading begin. It could expire while earlier work was still validly running.
Main now owns separate stage budgets; dependent workers wait with cancellation.
SD mounting runs in a watched worker. Retail apploader code starts only after
local preflight and module-list readiness. Set the clock before timed workers;
accumulate forward elapsed time and preserve it when the clock moves back.
The launcher's old remote policy check was not an update download. Remove it
entirely: local files/hashes, cheat rejection and installed regional TU130
checks remain; the game starts its own network session. Legacy update_host
and update_port settings are accepted but ignored, and new packages omit them.
Regression: tests/test_loader_timing.py and tests/test_offline_launcher.py.
Evidence: research/client-timeout-findings.txt; network-022-rc2-summary.json.

0.2.2-rc3: code cache publication and boot-stage diagnostics
The rc2 recording passed local checks, then went green after Reading client
module. IOS58 rev6176 had successfully reloaded IOS57 rev5919. The recording
does not identify the faulting instruction or prove the cause of the crash.
Confirmed defect: apploader entry lacked explicit instruction-cache
publication; retail sections and the linked module flushed data only.
src/code_cache.c now flushes data then invalidates instructions over complete
32-byte cache lines. Call it after loading the apploader, after each retail
section read, and after module relocation/stub generation, before execution.
Keep individual patched function-entry cache maintenance as well. Validate
apploader entry alignment and membership in the actual loaded body. Retain
the additional progress messages; they add no intentional boot delay.
Regression: tests/test_boot_handoff.py runs the compiled launcher and local
USA retail apploader, checks 17 reads and cache-call ordering, rejects invalid
entries, covers unaligned ranges, and detects an omitted invalidation.
Evidence: research/green-screen-findings.txt; boot-handoff-tests.json;
boot-022-rc3-summary.json; boot-022-rc3-coldboot-multiplayer.json.
All seven regional checks passed and rc3 reached MW3 Online in Dolphin.
Limit: these tests do not emulate the physical cache or prove the reported
Wii crash is cured. Keep that distinction in release notes and support replies.
Follow-up: the user confirmed rc3 still crashes on a physical Wii using a USA
disc and component output; ordinary Disc Channel boot works. The new recording
reaches Linking client module; boot=menu also freezes. See green-screen-rc3-retest.txt. Rc3 is not a
confirmed remedy for this incident.

Checking future launcher changes
Offline diagnostic 0.2.2-diag1 retains the existing IOS/loader/shutdown path
but suppresses module reservation/hooks and DOL patches. Its setting is
launcher-only; never extend the pinned module ABI for diagnostics. The package
defaults to diagnostic mode, and is not an online release or confirmed fix.
tests/test_disc_diagnostic.py checks untouched retail code, zero module memory
reservation, symbol-reader completion before unmount, ordinary-mode patching,
and strict config parsing/reset. Existing rc3 test receipts were copied into
research/rc3-original-receipts before running new builds' general test suites.

2026-10-08 physical isolation result and diag2
The user confirmed diag1 reached the actual main menu on the affected Wii,
not merely a loading/controller screen. Record: disc-diag1-physical-result.json.
This rules out the common native-disc path as sufficient to cause this freeze
in the observed baseline; it does not prove all loader behavior is correct.
Diag2 accepts diagnostic_disc_boot=memory and restores actual module section
placement and the same 14,272-byte reservation as the normal client. It stops
before hook installation/export/final SDK relocation and omits DOL patches.
Its package remains offline with boot=menu. tests/test_memory_diagnostic.py
executes the real compiled ELF loader with filesystem, heap and SDK-lookup
boundaries instrumented. It verifies equal reservations, untouched retail
code in memory mode, and all three installed hooks in the normal control.
Diag1's historical general receipts are saved in diag1-original-receipts.

Diag2 physical failure and diag3 isolation
The user reports diag2 triggered the crash on the same physical-disc test.
Record: memory-diag2-physical-result.json. Do not blame hook execution or DOL
patches as necessary for this reproduction: both were disabled in diag2.
Diag3 parses the pinned module to retain exactly the same 14,272-byte reserved
footprint but skips Module_ListLink entirely. Retail BI2/FST relocation still
occurs, separating reservation/relocation from module placement/linking.
Its package uses diagnostic_disc_boot=reserve, stays offline, and keeps the
same IOS and shutdown path. The compiled ELF-loader test now verifies that
the reserved module area is untouched in reserve mode, with matching sizes
in reserve/memory/normal modes. Diag2 receipts are in diag2-original-receipts.

Rc4: concrete BI2 relocation defect, after diag3 physical failure
The user reports diag3 crashed, with no module placement or runtime patches.
Tracing the retail USA apploader showed subsequent callbacks reading BI2
fields through low-memory 0x800000f4. The launcher had moved BI2 from
0x817fa880 to 0x817f70c0 (14,272-byte reservation), leaving that pointer stale.
The apploader reads +0x2c to calculate MEM2 limits and IOS heap bounds. With
stale 0x00100000 there, the old loader reports 1 MB instead of 64 MB and an
IOS heap at 0x8f4e0000, outside MEM2. No reservation correctly overwrites the
old address and succeeds. This reproduces a concrete defect independently
of module hooks or the server. Evidence: bi2-relocation-before-fix.json.
Rc4 recognizes when the relocated read is the block addressed by the native
BI2 pointer and updates/flushes it immediately after successful DI_Read,
BEFORE the next retail callback. Updating it only after all reads is too late.
test_bi2_relocation.py now passes with stale high RAM at reservation sizes
0, 14,272 and 65,536 bytes, preserving native MEM2/IOS bounds in each case.
Do not describe emulator zero-filled RAM as proof that no stale-pointer bug
exists. Do not claim this is physically cured before the affected Wii retest.
Rc4 restores full runtime patching by default; diagnostic settings must not
be carried over from diag1/2/3. Module, symbols and endpoints remain pinned.

Rc4 physical acceptance, 2026-10-08
The user reports: "It worked and I was able to connect to the server" after
testing the delivered rc4 candidate on the previously failing USA-disc Wii.
Record this incident as boot and server-connection success, with user-report
provenance. It supports the BI2 relocation repair as the remedy for this crash.
No new physical trace or matched server-log evidence was captured. Match play,
USB loading, other consoles/regions and the friend's separate 50120 incident
are not established by this report. Preserve the delivered rc4 binary/source
archives and pre-delivery receipts; this separate result supersedes their
then-pending physical status without rewriting historical evidence.

For rc5's USB handoff repair, also read usb-partition-findings.txt and run
tests/test_usb_partition_handoff.py. Close the partition inherited from an
alternative-DOL loader before opening it again; do not reset its cIOS mapping.
The native-disc path and BI2 repair remain unchanged. Rc5's physical retest
still fails at metadata open with 128; normal USB boot works. See
usb-rc5-physical-result.json. The prior model does not establish the hardware
cause. usbdiag1 reports startup IOS/revision, chosen startup path, disc ID,
submitted partition command, buffer addresses and whether IOS wrote an ES
error. It preserves rc5 boot behavior and reports the first open failure once
instead of flooding the screen on retries. It is diagnostic, not a new fix.
Historical receipts are in rc4-original-receipts and rc5-original-receipts.

usbdiag1 photo follow-up: IOS57 rev5918, native reset path, SM8P52, open 128,
no ES detail written. This skipped the inherited-partition close. GX's Error
002 patch copies the game's requested IOS from 0x80003188 to 0x80003140,
the value read by libogc's IOS version APIs. A reported slot <200 is therefore
not proof of native IOS after alt-DOL entry. Read the latest
usb-partition-findings.txt before changing detection or resetting/reloading
IOS. The actual Game IOS setting and console identity remain unconfirmed;
do not silently merge this UK screenshot with the USA physical-disc success.

From the project root, use the configured Python and local devkitPPC toolchain.
For launcher-only changes, preserve build/module/mw3.mod and build/symbols:
  python -c "import sys;sys.path.insert(0,'tools');import build;build.launcher()"
Run the suites appropriate to the affected paths:
  python -B tests/test_boot_handoff.py
  python -B tests/test_loader_timing.py
  python -B tests/test_offline_launcher.py
  python -B tests/test_hardware_preflight.py
  python -B tests/test_regional_preflight.py
These run compiled PPC with platform boundaries instrumented. Retail inputs
must already exist locally and must not be included in source distributions.
For boot changes, use an isolated Dolphin test profile and visually confirm
the expected game/online screen. Bind receipts to the actual launcher hash.
If runtime module behavior changes, also run native module/mode-transition
tests; launcher-only results are not evidence for new runtime patches.

Release and documentation discipline
Delivered 0.2.1, rc1, rc2 and rc3 ZIPs/receipts are historical artifacts.
Do not overwrite them when editing notes or preparing another build. Bump the
launcher/package version and adapt the packaging/verification helper first.
Rc3 uses tools/package_boot_fix.py and tools/verify_boot_release.py; the older
package_network_fix.py targets rc2. The scripts are version-specific, and the
verifier compares source files to the workspace as it existed at packaging.
Later documentation changes do not retroactively change a delivered receipt.
Future source packages include AGENTS.md and these investigation notes.

Hardware follow-up still needed
New SM8P52 physical-disc report: successful IOS58/6432 -> IOS57/6175 reload,
preflight and executable checks, then function replacement failure. Linkdiag1
adds named hook diagnostics. See disc-link-failure.txt. The real-symbol test
passes seven regional inputs but does not reproduce the hardware failure.
Keep the accepted USB250 release intact; no new fix is established yet.

USB250 latest acceptance: the user now reports it works after the 51420
follow-up. Record user-reported USB boot and online success, without claiming
which network change resolved the error. See usb250-online-physical-result.json.
Publish the exact tested artifacts; keep pre-delivery receipts unchanged.

USB250 physical follow-up: the user reports boot now works and supplies a
51420 network error screen. Record the partition/boot fix as user-confirmed
for this case, with online unresolved. Nintendo associates 51420 with LAN
adapter detection. See usb250-physical-result.json; preserve prior receipts.

USB250 follow-up: both 249 and 250 settings failed with the earlier launcher.
The explicit USB250 candidate fixes path selection under GX's rewritten IOS
identity, with a required matching Game IOS 250 setting and installed-base
validation. It does not auto-detect the live slot. See usb250-findings.txt.
Use the seven external USB DOLs only for this contract; apps/boot.dol remains
the native HBC/Dolphin entry. Prior USBdiag1 receipts are preserved separately.

For the next Wii report, retain version, console model, disc ID/region,
HBC/disc versus USB-loader path, IOS revision/base, last progress line, and
time of any online retry. Match server evidence to that attempt, not merely
to the existence of some launcher request. Do not assume a green screen means
video-mode mismatch, an update error, save corruption or server failure.
Confirm success on the affected Wii before recording either green-screen or
50120 as a resolved hardware incident. Keep existing saves and TU installations
unless separate evidence and the user's request justify changing them.

2026-10-09 main-menu default
The original-Wii bench reached the game Loading screen but hung before menu
with linkdiag1 boot=multiplayer. Only mw3vc.ini was changed to boot=menu;
the user then confirmed disc loading worked and requested this as the default.
Retain this default for new packages. All runtime hooks remain enabled.
This is a startup workaround with one reported successful menu test, not proof
of the root cause or of manual Multiplayer/online success. menu1 repackages
the exact linkdiag1 executables with the tested config, instructions and new
hash manifest. No source rebuild or historical archive replacement is needed.
See bench-menu-default-result.json and menu-default-package.json.

2026-10-10 Recent Players candidate
0.2.3-recent1 changes the guarded MP Recent Players save interval from five
minutes to ten seconds. Read research/recent-players-findings.md. Preserve
native dirty/task handling, Ally filtering, strict code hashes, and cache
publication. This changes the runtime module, so rebuild matching launcher
pins and both native/USB entries; do not apply old module pins. Test the actual
new reservation size. boot=menu remains the default. The affected-Wii retest
and exact player-name correlation are pending.

Follow-up: the user identified their name as 123 and their friend as REQUIS.
The short reconnect belongs to 123 (18:06:05 through 18:10:02 UTC); REQUIS
remained connected. The read-only registry confirms they are not Allies.
This supports the reproduced loss path. Physical candidate retest is pending.
The already packaged source ZIP retains the earlier pending-name wording;
its historical contents and all delivered archives remain unchanged.

2026-10-10 NAND login and moderation candidate
0.2.4-nand1 adds an ES device-ID auth extension and native rejection cards in
MP/SO. Read nand-moderation-findings.md. This is an identity gate, not signed
certificate attestation. Preserve the matched runtime/SDK symbols/launcher
pins and all seven USB entries. boot=menu and the Recent Players fix remain.
Run tests/test_moderation.py and tests/test_native.py for all seven regions,
the real-symbol loader test, and a retail apploader test using the actual new
module reservation. Physical card and IOS behavior still need a Wii retest.

2026-10-10 recent1 platform follow-up
The user confirms 0.2.3-recent1 launched on Wii U, and explicitly clarifies
that this is launch success only. Recent Players has not yet been validated.
The friend's Dolphin photo shows IOS58/6176 and wait-for-disc error 0, before
disc ID, regional TU130 validation or runtime linking. Check its selected MW3
Default ISO first; configuration and a corrected retest have not been supplied.
See recent1-platform-result.json. Preserve the delivered candidate archives.

2026-10-10 native ban-title follow-up
An imported owner NAND reproduced a correct ban body with an empty title.
The native popup translates its title key; arbitrary server text has no entry.
0.2.4-nand2 bypasses this lookup only for the received title buffer and retains
normal localization for ordinary errors. Run the real-popup moderation tests,
all regional native/link tests, and an imported-NAND visual test. Keep nand1
archives intact; new binaries require a matched module, both launcher profiles,
and all seven external DOLs. Server wire format and playlist v130.6 are unchanged.

2026-10-10 admission message follow-up
0.2.4-nand3 retains the NAND v1 prefix and appends M3VR plus a bounded 32-byte
client version string during native authentication. Older NAND-aware servers
ignore the suffix. Updated servers require a configured exact client version
and return a native update card on mismatch or missing version. No launcher
networking is added. The ban heading is Console Banned; the default Dolphin
NAND has its own card. Preserve v130.6 and the Recent Players fix. Rebuild
matching module pins, native and USB entries, and validate all seven regions.

2026-10-11 active cheat hooks
0.2.4-cheat1 is a launcher-only revision over 0.2.4-nand3. It allows unused
GCT files and requires a recognized resident handler plus a relative branch
from current executable text before diagnosing an active Gecko/Ocarina hook.
Check launcher text at preflight and freshly loaded retail text before hashes.
Do not scan arbitrary RAM, treat unhooked leftovers as active, or remove the
retail/runtime integrity checks. Read cheat-hook-findings.md. Run
test_cheat_hooks.py, regional/offline/hardware preflight, loader timing,
boot handoff and USB entry profile tests. Retain runtime module/symbol pins
and MW3VC_VERSION=0.2.4-nand3; only MW3VC_LAUNCHER_VERSION changes. Server
admission stays nand3. New ZIPs have all seven external entries and boot=menu.
Physical-Wii USB acceptance remains pending. Historical general receipts were
copied to nand3-original-cheat-receipts before running the changed launcher.

2026-10-11 client version label 0.2.6
The user requested 0.2.6 as the label for the full themed Barracks client.
Only the launcher-visible version and release metadata change from barracks2.
The runtime module, symbols, wire/auth version 0.2.4-nand3, configuration,
Gecko/Ocarina behavior, and game behavior are preserved. Both launcher
profiles are rebuilt; all seven external DOLs use the matching USB build.
Historical delivered archives and receipts are retained. New validation and
packaging receipts use release-0.2.6-* names.

2026-10-11 stock-style confirmation candidate 0.2.7
The user supplied the native prestige card as the desired style. The modal now
uses full-width dark title/footer bars, wrapped sentence-case body text, and
the native controller glyph. Confirmation safety and progression behavior are
preserved. Rebuild the changed module and both launchers with matching pins;
keep all seven USB DOLs, boot=menu, auth 0.2.4-nand3, and previous releases.
See barracks-style-findings.md and matching receipts. Physical Wii is pending.
