v0.4.2's first run created the draft with gh release create, then looked its
id up in the release list, which didn't show the fresh draft yet; the PATCH
went to releases/ (404) and the builds were skipped. Now the draft is POSTed
and the id read from the response, after checking the tag exists on GitHub
(what --verify-tag guarded). A rerun still reuses the draft found by tag_name,
and an empty id stops the job instead of PATCHing releases/.
tests/test_release_workflow.py runs the step against tests/fakegh, which now
answers POST releases and applies --jq through jq when installed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
electron-builder's 7-Zip compresses a bare arm64 ELF with its ARM64 branch
filter (method 0A), which the NSIS installer's extractor can't decode and
silently skips. Every installed Windows copy (0.4.0, 0.4.1) lacked
libXrApiLayer_FRAME_compat.so, so VR APK installs failed instantly.
- Commit and package the library as libXrApiLayer_FRAME_compat.so.gz
(byte-identical when decompressed; SHA-256 checked against the README);
frame_android decompresses it, and a corrupt file counts as missing.
- build.sh writes the .gz.
- check-resources.js also runs from the command line against an installed
copy, comparing every file with the unpacked build.
- release.yml: the Windows job installs the NSIS installer silently and runs
that check.
- Tests: no bare ELF under prebuilt/, packaging filter ships only the .gz.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
publish-release.sh took update.json's "page" from the draft's url, which is
releases/tag/untagged-... and dies on publishing; 0.4.0's manifest shipped
that dead link. It also looked the draft up with `gh release view <tag>`,
which reports "release not found" while a draft's tag_name still reads
untagged-... (and uses rate-limited GraphQL).
- publish-release.sh: REST only. Checks the tag exists, finds the release by
tag_name or else the one untagged draft titled "Frame Control X.Y.Z",
keeps the 8-installer digest check, replaces update.json via the uploads
API, then PATCHes tag_name/draft/prerelease/make_latest. Adds --dry-run.
- updater.js: trust only this repo's releases/tag/<tag> pages (never
untagged-...); otherwise link to releases/tag/v<version>.
- release.yml: one draft job before the matrix (no racing creates), with
--verify-tag and tag_name set explicitly.
- Tests: tests/test_publish_release.py with a stand-in gh (tests/fakegh/gh),
and an updater test for the page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>