Skip to content

developers

github-actions[bot] edited this page Oct 26, 2026 · 10 revisions

Developer and Documentation Maintenance

Keep source behavior, user instructions, CI contracts, release packaging and third-party attribution synchronized.

Developer guides

Source of truth

The public site is generated from docs-site/content/*.html plus docs-site/manifest.json by docs-site/build.py. docs/wiki/*.md contains the version-controlled, wiki-style guide set, and the Synchronize GitHub Wiki workflow mirrors it, the site pages and docs/THIRD_PARTY_CREDITS.md into the repository wiki without deleting unmanaged pages. Do not hand-edit the generated gh-pages branch or the wiki: the publishing workflows replace them. Pages are HTML fragments (no <html> wrapper); give every h2/h3 an id so it appears in the table of contents and search, and reuse the existing callout, matrix, tree and table markup.

Build at a glance

Release builds use the PS2BUILD SDK and its LLVM/Clang toolchain, exactly as CI does. After installing the SDK (ps2build update, ps2build update llvm-toolchain):

bash scripts/build_cloud_tls.sh      # Mbed TLS 3.6.7 for the active toolchain
bash scripts/build_jpeg.sh           # libjpeg-turbo 3.1.3 for the active toolchain
python3 scripts/gen_cloud_client.py  # Google OAuth client header (from env, optional)
python3 scripts/gen_githash.py --require-git
ps2build build                       # -> build/bin/wLaunchELF-packed.elf

python3 scripts/configure_ds34.py # DualShock variant ps2build build -c .ps2-ds34.yaml -o build-ds34

The full procedure, including the verification scripts, packaging, tests and GCC comparison builds, is on Building from Source and in docs/BUILDING.md.

Build and validate the documentation

python3 docs-site/build.py --out site --zip Launchstation-Documentation.zip

The generator checks the page inventory, unresolved template fragments, site assets, images, stale upstream branding outside Credits, and internal HTML links before writing the offline archive. A page that exists in content/ but not in the manifest is not built (though the wiki sync still publishes it), and a manifest entry with no fragment fails the build. python3 tests/test_wallpaper_docs.py and tests/test_project_branding.py guard the theme guide and the project identity strings.

Main CI gates

.github/workflows/compile.yml runs on every push to master/main, every pull request and manual dispatch:

  • More than a hundred compiled or source-contract regression tests (device/USB/PAD timing, navigation, settings, MMCE backup and recovery, cloud, updater and release-workflow safeguards, storage drivers, PC CARD CF, UDPFS). The list is explicit in the workflow.
  • Documentation site build, then the SDK install and update.
  • Mbed TLS and libjpeg-turbo cross-builds, the Google client header, and the isolated PC CARD CF driver.
  • Standard and DS34 cross-builds with check_ds34_build.py (variant symbols), check_toolchain_purity.py (Clang-only objects), check_udpfs_smap.py (source-built SMAP and bundled peer ABI) and check_loader_layout.sh (embedded loader fits 0x84000..0xa0000).
  • Package generation and verification, copy-test fixture upload and artifact hashes.

Hardware-only timing, USB bridge behavior, console model quirks and external game-core interaction remain separate from automated acceptance.

Rolling release and Pages

A verified push to master publishes APP_LAUNCHSTATION.psu/.zip, APP_LAUNCHSTATION-DS.psu/.zip and the loose LAUNCHSTATION.ELF, LAUNCHSTATION-DS.ELF, BOOT.ELF and BOOT2.ELF to the rolling latest release. The step skips superseded builds, refuses to move the latest tag unless the old commit is an ancestor of the new one, uploads, downloads the assets back and compares them byte for byte, and only then moves the tag and marks the release Latest. Release notes come from scripts/release_notes.py, which prefers the ## Rolling section of CHANGELOG.md and adds first-parent merge links when that text did not change. The documentation workflow builds from the same source and publishes gh-pages whenever docs-site/** changes on master. A docs-only commit therefore produces a new rolling build without implying runtime behavior changed.

Native updater

Check for updates (Settings > Storage & devices > MMCE backups) queries the GitHub API for the latest release, reads the SHA-256 digest GitHub reports for this variant's PSU (APP_LAUNCHSTATION.psu or APP_LAUNCHSTATION-DS.psu, chosen at compile time), and asks GitHub to compare the installed commit with the release commit. Only a release that is strictly ahead is offered; same, behind, diverged or unverifiable results are not installed. On confirmation it downloads the PSU (at most 16 MiB, up to six HTTPS redirects) to <ELF>.PACKAGE, verifies the digest, extracts the ELF to <ELF>.UPDATE, checks that it is a PS2 ELF, restores a missing WLE-UPDATE-CA.PEM or BGM.ADP from the package (never overwriting existing files), renames the running ELF to <ELF>.BAK, moves the new ELF into place, and rolls back automatically if that last rename fails. Stale .PACKAGE/.UPDATE files stop the update until handled manually. In-place update is supported for ELFs on mc, mass/usb, mmce, mx4sio, ilink, ata and hdd paths. See Downloads.

Runtime architecture

Neutrino uses an already mounted backing-store stack for quick-boot, while Ember's USB path first performs a controlled clean IOP storage-stack rebuild and remounts the same game identity before its final keep-IOP launch. Neither follows the ordinary ELF reset preference. Local MMCE history is verified before optional Drive upload. See Architecture & Repository Layout.

Building the Google client into a build

Official builds embed the project's own Google OAuth client. CI passes the repository secrets WLE_GOOGLE_CLIENT_ID and WLE_GOOGLE_CLIENT_SECRET to scripts/gen_cloud_client.py; forks and local builds without them have no built-in client, and users must supply their own in WLE-CLOUD.CNF (Advanced setup). To create a client for your own builds:

  1. In Google Cloud console create a project (no billing account is required) and enable the Google Drive API.
  2. Configure the OAuth consent screen as External with only the https://www.googleapis.com/auth/drive.file scope.
  3. Set the publishing status to In production. drive.file is a non-sensitive scope, so no verification review is needed; apps left in Testing work only for listed test users and Google revokes their refresh tokens after 7 days.
  4. Create an OAuth client of type TVs and Limited Input devices, then export WLE_GOOGLE_CLIENT_ID and WLE_GOOGLE_CLIENT_SECRET (or add them as repository secrets) before running gen_cloud_client.py.

Google does not treat installed-device client secrets as confidential; keeping them out of git only stops forks from reusing the project's quota by accident. The values are compiled into the ELF. Never commit the generated header or any WLE-CLOUD.TOK. See docs/NATIVE_CLOUD.md.

Claude Code cloud sessions

A SessionStart hook in .claude/settings.json runs .claude/hooks/session-start.sh in Claude Code cloud sessions. It installs the PS2BUILD SDK and LLVM toolchain with the same installer and retry options as CI, runs ps2build update and update llvm-toolchain, and exports PATH, LLVM_BIN and PS2BUILD_TOOLCHAIN=llvm, so a fresh session can build and test immediately. It does nothing outside cloud sessions.

Developer aids

Defining DASH_AUTOTEST in the wLaunchELF target's defines replays a scripted button sequence and seeds a sample library for emulator screenshots, and DASH_THEME_TOUR cycles every theme preset; neither belongs in a release. See docs/dashboard.md. make stale-audit (legacy Makefile) writes build/stale-code-report.txt with stale markers, disabled blocks and the largest files; CI does not run it.

Attribution discipline

Every external project mentioned in READMEs, site pages and guides must appear in Credits with its role identified. Update the attribution inventory when vendoring modules, incorporating sources or adding external handoff targets. Preserve each original file-level license; a reference is not the same as a redistributed component.

Clone this wiki locally