Files
Shipwright/prebuilt/README.md
T
briaguya 9c29824f38 Copy soh.o2r from a checked-in prebuilt archive (TEMPORARY)
Unblocks the rest of the migration. soh.o2r is produced by ZAPD via
OTRExporter/extract_assets.py, both of which this migration deletes; its
replacement is a small in-tree packer that has to reproduce ZAPD's
texture quantisation exactly. Rather than block Phases 2/3/5 on that
packer, check the archive in and make GenerateSohOtr a copy.

The archive doubles as Phase 4's acceptance oracle -- the packer is
correct when its output matches this entry-for-entry -- which is strictly
more useful than Gate E's planned manifest of hashes of it.

Generation turns out to be content-deterministic but NOT byte-
deterministic: two runs give identical payloads for all 1,042 entries but
different file hashes, because zip stores per-entry timestamps. So the
Phase 4 comparison must be entry-wise; whole-file would fail even on a
correct archive. Recorded in prebuilt/README.md.

Adds a configure-time guard on the baked-in portVersion. OTRGlobals.cpp
:283 requires exact major.minor.patch equality and RunExtract exit(1)s
with "soh.o2r is outdated", which is an opaque symptom for a stale
checked-in file; verified the guard fires by building against 9.2.4.

ExtractAssets, CI and copy-existing-otrs.cmake are deliberately untouched
-- ExtractAssets still generates a correct archive while ZAPD exists, and
the CI job keeps working since it just builds this target.
2026-07-25 00:28:53 -04:00

4.2 KiB

Prebuilt soh.o2rtemporary

This directory exists to unblock the Torch migration and is meant to be deleted.

soh.o2r is the port's own asset archive: fonts, textures, presets, translations, shaders — everything under soh/assets/custom/, plus a portVersion stamp. It is built by GenerateSohOtr, which today drives ZAPD through OTRExporter/extract_assets.py. The migration deletes ZAPDTR and OTRExporter, so that producer goes away and its replacement — a small in-tree packer (Phase 4 of torch-migration/PLAN.md) — has to reproduce it byte-for-byte, including ZAPD's specific texture quantisation.

Rather than block every other phase on that packer, the archive is checked in here and GenerateSohOtr just copies it into place. Phases 2, 3 and 5 become testable without the packer existing.

This file also serves as Phase 4's acceptance oracle: the packer is correct when its output matches this archive entry-for-entry. That replaces Gate E's planned sha256 manifest — the artifact is strictly more useful than a list of hashes of it.

Provenance

Generated 2026-07-25
Shipwright branch torch-migration @ fe2f52248
develop at the time c4e92a70f (inputs verified identical — git diff develop HEAD -- soh/assets/custom libultraship CMakeLists.txt was empty)
libultraship submodule c57da1b4
CMAKE_PROJECT_VERSION 9.2.3
Producer cmake --build build --target GenerateSohOtr (ZAPD botr -se OTR --norom)
Size / entries 4,414,957 bytes / 1,042 entries (1,038 checked-in assets + 3 LUS shaders + portVersion)
sha256 1d23b582fbc29cebf803b6ee54856089d0978e5496e6d4b1dbcde876e13cf13c
sha256 of inputs de8ba0b5167bec6956258dd0445d01ac0f6daac84aff091c678d951cc72598f6

The input hash covers every file under soh/assets/custom/ except shaders/, which is not checked in — it is copied out of libultraship/src/fast/shaders/ at generation time. Recompute it with:

find soh/assets/custom -type f -not -path '*/shaders/*' -print0 | sort -z \
    | xargs -0 sha256sum | sha256sum

(-print0/sort -z are required: several preset filenames contain spaces.)

Generation is content-deterministic, not byte-deterministic

Two consecutive runs produce archives with identical payloads for all 1,042 entries but different whole-file hashes — the zip stores a modification timestamp per entry. So:

  • The sha256 above identifies this file, not "any correct archive".
  • Phase 4's acceptance test must compare entry-by-entry, never whole-file. A byte-identical archive is not achievable and not the goal.

What this pins

The archive freezes three inputs. If any changes while this workaround is in place, the checked-in copy is stale and nothing will tell you at runtime except missing or wrong assets:

  1. soh/assets/custom/ — edit an asset and your change is silently ignored. Compare the input hash above.
  2. libultraship's shaderslibultraship/src/fast/shaders/ is copied in at generation time, so a LUS submodule bump can drift the three shaders inside this archive.
  3. The project version. portVersion here is 9.2.3. OTRGlobals.cpp:283 requires exact major.minor.patch equality against the build's version, and RunExtract calls exit(1) with "soh.o2r is outdated" if it fails. A configure-time check in the root CMakeLists.txt catches this and tells you to regenerate, because the runtime symptom is not obvious.

Regenerating

From a tree where ZAPDTR/OTRExporter still build (i.e. develop):

cmake --build build --target GenerateSohOtr
cp soh.o2r prebuilt/soh.o2r

Then update the provenance table above.

Removing this

When Phase 4's packer lands and its output matches this archive entry-for-entry, delete this directory, drop the !prebuilt/soh.o2r negation from .gitignore, and restore GenerateSohOtr to a real build step (including the libultraship shader copy, which the copy-only version skips).

Delete it before the migration PR merges if at all possible. It is a 4.4 MB binary, and a blob that reaches develop is in the history permanently; removed in the final tree and squash-merged, it never lands there at all.