# Testing Four layers, cheapest first. Push a check down to the cheapest layer that can hold it — a host self-test runs in milliseconds and cannot wedge a console, which a hardware test very much can. | Layer | Command | Needs | |---|---|---| | 1. Host gate | `npm run validate` | nothing | | 2. Payload build + self-tests | `npm run validate:full` | `PS5_PAYLOAD_SDK` | | 3. Live console | `npm run validate:hardware` | a PS5 with the payload loaded | | 4. Fresh-install matrix | manual, per release | clean VMs | ## Layer 1 — the host gate ```sh npm run validate # or: make quality ``` Runs, and fails on any of: version drift against `VERSION`; script syntax (Node, Bash, Python, and PowerShell when `pwsh` is present); the script inventory audit; `git whitespace` (`git diff --check`); **engine fmt**, **engine clippy** (`-D warnings`) and **engine tests**; **desktop cargo check**, **desktop clippy** and **desktop tests**; **client typecheck**, **client lint**, **client tests** and **client vite build**; and **i18n coverage**. Two of these catch things the others structurally cannot, and both have caught real regressions: - **`engine fmt`** fails on formatting no test exercises. Run `cargo fmt --all` in `engine/` before assuming a failure is real. - **`client typecheck`** covers test files too. Vitest does not typecheck, so a test can pass while calling a function with the wrong argument types. Running a narrower check and assuming the wider one follows is the most common way to burn a cycle here. `npm run validate` is not the whole gate. Before a PR also run: ```sh ( cd client/src-tauri && cargo fmt --all -- --check ) # validate only checks fmt in engine/ ( cd engine && cargo test -p ava1-ctest -- --test-threads=1 ) make test-payload # needs PS5_PAYLOAD_SDK make check-no-ftx2 # the retired protocol must stay gone ``` ## Layer 2 — payload build and self-tests ```sh export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk npm run validate:full # or: make quality-full / make test-payload ``` Builds `payload/ps5upload.elf` and the DPI daemon, checks both are PS5 ELFs with valid gzip resources, then runs every host self-test with `-Wall -Wextra -Werror`: Each self-test lives in `payload/tests/*_selftest.c` (hardware guards, ptrace recovery, `app.db` reading, FTP, SDK param rewriting, installer, cheats, wake watchdog and more). The AVA1 C itself is tested by `ava1-ctest`, which compiles it on the host and checks it against the Rust side (see the full gate below). The SDK version is pinned in `scripts/ps5-sdk.env` (currently **v0.44**) and verified by checksum. Local installers and CI read the same file. To move to a newer SDK release, run `make update-sdk` (or `scripts/update-ps5-sdk.sh [--tag vX.Y] [--check]`). It downloads the release, rewrites the pin and its checksum, refreshes the vendored `prospero-nid` and `payload/third_party/sdk-crt` if upstream changed them at that tag, and installs the SDK into `$PS5_PAYLOAD_SDK` (default `/opt/ps5-payload-sdk`), keeping the old one as a `.backup--