One `stage` job in release.yml now flattens the artifacts, writes
SHA256SUMS.txt, signs it with the project minisign key
(SHA256SUMS.txt.minisig; public key docs/release-signing.pub once the
maintainer generates it) and attests build provenance for every file with
actions/attest-build-provenance. A `verify-signatures` gate on a macOS
runner then checks each asset against its expected signing state
(scripts/release/verify.sh: macOS Developer ID + notarized, Windows
`unsigned` until #1150 flips one line, AppImage and checksum signatures once
their public keys are committed, attestation on everything), strict on tags
and release/**, warn-only on develop so an outage cannot withhold the core
nightly. Its per-artifact table (signed, notarized, attested) replaces the
signing prose in the release body and the job summary. The macOS and
AppImage signing steps write signing-status sidecars for the facts the gate
cannot re-derive from a file (Apple's ticket on a bare Mach-O).
AppImages: make-appimage.sh passes --sign --sign-key to appimagetool when
VJ_APPIMAGE_SIGN_KEY is set (app-package.yml imports APPIMAGE_GPG_PRIVATE_KEY
into a throwaway GNUPGHOME; the passphrase goes through
APPIMAGETOOL_SIGN_PASSPHRASE). appimagetool 1.9 has no verifier, so
app/packaging/linux/verify-appimage.py re-hashes the image with the
signature sections zeroed and runs gpg --verify.
Installers: tools/install.sh and install.ps1 verify SHA256SUMS.txt's
minisign signature (pinned key) or, with gh, its attestation before
trusting it; a bad one aborts, a release that predates signing warns;
--no-verify / -NoVerify skips the step. Both hermetic suites cover it with
fake minisign/gh. New release-scripts.yml tests the stage/sign/verify
scripts (Linux also signs a real AppImage). A `dry_run` dispatch input on
release.yml runs everything up to the gate on any branch and publishes
nothing.
Docs: key generation and secret commands in app/packaging/README.md
(SignPath "dormant" text removed), release-process.md, SECURITY.md, the
site's Download page (public key once committed), the nightly tracker text,
and the stale "signing service" known-issue line in the v3.11.0 notes.
Closes#1151Closes#1152
Co-Authored-By: Claude Fable 5.1 <[email protected]>
* ci: stop re-running PR-covered workflows on develop pushes; debounce nightly; route macOS to Studio runner
Drop develop from push: in c-cpp, app, regression-test, acid-test, installer,
jaguar-demos, microbench, jaguar-toolchain and cheat-import (PRs already ran
them); ignore develop in pull-request.yml. release.yml's nightly waits 10 min
in its guard job so a merge burst builds once. macOS rows of c-cpp/app/
regression and the unsigned iOS/tvOS nightly rows use the self-hosted Studio
runner on trusted events only, with a VJ_STUDIO_RUNNER=off kill switch.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
* ci(spm): find blitter_simd objects independent of SwiftPM build layout
Xcode 26 SwiftPM keeps objects under .build/out/Intermediates.noindex/...
instead of <triple>/debug/virtualjaguar.build, which broke the vtable check on
the Studio runner. Search by object name and fail loudly if one is missing.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
---------
Co-authored-by: dry <dry@x>
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
test/tools/matrix_diff.py OLD.md NEW.md compares two cart or CD boot
matrices per row. Stage rank (low->high): -1 ?(core_error|build_mismatch|
no_reg), 0 LOAD_FAIL, 1 HARNESS_HANG/?/?(pc_escape|timeout|BIOS band),
2..6 BIOS_INTRO, BOOT_STUB, GAME_CODE, MENU, IN_GAME. At equal rank a new
crash-watchdog signature (from the notes/Watchdog cell) is backward.
Prints regressed / still-asymmetric / improved / added / removed; exits
1 on any backward move, 2 on parse error. test/test_matrix_diff.sh (43
checks) runs in make test. The cart matrix header (generator + doc) now
carries the never-backward rule; docs/release-process.md gains the
pre-tag checklist (regenerate both matrices on the RC on the corpus
machine, diff vs the previous tag, a backward row blocks the tag until
ticketed and deferred, improved list feeds release notes).
Sanity: cart v3.7.0 -> v3.7.1 shows 5 regressed cells (Music Demo BIOS
GAME_CODE -> ?(pc_escape); inframe_hang newly visible on 4 homebrew).
Closes#749
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The version lives in the Makefile, dist/info and src/core/version_fallback.h.
The script compared only the first two; v3.6.1's stale fallback header was
caught by a different CI job ('duplicated lists in sync') instead. Now it
fails naming the fallback file when that one drifts. Verified: passes on
develop (all v3.6.1), fails with exit 1 when the fallback says v3.6.0.
docs/agent/github.md's release step lists all three.
Fixes#734
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ci(pr-issue-link): create the link from a body tag instead of demanding a manual step
Every new PR here went red on creation for a step that cannot be performed
until after the PR exists: the linked-issue check failed, and the fix was a
manual click in the Development panel that does not re-trigger the job.
The premise behind that was stale. This job's own comment -- and
docs/agent/github.md -- asserted "there is no public API to create that
link, so it has to be done in the UI" and "don't burn time on a gh flag or
GraphQL mutation". The mutation exists:
addCloseIssueReferences -- "Adds one or more pull requests as manually
linked closing references on an issue."
That is exactly the Development-panel relationship, and it is idempotent
(verified against PR #641/#632, already linked: re-running changed nothing;
and end-to-end against #642/#633 by unlinking, re-linking from a body tag,
and confirming the result).
So the job now makes the link rather than complaining that nobody did:
* scripts/pr-link-issue.sh <pr> [issue] [--repo o/n] does the work and is
runnable by hand. No issue argument -> scan the PR body for a tag.
Already linked -> no-op, so it is safe to run unconditionally.
* The workflow runs it and only fails when there is no tag to act on. Its
failure summary now says to edit the description, because `edited`
re-runs the job and it links then -- no push required.
Accepted tags, case-insensitive:
Closes#123 / Fixes#123 / Resolves#123 / Refs #123
<!-- link-issue: #123 --> invisible in the rendered body
The hidden form wins over the keywords, so a PR can discuss one issue in
prose and link a different one deliberately. The keywords still do nothing
on GitHub's own side here -- GitHub honours them only when the PR targets
the default branch, which is `master` while PRs target `develop`. They are
markers for this job.
Security: the job runs pull_request_target with a write token, so it checks
out the BASE ref (actions/checkout's default for that event) and never the
PR head -- the script it executes is the trusted copy from the target
branch, not one the PR could have edited. The only untrusted input is the
body, parsed to an integer and validated to be an existing issue (not a PR)
before use. Permissions widened by exactly one: issues: write, which is what
the mutation needs.
Refs #643
* fix(pr-link-issue): ignore link tags inside code blocks
Caught by the feature's own PR. #644 documents the accepted tag syntax with
a fenced example:
Closes#123Fixes#123Resolves#123 Refs #123
<!-- link-issue: #123 -->
The scan matched that example before reaching the real `<!-- link-issue:
#643 -->` at the bottom of the same body, and linked the PR to issue #123 --
a closed OP performance spike with nothing to do with it. Any PR that
explains this feature would have done the same, which makes it exactly the
kind of body the parser has to survive.
Strip fenced blocks and inline code spans before scanning. Anything inside
code is a sample, not an instruction.
Verified: re-running against #644 now yields "PR #644 -> linked to #643",
and a synthetic body with an inline `Refs #111`, a fenced `Closes #222` and
`<!-- link-issue: #333 -->`, plus a real `<!-- link-issue: #444 -->` outside
any code, selects 444.
Refs #643
CLAUDE.md loaded ~10K tokens on every message and into every subagent at
startup. Slim it to load-bearing always-on rules (~2K) plus an index, and
move the catalogs and how-to detail into docs/agent/*.md that load only when
read:
- docs/agent/build.md — build cmds, C89 exempt list, TEST_EXPORTS relink,
build-identity guard, stale-.o hazard
- docs/agent/hardware.md — processor model, memory map, clocks, source
layout, distilled JTRM index
- docs/agent/testing.md — harness catalog, vjtrace, audio-test requirements,
crash-watchdog signatures, acid gating, profiling
- docs/agent/github.md — PR-issue linking, Copilot/Kimi, release process,
site publishing
Safety rules (C89, branch-off-develop, DEVELOPER_DIR, audio-test pair,
PR-issue link, private-ROM / git clean danger, shell-alias trap) stay inline
so no agent can miss them without opening a doc. Removed the duplicated
build-identity-guard block; compressed language to shorthand. No content
dropped — verified the tripwire facts (MMULT fix, PR #170, closingIssues,
ROM-symlink rules) survived the move.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AiMAfypdq7ASvQWK6vQ5hW