Release v0.4.0 evidence

Release: v0.4.0

Status: Completed

Source reference: unreleased at the time of writing. No annotated tag or frozen branch exists yet. Tagging v0.4.0 and creating release-v0.4.0 remain maintainer steps under section 7 of the release process.

Verification date: 2026-08-04

Required gates

GateCommandResultNotes
Fast./gate.py fast --all-compositionsPassedContained in the audit gate below
Strict./pet.py verify allPassedThe required completion gate for every implementation PBI, run per composition as each one closed
Audit./gate.py audit --all-compositionsPassedFinal release gate, run from a clean tree over headless and desktop-sdl

The audit gate begins with its own clean step, so the release result was produced from an empty build tree rather than from an incrementally reused one. It was run once to collect the evidence below and again after the project version was set to 0.4.0 and the magic rejection test was widened, so the recorded result belongs to the tree that will be tagged.

The first run reported 181 of 184 and 182 of 184 Core branches rather than every one, because the magic rejection test damaged only the last of the four magic bytes and the earlier comparisons never took their failing branch. The test now damages each position in turn, and the recorded run covers every branch.

Release checks

Every row was produced by ./gate.py audit --all-compositions unless noted.

CheckEvidenceResultNotes
GCC build/testIncluded in audit gatePassed12 CTest cases desktop-sdl, 11 headless
Clang build/testIncluded in audit gatePassedSame suites, second toolchain
ASanIncluded in strict or audit gatePassedBoth compositions
UBSanIncluded in strict or audit gatePassedBoth compositions
CppcheckIncluded in fast, strict, or audit gatePassed85 sources analysed
Clang-TidyIncluded in strict or audit gatePassedProject code only, both compositions
FormattingIncluded in fast, strict, or audit gatePassed127 files match the style
Public header self-containmentIncluded in strict or audit gatePassed25 headers desktop-sdl and 23 headless, GCC and Clang
Core boundary symbolsIncluded in strict or audit gatePassedGCC needs nothing external, Clang needs memcpy and memset in 3 objects each, and no Core compile line names a file or allocation dependency
Include boundaryIncluded in fast, strict, or audit gatePassedboundaries.py, 12 boundaries hold over 268 scanned source files
Embedded boundaryIncluded in fast, strict, or audit gatePassedembedded.py, 12 project sources hold the boundary against the ESP-IDF compile database
Component pathsIncluded in fast, strict, or audit gatePassed3 declared components are present
Asset manifest and runtime layoutIncluded in fast, strict, or audit gatePassedassets.py, 1 asset set with 5 manifest references resolving under each build output
Runtime allocation probeIncluded in audit gatePassed0 allocations and 0 memory errors in both compositions
Allocation probe coverageIncluded in strict or audit gatePassedprobe.py, 11 public Core operations exercised, in every composition and toolchain pass
CoverageIncluded in audit gatePassedMeasures src only
ValgrindIncluded in audit gatePassedThe allocation probe reports 0 allocations and the test suite 16 framework allocations, with 0 errors per composition
Composition selectionpython3 tools/tests/test_compositions.py, contained in the gatePassed31 composition tests
Gate selectionpython3 tools/tests/test_gate.py, contained in the gatePassed36 gate tests
Project command entrypointpython3 tools/tests/test_pet.py, contained in the gatePassed32 project command tests
Dependency overridespython3 tools/tests/test_dependencies.py, contained in the gatePassed7 dependency override tests
Verification policypython3 tools/tests/test_verification.py, contained in the gatePassed105 verification tests
Process-level round trippet_headless_round_trip, contained in the headless gatePassedRecorded below
ESP-IDF build proofidf.py set-target esp32 and idf.py buildPassedRecorded below, run outside the hosted gate
Support matrixpython3 tools/verify/matrix.pyPassedRelease-time step rather than a gate step

The five tool suites above run as gate steps and total 211 tests.

Persistence evidence

The Core suite runs 209 tests, of which the save and load suites own 56.

AreaSuiteTestsNotes
Savepet_save20Encoding, capacity, null arguments, and the reported length
Loadpet_load36Round trip, absence, and rejection, of which 20 are rejection tests
Storage contractpet_storage_tests23Dispatch validation, the stdio implementation, and the contract over both implementations
Shared app sequencepet_app_tests10The stage a result came from, over the memory double
Headless apppet_headless_tests24Options, diagnostics, and a whole run over the memory double
Desktop apppet_desktop_tests43Includes a 7 test persistence suite, the wall clock, and the storage diagnostic category

The rejection tests cover wrong magic in each of its four byte positions, an unknown format version, a wrong length, a failed integrity check, out-of-domain activity, expression, name length, and name padding, dwell stamps and an update count beyond the elapsed time, and a candidate that would overflow the world clock. Every one asserts that the destination world is byte for byte untouched.

pet_headless_round_trip runs the headless application to save a world into a real file and again to load it, and asserts that the restored initial snapshot equals the saved final snapshot. A second pair of runs supplies both wall-clock values and asserts an absence of exactly one day reaching the world clock. It then refuses a lengthened payload, a payload of foreign bytes, and a removed payload, so a run that ignored what it was asked to load could not pass. The payload lives under the build directory and is removed, so the check leaves no file in the source tree.

Embedded build evidence

Run from platforms/esp_idf after . "$HOME/.local/opt/espressif/export.sh".

ItemValue
Commandsidf.py set-target esp32 then idf.py build
FrameworkESP-IDF v6.0.2
Toolchainbundled Xtensa GCC 15.2.0, xtensa-esp32-elf-gcc
Targetesp32, derived from the classic T-Display variant
Resultconfigured, compiled, and linked pet_firmware.elf
Imagepet_firmware.bin at 0x1e120 bytes, 88% of the smallest app partition free
Storagecomponents/storage/src/storage.c compiled into libpet_storage.a, defining pet_storage_read and pet_storage_write and no implementation
Boundarypython3 tools/verify/embedded.py --require holds over 12 project sources against that build
Deviceno board was flashed or run

The storage contract is compiled for the target with no implementation selected, which is what LIM-015 records. The firmware application links no storage dependency and keeps no pet across a power cycle, so this is build evidence for the boundary rather than any embedded persistence claim.

Coverage

TargetLine coverageBranch coverageNotes
Pet Core100.0%100.0%299/299 lines, 184/184 branches, measured over src in both compositions, from _reports/coverage

The desktop app, the headless app, the SDL frontend, the firmware app, and the shared components are exercised by their own CTest suites rather than by the Core coverage figure, which measures src alone.

Desktop runtime evidence

Taken from build/linux-gcc-debug-desktop-sdl as the working directory.

CommandResultKind
./apps/desktop/pet_desktop --steps 240 --step-ms 16 --save <path>Exit 0, the reported line unchanged, and an 84-byte payload written at the given pathAutomated process
./apps/desktop/pet_desktop --steps 240 --step-ms 16 --load <path>Exit 0, same reported line, on the real Wayland driverAutomated process
SDL_VIDEODRIVER=x11 ./apps/desktop/pet_desktop --steps 240 --step-ms 16 --load <path>Exit 0, same reported line, on the real X11 driverAutomated process
./apps/desktop/pet_desktop --load <absent path>Exit 1, component=storage operation=storage_read status=PET_STORAGE_MISSING code=1301Automated process
./apps/desktop/pet_desktop --load <damaged payload>Exit 2, component=core operation=world_load status=PET_ERR_INVALID_ARGUMENT code=2501Automated process
pet_desktop observed by the maintainer on Wayland and X11Carried forward from v0.3.0, where the window with the pet drawn in it, a visible greet response to the space key and the left mouse button, a greet settling from the happy expression into the attentive activity, and a clean exit through the window close button and Ctrl-C were all observedManual observation

The five automated rows are the desktop file evidence for the release. They prove that the operator’s path is the only place a payload comes from, that a payload survives the process, and that a missing file and a damaged one separate into the app and Core exit statuses.

Visible rendering and synthesised interaction remain outside automated verification, which LIM-011 records, so the manual row is the only evidence for either. It is carried forward from v0.3.0 rather than repeated by hand, which LIM-011 allows, because nothing in this release touches rendering, the frontend, or input. The five automated rows above prove that the persistence work leaves the lifecycle intact on both real drivers, and the carried row covers what is drawn and what an input device produces.

Support status

EnvironmentStatusNotes
Linux GCCVerifiedBuilt and tested, GCC 16.1.1, plus the real-driver desktop save and load runs
Linux ClangVerifiedBuilt and tested, Clang 22.1.8
Windows MSVCDesignedPresets provided but never executed. The symbol scan and the allocation check cannot run there at all, see LIM-001 and LIM-002. No Windows claim changed in this release, and the storage replacement fallback is unverified there
Embedded, classic T-Display for esp32Cross-compile verifiedConfigured, compiled, and linked through ESP-IDF v6.0.2, with the storage contract compiled and no implementation selected. No hardware runtime claim and no persistence claim, see LIM-012, LIM-013, and LIM-015
Embedded, any other board or targetDesignedNot implemented and not built

Persistence is claimed for the hosted applications only, and only when an operator supplies a path. No automatic save, no automatic load, no save location policy, and no embedded storage is claimed, which LIM-008, LIM-015, and LIM-017 record.

Verified toolchain

ToolVersion
CMake4.4.0
Ninja1.13.2
GCC16.1.1
Clang and clang-format22.1.8
Cppcheck2.21.0
Gcovr6.0
Valgrind3.27.1
GNU nm2.45.0
Python3.13.14
ESP-IDF6.0.2
Xtensa GCC15.2.0

The verification host was Linux x86_64. tools/verify/matrix.py prints the hosted set from the environment it runs in. The ESP-IDF and Xtensa rows come from the embedded build above. The host GCC moved from 15.3.0 to 16.1.1 between v0.3.0 and this release.

Notes

  • The project version in cmake/pet_version.cmake is 0.4.0, and pet_version_string returns it through the generated pet/version.h.
  • No check required for the release failed. The unavailable Windows checks and the absent hardware runtime evidence are recorded as not run rather than passing, and neither is required for this release. The manual desktop observation is carried forward from v0.3.0 under LIM-011 rather than repeated.
  • The full claim-to-evidence mapping is in section 10.5 of the version architecture.
  • This evidence is valid for the commit that will be tagged v0.4.0. If any source changes before tagging, the final required gate must run again against the exact commit to tag.
  • Future fixes require a new commit and a patch release tag, such as v0.4.1.