# P4 server release compatibility `version_compatibility.py` creates a fresh disposable commit-server installation for every selected release/platform pair. The required matrix is P4 **2023.1, 2023.2, 2024.1, 2024.2, 2025.1, 2025.2 and 2026.1** on UBI **8.10 and 9.8**. These release lines come from the vendor's [server schema release table](https://help.perforce.com/helix-core/server-apps/schema/current/). Each cell downloads its own matching `p4`, `p4d`, broker and proxy binaries and verifies their hashes against that release's vendor `SHA256SUMS`, for example [2023.1 x86_64](https://ftp.perforce.com/perforce/r23.1/bin.linux26x86_64/SHA256SUMS) and [2026.1 ARM64](https://ftp.perforce.com/perforce/r26.1/bin.linux26aarch64/SHA256SUMS). The exact patch builds, checksums and immutable image IDs are recorded with the results; this does not test every earlier patch build in a release line. The runner refuses an existing container. Every cell invokes the actual `reset.sh`, `mkdirs.sh` and generated `mkdirs.cfg` with an empty database. It does not downgrade populated databases or rehearse an existing-install migration. Its distro Python 3.12 virtual environment and P4Python are separately labeled; this compatibility matrix does not replace the main source-built Python matrix. The journal is `/p4/1/journals/journal`, storage is local, mail is disabled, and all server endpoints are confined to their container's loopback interface. The temporary restored-database probes disable journaling with `-J off` while comparing data; every installed live server retains the required journal path. Their scratch database is removed only after the daemon has exited. A failed stop or shutdown timeout fails the scenario and retains that scratch directory inside the stopped test container for inspection. Each cell must pass all eight named scenarios: | Scenario | Required behavior | | --- | --- | | `clean_install` | Real clean SDP installation, version-matched binaries and systemd startup | | `service_user_authentication` | Create a native service user, initialize its password under server policy, authenticate and perform a real read | | `exact_fixture` | Independently known text/binary revision bytes, edit/delete/move history, shelf contents and label/client/group specifications | | `restart_preserves_data` | Installed service restart preserves that exact fixture | | `checkpoint_restore` | SDP checkpoint/restore is served separately and its fixture is compared with the original | | `journal_rotation_restore` | A later submitted file and counter survive journal rotation and replay | | `maintenance_queries` | Real inactivity queries, complete path inventory and limit-zero client selection preserve fixture data | | `sendq_cleanup` | Real local configuration scope/identity/path selection, service-down enforcement, dedicated queue cleanup and exact shared partitioned-client have preservation | The cleanup scenario runs the same twenty-four named subcases as the current-server matrix. These cover unset/empty, global/local/other-server settings, relative and absolute paths, root symlinks, missing/non-directory targets, P4NAME environment and database redirects, `-In` precedence, and running-server refusal. Shared readonly overlap in either direction, or a readonly path traversing queue symlinks (including a chain whose configured path starts outside the queue), must preserve every required alias, actual persistent tables and synced partitioned-client have revisions. A queue containing an alias required by the configured database root or by the queue path itself must be refused without removing any queue entries. Queue cleanup runs only while the installed service is stopped; configuration is restored before the next scenario. Missing binaries, setup failures, failed capabilities, missing scenarios or missing matrix cells fail acceptance. A failed prerequisite blocks later dependent scenarios and remains a failed cell. Stopped containers and logs are retained for inspection; remove only explicitly named test containers after reviewing results. Older servers can lack the `p4 diskspace` features used by installer safety checks. The report counts and exposes these skipped checks in `capability_gaps`; passing the data scenarios does not claim that those safety checks ran. Version-gated configurable omissions are recorded there individually with their required and running server versions. Applicable settings must still succeed. Unexpected configuration errors still fail the installation cell, even if the installer exits successfully after logging a warning. ## Images and execution Build the regular UBI images with the [main matrix runner](README.md). On an ARM host, releases 2023.1 and 2023.2 require x86_64 emulation: their vendor ARM64 binary directories are absent. A working Linux `binfmt` emulator is a prerequisite; record it with the results and do not describe emulated tests as native x86 coverage. Build the two x86 package images using the existing definitions: ```bash docker build --platform linux/amd64 -f sdp/test/containers/Dockerfile.rhel8 -t sdp-assurance-rhel8-amd64:8.10 sdp/test/containers docker build --platform linux/amd64 -f sdp/test/containers/Dockerfile.rhel9 -t sdp-assurance-rhel9-amd64:9.8 sdp/test/containers ``` Derive the historical images before starting containers. This masks `systemd-binfmt.service` inside these disposable images, preventing a container boot from resetting the dedicated VM's emulator registration. For each base/tag pair below, run: ```bash docker build --build-arg BASE_IMAGE= -f sdp/test/containers/Dockerfile.versions -t sdp/test/containers ``` | Base | Tag | | --- | --- | | `sdp-assurance-rhel8:8.10` | `sdp-version-rhel8:8.10` | | `sdp-assurance-rhel9:9.8` | `sdp-version-rhel9:9.8` | | `sdp-assurance-rhel8-amd64:8.10` | `sdp-version-rhel8-amd64:8.10` | | `sdp-assurance-rhel9-amd64:9.8` | `sdp-version-rhel9-amd64:9.8` | For the last two derived builds, add `--platform linux/amd64`. The runner pins the resolved image ID. It does not mount host directories, publish ports or expose credentials. The containers run privileged only inside the dedicated test VM. ```bash python3 sdp/test/containers/version_compatibility.py \ --source /absolute/path/to/verified-source-export \ --results /absolute/path/to/new-version-results \ --name-prefix sdp-version-unique-run --jobs 2 ``` A single-cell development run can add `--release 2023.1 --platform rhel8`. `--jobs` defaults to one and permits at most two independent cells. Each uses its own fresh container and result directory. Incremental reports retain every completed cell, and the final report always orders cells by release and platform, regardless of completion order. A tooling failure remains a failed cell while other cells finish. Within one runner, container startup/readiness and shutdown are serialized while provisioning and the test scenarios remain parallel. This avoids overlapping privileged systemd lifecycle operations; it does not diagnose or guarantee a fix for emulator startup failures. Coordinate other runners' container shutdowns and starts separately when investigating such failures. Systemd readiness has a 180-second deadline, longer than the images' normal 90-second unit-start timeout. Only `running` or `degraded` states are accepted; `initializing` and other unfinished states fail at the deadline. A failed boot retains container inspection, console, manager state, pending jobs and failed-unit diagnostics before shutdown. The final release gate still requires all fourteen cells. Do not merge cells from different source exports. `version-compatibility.json` identifies the exact source manifest; each subdirectory retains installation configuration, vendor provenance, worker assertions, server logs and its `case.json`. These fixtures establish specific release compatibility, not production-scale throughput, every historical role combination, network filesystem semantics, upgrade safety or behavior across an entire fleet. Review any failed or blocked cell before expanding the supported claim.