POPStarter DOCS

AGENTS — orientation & high-risk surfaces

← POPSLoader docs · view on GitHub ↗

Last updated: 2026-07-27 (rolling dev = v1.1.1-dev; released line 1.1.0)

Operational guidance and entry point for AI agents (cloud or interactive) working in this repository. This file is self-contained: it absorbs the former AGENTS_START_HERE.md orientation content. For current code/hardware status, behavioral invariants, preservation contracts, and the canonical known-issues list, defer to STATE.md rather than restating them here.

Start Here / Orientation

POPSLoader is a PS2 launcher for POPStarter built on Enceladus runtime pieces, with behavior primarily orchestrated by embedded Lua modules (system.lua, ui.lua, images.lua). The Lua is bin2c'd into the EE ELF at build time, so a runtime Lua error (nil global, type error, load-order error) is invisible to luac -p and to CI and only surfaces on real PS2 / PCSX2. (pops_profiles.lua was removed 2026-07-13 with the profile-preset system.)

Historical note: Earlier entry-point docs framed D-10 (HDD POPSTARTER + HDD game) as the single urgent unresolved objective. D-10 was resolved by the B2 PFS-unmount fix at commit 4ae6679 and is now a preservation contract, not an open blocker (see STATE.md > Preservation Contracts).

Where to look first

File What's there
STATE.md Canonical. Current code + hardware status, behavioral invariants, preservation contracts, the single known-issues list, hardware-verification table. Start here for ground truth.
QA_REGRESSION_MATRIX.md Authoritative detailed hardware/CI run ledger with per-artifact history.
ROADMAP.md Prioritized backlog / open work.
DECISIONS.md Decision log with rationale and evidence.
docs/archive/ Investigation artifacts: U10_INVESTIGATION.md, LAUNCH_HYGIENE.md (launch-path architecture, V2 mimicry, Layer A/B/C), HDD_POPSTARTER_HANDOFF.md.

Source-of-Truth Rule

Scope

Preservation Contracts & Known Issues

These are shared, volatile facts maintained in one place. Do not restate or fork them here.
- Preservation contracts (D-10 / D-14 / D-15 / DKWDRV-MC / BOOT.ELF-USB-booted / EnsureBootPartitionWritable): see STATE.md > Preservation Contracts and the Reported Hardware Status table. Write these as contracts hardware-confirmed in the BETA line, not as open failures.
- Known issues (open / in-testing / recently-resolved): see STATE.md > Known Issues. Notable status deltas already reflected there: U-10 (BOOT.ELF from HDD-boot) and DKWDRV from a custom HDD path are RESOLVED (were known-broken); Class-A HOSDmenu / wLaunchELF start failures are resolved. The old "HDD installs save to mc0: because ps2hdd-osd.irx can't write PFS / needs an IRX swap" claim is OBSOLETE — HDD installs now save on the HDD boot partition via the RW mount take-over (single-device parity; see STATE.md > Settings).

High-Risk Surfaces

Changes in these files can break core behavior and require extra care:
- bin/POPSLDR/system.lua (LaunchEngine, RunPOPStarterGame, ResolveBootContext, classify_mass_boot, AutoInitStartupBackends, EnsureMmceReadyOnce, PLDR.ResolveLaunchPopstarterPath — the per-device POPSTARTER.ELF resolver: the explicit user-configured absolute path (the "POPSTARTER Path" setting; empty = Automatic — the 16-preset profile system was removed 2026-07-13, UI/config layer only, the ladder is untouched) wins first, then for removable devices the game's own <device>:/POPS/POPSTARTER.ELF, then the cwd copy beside POPSLOADER.ELF, then the mc0:mc1: net (for internal-PFS HDD the device step is hdd0:__common/POPS/POPSTARTER.ELF, resolved through the same __common partition machinery that preserves the D-10/D-15 partition context); the device + cwd steps are existence-gated so a device without a copy falls through. Not yet hardware-tested. And PLDR.HDD.EnsureBootPartitionWritable — the boot pfs-slot unmount→remount-RW "take over the mount" that is now load-bearing for HDD settings save and HDD in-app .hide; a launch-path or mount change must not break it. Note also the load-order trap: PLDR.HDD methods must be defined after PLDR.HDD exists — defining them early bricked recent HDD-feature rolling builds, fixed d4b04be. New 2026-07-09 launch-path residents: PLDR.MaybeApplyAdaptiveBdma (launch-time BDMA staging — runs after the launch validations, cancels the launch on a staging failure; nothing queued after exec can render, so don't move its toast past the exec) and the partition-installed game arm in RunPOPStarterGame (argv0 = the literal PP./__. partition label — case-sensitive, never sanitized).)
- bin/POPSLDR/ui.lua (LaunchSelectedGame — its POPSTARTER preflight must resolve with the SAME root the RunPOPStarterGame call gets: the game entry's own device root on encoded-entry pages (USB entries = "<root>POPS/|name.vcd", PLDR.GAMEPATH deliberately empty there), GAMEPATH on bare-name pages, scene-guarded on GHDD. Resolving the preflight with GAMEPATH blocked every drive-resident-only USB POPSTARTER with "No POPSTARTER.ELF found" while the launch itself would have worked (sAGA/oldman63, fixed 2026-07-16) — do not reintroduce the divergence. Also LaunchBootElf, OpenDKWDRV; BuildCoverCandidates — the per-device cover-art seeker: it returns exactly ONE candidate (EXP71, maintainer directive). Removable devices: <device>:/ART/<gamefilename>_COV.png, device root matched with %w+:/ so a digit-bearing device name like mx4sio0: still resolves (%a+%d*: did not, and MX4SIO covers were unfindable). APA/PFS: hdd0:__common/POPS/ART/<gamefilename>_COV.png via PLDR.ResolveHddPartitionReadablePath, which existence-confirms. The user-selectable folder (ART_LOCATION, the Cover/details folder row) was REMOVED in EXP35 and the key is inert; the disc-marker-stripped family name, the always-appended POPS/ fallback, the legacy <name>.png and the additive legacy families are ALL GONE — a stripped candidate can shadow exact per-disc art and every extra candidate is a full dir-chain walk on a big ART folder. The .txt details sidecar (<device>:/ART/<gamefilename>.txt) is read on the RESIDENT COVER WORKER via Graphics.coverLoadTextPath + coverLoadText, never on the render thread; System.listDirectory on the cover folder must NOT come back (implicated three times). INVARIANT: selecting a game performs ZERO blocking file reads, pinned by harness T30/T35/T40; external launches drain the worker first (T39). Canonical detail: STATE.md > Cover art plus the EXP71/EXP73 bullets; also UI.Pad.Listen/resolve_nav — the frame-counted nav auto-repeat and the Pads.getMode()-gated analog-stick fold; do not reintroduce wall-clock timing or an ungated stick read — see Gotchas)
- src/main.cpp (detectBootDeviceHintFromArgv0, parseLaunchArgs, eager IRX load order, conditional mmceman)
- src/luasystem.cpp (lua_loadELF, EnsureBDM, EnsureMmceman, lua_mx4sio_init with mandatory EnsureUsbMass-first ordering, getMassMountDriver)
- src/luaplayer.cpp
- src/elf_loader/src/elf.c (LoadELFFromFile, ExecuteViaEmbeddedLoader, ExecuteHddBackedViaEmbeddedLoader, LoadELFFromFileWithPartition)
- src/elf_loader/src/loader/src/loader.c (BRAM child loader; HDD partition-context branch must preserve B2 dynamic PFS unmount)
- etc/boot.lua (pfs1: boot mount normalization)
- Makefile
- .github/workflows/compilation.yml
- .github/workflows/rolling-release.yml (builds and harness-gates on push to dev
and* on PR events, but the publish step carries if: success() && github.event_name == 'push' — only a push to dev moves the canonical rolling-release tag and its bare-ELF + zip assets; gated since PR #511, 2026-07-16)

Change Discipline

Safety Rules

Build / Test Reality

Gotchas / Footguns

High-value traps that have actually burned agents in this repo. Verify the unit/binding from the toolchain or source, never from assumption.

Testing Expectations

Documentation / Evidence Discipline

When updating status after changes:
- STATE.md is canonical for runtime state, invariants, preservation contracts, the known-issues list, and hardware status; the other root docs (README, this file, ROADMAP, DECISIONS) point there instead of duplicating. Treat QA_REGRESSION_MATRIX.md as the detailed hardware/CI run ledger.
- Hardware pass/fail claims must have a matching QA_REGRESSION_MATRIX.md row with a date and result.
- In-flight / unreleased work is Unknown (verify on hardware) unless explicitly recorded. Do not enumerate stale PR numbers here — for the current in-flight/known-open work list, see STATE.md > Known Open Work (and ROADMAP.md).
- Released changelog entries should not be retroactively edited; new work goes in [Unreleased] at the top of bin/changelog.
- Remove stale branch names, stale feature claims, and outdated decisions.
- Do not silently carry forward old "fixed" claims when the only evidence is a prior chat report. If a regression was reported on hardware, record that result explicitly.

Communication Format

Use this report structure in task responses:
- Summary: what changed and why.
- Diffstat: file-level change summary.
- Diff: key hunks or full patch when requested.
- Test plan: what was run, what passed/failed, and what was not run.

Summary For The Next Agent

POPSLoader's stable backbone (HDD POPSTARTER paths, DKWDRV-MC, BOOT.ELF for USB- and HDD-booted, settings sidecar) is hardware-confirmed in the BETA line. The 2026-06 work — HDD-resident settings save + in-app .hide via the boot-partition RW take-over, PAL native 640×512, the BDMA bdma_mode.txt marker + POPSTARTER-MC-folder toggle/interlock — is implemented and boots on PCSX2, with HDD RW confirmed on hardware (provato) and the full flows still validating on hardware. Your job is most likely: drive doc/feature work, hardware-verify the in-flight HDD/PAL features, complete a queued PR, react to a tester report, or (once D-10/D-14/U-10 and the new features settle) the queued Settings UI redesign. Whatever it is: preserve the contracts in STATE.md, hardware-verify before claiming any new fix, and keep the docs pointed at STATE.md rather than re-duplicating the shared facts.