Commit Graph
16 Commits
Author SHA1 Message Date
James Dansereau 3dcceaafd9 ci: route windows-build to self-hosted runner (G2); land ROM-gated sweep workflow (G1) (#65)
* ci: route windows-build to self-hosted runner (G2); land ROM-gated sweep workflow (G1)

G2: windows-build now runs on the self-hosted box (corpyvt6agent01) for
push/workflow_dispatch, using local ccache instead of the actions/cache
round-trip and skipping msys2/setup-msys2's install once packages are
already present. pull_request always stays on windows-latest — fork PRs
must never reach a box that will hold a ROM.

G1: adds .github/workflows/selfhosted.yml, a dispatch-only workflow that
builds + runs the 21-level headless sweep (tools_pc/verify.sh sweep --json)
against a runner-cached ROM. Inert until manually dispatched.

Still pending (manual, physical steps on the box — not done by this
commit, see docs/dev/notes/SELFHOSTED-RUNNER-PLAN.md rollout table):
- register corpyvt6agent01 as a runner against this repo
- confirm MSYS2 at C:\msys64 with the required mingw64 package set
- one-time ROM seed into {runner_home}/_rom-seed/
- first workflow_dispatch sweep + parity check against a local run
- flip G1 from workflow_dispatch to push:[main] once green

Claude-Session: https://claude.ai/code/session_01J5PZ3sTHiuW6MdQnepasSU

* fix(selfhosted.yml): remove invalid concurrency.max-parallel key

Found by testing: dispatching the workflow failed with a hard parse
error (HTTP 422, "Unexpected value 'max-parallel'"). GitHub Actions'
workflow-level `concurrency` block only supports `group` and
`cancel-in-progress` — `max-parallel` is a job `strategy:` key for
matrix jobs, not a concurrency-block key. Serialization was already
achieved via group + cancel-in-progress:false; the stray key just
blocked every dispatch.

Claude-Session: https://claude.ai/code/session_01J5PZ3sTHiuW6MdQnepasSU

* fix(selfhosted.yml): register the msys2 shell wrapper (setup-msys2 step)

Found by testing: the first fixed dispatch failed every msys2-shell step
with "msys2: command not found". Unlike ci.yml's windows-build, this
workflow used `shell: msys2 {0}` without ever running msys2/setup-msys2,
which is what registers that shell alias for the runner — MSYS2 being
pre-installed on the box doesn't help if Actions doesn't know the shell
exists. Adds the same setup-msys2 step ci.yml uses, with update:false
since the packages are expected already present (fast no-op per plan).

Claude-Session: https://claude.ai/code/session_01J5PZ3sTHiuW6MdQnepasSU

* ci: stop reinstalling MSYS2 per run on the self-hosted box

The self-hosted paths (selfhosted.yml; ci.yml windows-build's push/
dispatch route) no longer call msys2/setup-msys2 or pacman -S at all.
MSYS2 + the mingw64 package set are now assumed hand-maintained on
corpyvt6agent01 (docs/dev/notes/SELFHOSTED-RUNNER-PLAN.md), invoked by
calling its bash directly (`C:\msys64\usr\bin\bash.exe -leo pipefail
"{0}"`, the same invocation setup-msys2's generated wrapper uses) with
MSYSTEM=MINGW64 so /etc/profile still puts mingw64/bin on PATH.

Adds tools_pc/check-selfhosted-deps.sh: a fast, install-free check that
exits 0 immediately when the required packages (toolchain, cmake,
SDL2, zlib, python, ccache, zip, unzip) are present, or fails with the
exact `pacman -S --needed ...` line to run otherwise — so a missing
package on the box surfaces immediately with a clear fix, instead of
as a confusing failure deeper in the build.

ci.yml's windows-latest (PR) path is unchanged: ephemeral runners still
get a full msys2/setup-msys2 install every time, since there's nothing
to persist there.

Claude-Session: https://claude.ai/code/session_01J5PZ3sTHiuW6MdQnepasSU

* fix: use msys2/setup-msys2 release:false instead of a raw bash-path shell

The previous attempt (invoking C:\msys64\usr\bin\bash.exe directly as a
custom `shell:` command) failed on the actual runner with "Second path
fragment must not be a drive or UNC name" — a real limitation, not a
typo; it failed identically in both files, including the one with a
static (non-templated) shell string, so it wasn't the ${{ }} expression
either.

Root-caused by reading msys2/setup-msys2's actual source: `release:
false` makes it reuse the existing C:\msys64 as-is (hardcoded path in
that branch, confirmed in main.js) instead of downloading+installing a
fresh copy, and — verified in the same source — omitting `update` and
`install` skips every pacman call entirely (just one `uname -a` + a
pacman.conf sed tweak, no network). This is the officially documented
mechanism for self-hosted runners with a pre-existing MSYS2 install
(see the action's README, "release" section).

ci.yml's windows-build now runs setup-msys2 unconditionally but with
release/update/install all keyed off github.event_name: full install on
windows-latest (PR, ephemeral), reuse-only on the self-hosted box
(push/dispatch). selfhosted.yml always uses release:false. Both then
run tools_pc/check-selfhosted-deps.sh to verify the box's hand-
maintained packages are actually present.

Claude-Session: https://claude.ai/code/session_01J5PZ3sTHiuW6MdQnepasSU

* fix(selfhosted.yml): cp -r for the ROM sidecar directories

Found by testing with the ROM seed actually in place: pcmodels-ntsc-final
and pccg-ntsc-final are directories (not single files, unlike
ge007.ntsc-final.z64), so a plain `cp` failed with "omitting directory"
and left the seed step failing on every run even with the seed populated.

Claude-Session: https://claude.ai/code/session_01J5PZ3sTHiuW6MdQnepasSU

* ci: drive MSYS2 MINGW64 directly via ci-shell.cmd, drop msys2 shell shim

The self-hosted runs were dying with 'msys2: command not found' because the
msys2/setup-msys2 action's shell shim was never registered on the box. Replace
the dependency on that shim with a small committed launcher (tools_pc/ci-shell.cmd)
that headlessly reproduces the local 'MSYS2 MINGW64' terminal:

  - MSYSTEM=MINGW64 + /mingw64/bin on PATH
  - NON-login bash, so it keeps the workspace cwd (a login shell cd's to $HOME
    and would break every relative path in the workflow)
  - -e -o pipefail for GitHub-style error propagation

Both workflows now set defaults.run.shell to C:\msys64\ci-shell.cmd {0}; a
bootstrap step (shell: cmd) refreshes the launcher from the repo into C:\msys64
each run. selfhosted.yml drops setup-msys2 entirely; ci.yml keeps it only for
the ephemeral windows-latest PR path (which installs MSYS2 at C:\msys64).

.gitattributes: force CRLF for *.cmd so cmd.exe parses the launcher correctly.

* Revert "ci: drive MSYS2 MINGW64 directly via ci-shell.cmd, drop msys2 shell shim"

This reverts commit a976b2589c.

* docs(D244): log self-hosted-runner link failure — undefined reference to objectiveGetStatus_WEAK

First real build attempt on the reinstalled corpyvt6agent01 box (run
34707798707) fails at link with an unresolved #pragma weak alias. A local
repro of the identical alias pattern links fine on current MSYS2
(gcc 16.2.0/binutils 2.47); the box reports gcc 16.1.0 — likely a stale
toolchain, consistent with rollout step 2's earlier package-hygiene gap.

Claude-Session: https://claude.ai/code/session_01CUFSnpgrAyQSDVHoQQ6Sx3

* fix(verify.sh): surface run.log tail on NO-FRAMES instead of silently discarding it

sweep mode's per-level run.log (the game process's own stdout/stderr, where
an SDL/GL init failure would show up) was captured into a mktemp capdir but
unconditionally rm -rf'd with no diagnostic ever printed for the NO-FRAMES
(no-crash) case -- every level failed this way on the self-hosted runner's
first real sweep attempt with zero clue why.

Claude-Session: https://claude.ai/code/session_01CUFSnpgrAyQSDVHoQQ6Sx3

* fix(selfhosted.yml): stop deleting the ROM seed dir -- cache save silently fails on this box

actions/cache/save has been failing to persist the ROM cache entry on
corpyvt6agent01 (WARNING annotation, tar.exe exit code 2) but doesn't fail
the step -- by design, a cache-save failure is non-fatal, so the workflow
carried on and the now-unconditional "Delete one-time seed dir" step wiped
the only copy of the ROM every single run. Every dispatch since has failed
at "Seed ROM cache" with an empty seed dir and an empty cache -- exactly
the user-reported "it wipes out the ROM data each run".

Fix: don't delete the seed dir. It's cheap disk (three files, a few hundred
MB) and the existing restore-then-seed-if-missing logic already treats it as
the fallback source whenever the cache comes back empty, so leaving it in
place is safe and makes the workflow tolerant of the cache-save bug until
that's root-caused separately.

Claude-Session: https://claude.ai/code/session_01CUFSnpgrAyQSDVHoQQ6Sx3

* fix(verify.sh): sweep --json never actually produced a verdict array; fix NO-FRAMES diagnostic clipping it further

Two bugs, found together while chasing the self-hosted runner's first real
sweep attempt:

1. sweep mode's `out=$(verify_level ...); echo "$out" | head -1` always
   discarded emit_verdict's second (--json) output line -- RESULTS_JSON was
   declared for assembling a verdict array but never populated or printed,
   so `sweep --json` has never produced anything but `[]` for the
   workflow's "Extract JSON verdict" step. Now builds and prints a real
   `[{...}, {...}]` array before the RC exit.

2. My own D244-session addition (printing a NO-FRAMES level's run.log tail)
   wrote to stdout, which the same `out=$(...)/head -1` capture turned into
   the *new* first line, clipping the real verdict summary. Moved to stderr,
   which bypasses that capture.

Claude-Session: https://claude.ai/code/session_01CUFSnpgrAyQSDVHoQQ6Sx3

* docs: regenerate findings-index.csv for D244

Claude-Session: https://claude.ai/code/session_01CUFSnpgrAyQSDVHoQQ6Sx3
2026-09-12 15:33:07 -04:00
James Dansereau 646798be56 docs(M-102): fix findings-index false-positive, release <version> bug, land parked site cleanup (#53)
* docs(M-102): fix findings-index false-positive, release <version> bug, land parked site cleanup

Docs triage pass (docs/dev/notes/PROMPT-docs-triage-session.md).

- gen_findings_index.py: D194's row was silently bucketed FIXED (an open
  design item) because it had no distinct status cell, so the generator's
  fallback keyword search matched "fixed" somewhere inside 6,500 chars of
  narrative -- the same misleading-index failure mode that cost a session
  on D227 (see docs/dev/findings.md SS H "D227 -- M-98"/"M-99"). Gave D194
  a real status cell. Also extended LEAD_RE/bucket() with 5 verdict tokens
  already in use in the doc (ANALYZED, GUARDED, DIAGNOSTIC SHIPPED,
  ROOT-CAUSED, NOT A BUG) and added a leading verdict word to 4 more rows
  that had a status cell but no recognized token -- fixes all 10 rows the
  generator previously bucketed "?" (D175 D174 D173 D220 D160 D133 D136
  D156 D153, plus D194). findings-index.csv regenerated; --check passes;
  diff reviewed, only these 10 rows moved.
- ci.yml: release-notes.md's <version> placeholders were never substituted
  before `gh release create --notes-file`, so every published release body
  (including the live v0.1.0 release) ships the literal text. Now sed'd to
  the tag first.
- Landed docs/dev/notes/UNLANDED-docs-site-cleanup-steps3-5.{md,patch}
  (parked M-101, never pushed, branch deleted): deletes the orphaned
  docs/StructureGuide.md (0 tracked references), adds title/description
  frontmatter to 5 published Pages docs, rewrites docs/index.md's stale
  "Phase 2 of 4 / no audio yet / 19-of-21" status text to match the
  current README. The 2 files whose hunks no longer applied via `git am`
  (docs/index.md, docs/dev/agentic-development.md) were redone by hand
  against current main.
- docs/BACKLOG.md (local, gitignored): retargeted a dead
  docs/PORT-LEARNINGS.md reference to docs/porting-notes.md.

Larger triage items (findings.md monster-row convention, full
status-accuracy sweep, duplicate-defect clustering, dev-notes plan
triage, HANDOFF rotation policy) scoped but not started -- see
docs/dev/notes/FOLLOWUP-docs-triage-session.md (gitignored).

Claude-Session: https://claude.ai/code/session_016TaKy6AAsVUTfjkhrX6CjG

* docs/index.md: fix stale in-level-music claim before merge

This PR predates the M-102c/M-105 correction (already landed in the
README via PR #55): in-level music is NOT absent, it plays with some
tracks having wrong-sounding instruments / occasional garbling (D77
fixed, D230 filed for the residual). This branch's own rewritten Status
paragraph still said music 'doesn't yet' play -- fixing it to match
before merge so main doesn't briefly regress to a stale claim this
session already corrected elsewhere.
2026-09-12 09:33:54 -04:00
James Dansereau 226f0490cb ci: add ccache to Linux + Windows build jobs (speed-ups plan Step 5)
CMakeLists.txt already opt-in enables CMAKE_{C,CXX}_COMPILER_LAUNCHER=
ccache when found (b49907de); CI just never installed ccache or persisted
its cache dir across runs. Wires actions/cache + ccache install into both
linux-build and windows-build, keyed on CMakeLists.txt's hash. Game
sources are frozen, so this should give a near-total hit rate after the
first run on each job.

YAML-validated; the actual hit-rate payoff needs a real CI run (cold, then
warm) to confirm -- not verifiable locally.

Claude-Session: https://claude.ai/code/session_01P3WrUHAFQZUuhrHhiJgTUr
2026-09-04 22:10:41 -04:00
James Dansereau dbea5a30fe chore(agentic): speed-ups plan Steps 1, 4 (N2/R8/R9), 6
Static/tooling slice of docs/dev/notes/AGENTIC-SPEEDUPS-PLAN.md — no build or
runtime environment needed to verify any of it.

- Step 6 / N7: add a VERIFY: line to the investigation-brief template
  (docs/dev-process.md) and the CLAUDE.md dispatch-preflight checklist — the
  brief must now name the exact probe/verify invocation that proves the task
  done, or state that runtime verification is impossible here.
- Step 4 / N2: tools_pc/README.md — indexes the ~60 scripts with a
  living vs artifact marker so closed-finding artifacts can be archived.
- Step 4 / R8: tools_pc/gen_findings_index.py -> docs/dev/findings-index.csv
  (label, bucket, one_liner, status_raw) — grep-before-you-read aid for the
  ~200 KB finding log. Heuristic parser of the §F/§H tables.
- Step 4 / R9: tools_pc/gen_env_probes.py — re-greps live getenv("GE_*")
  sites and reports NEW/GONE drift vs docs/dev/GE-ENV-PROBES.md (keeps the
  curated prose, only checks the site map). Doc reconciled: 7 new probes
  added, GE_D54 kept as a tombstone.
- CI: validate job now runs both generators with --check.

Step 1 / N1 (HANDOFF preflight) applied in the local-only docs/HANDOFF.md.
Step 2 (verify.sh) and the HANDOFF/HANDOFF-ARCHIVE trim are left for a
session with a build environment.
2026-09-04 19:21:35 -04:00
James Dansereau fcc23dd584 Merge pull request #17 from jkdansereau/release/v0.1.0-alpha-dual-platform
release: Linux x86-64 bundle + dual-platform alpha release notes
2026-09-03 12:13:32 -04:00
James Dansereau a0611727e9 release: add Linux x86-64 bundle + dual-platform release notes
- tools_pc/bundle-linux.sh: package a Linux build (exe + README + licenses +
  prepare-assets) as a .tar.gz. Mirrors bundle-win.sh's ROM / size guards and
  prepare-assets assembly. No shared libs bundled — the generated README tells
  the user to install SDL2 / zlib / libGL from their distro.
- tools_pc/dist/README.md.in: made OS-neutral via @PLATFORM@ / @EXE@ / @DEPS@ /
  @LICENSE_EXTRA@ tokens; refreshed the known-issues list (dropped the stale
  "ladders don't work" line — D177 fixed M-36; added black sky + missing HUD
  weapon icon).
- .github/workflows/ci.yml: linux-build now packages + uploads the Linux
  bundle; the release job attaches both platforms to the draft pre-release.
- .github/release-notes.md: rewritten for the two-platform NTSC-U alpha with
  the prepare-assets step and current known issues.

Alpha scope: NTSC-U only, one-time prepare-assets step (Part A launcher and
Part B native converter from release-dropin-rom-plan.md remain follow-ups).

Claude-Session: https://claude.ai/code/session_01V4pK3pT83YnPsBp3Ey4RP2
2026-09-03 10:54:06 -04:00
James Dansereau e886b970d7 ci: make docs-only PRs mergeable
Drop `paths-ignore` from the `pull_request:` trigger. With it, a docs-only
PR never triggered the workflow, so the required `validate` / `windows-build`
checks stayed "expected" forever and the PR could not be merged without an
owner bypass (M-44 hit this on #14/#15).

The workflow now always runs on PRs; the `changes` job diffs the PR against
its base sha (mirroring the existing branch-push logic against
`github.event.before`) and, for a docs-only change, reports the build jobs
as skipped — which branch protection accepts as success.

Claude-Session: https://claude.ai/code/session_01V4pK3pT83YnPsBp3Ey4RP2
2026-09-03 10:41:41 -04:00
James Dansereau 05b89374e8 Merge branch 'main' into feat/linux-ci-compile 2026-09-03 00:13:40 -04:00
James Dansereau 12c3941fd3 linux-build: -fplan9-extensions for the 'inherits' idiom; pin gcc-14
- src/bondtypes.h's `#define inherits struct` makes the base an unnamed
  tagged member and reads its fields directly. mingw32 GCC enables this via
  implicit -fms-extensions; native GCC does not -> "'ObjectRecord' has no
  member named 'type'". Add -fplan9-extensions (C only) for non-MinGW.
- Pin the CI job to ubuntu-24.04 + gcc-14 so the first Linux bring-up chases
  real portability gaps, not old-GCC pedantry (dev toolchain is GCC 16).
2026-09-02 21:36:15 -04:00
James Dansereau 4e49f11813 ci: add Linux (Ubuntu/GCC) compile job
validate only CMake-configures on Ubuntu; it never compiles, so GCC-on-Linux
strictness gaps (implicit declarations, -Wint-conversion, missing includes,
MinGW-only builtins) stay invisible until someone builds on a real Linux box.

Add linux-build: system GCC, `cmake --build` for ntsc-final. Green here means
"compiles + links on Linux", not a runtime claim (the port has never run on
Linux). Not wired as a required check yet.

Pairs with the romdata POSIX mmap patch on this branch (per docs/dev/LINUX-PORT.md).
2026-09-02 21:15:47 -04:00
James Dansereau ce9e090527 ci: skip build on docs-only pushes to main
The pull_request trigger already has paths-ignore (**.md, docs/**,
LICENSE, NOTICE), but push to main deliberately has none so tag builds
always run and the required check never hangs pending. A docs-only merge
to main therefore still ran a full ~15 min Windows build for nothing.

Add a lightweight 'changes' job (pure git diff against github.event.before,
no third-party action) that mirrors those globs. validate + windows-build
now gate on needs.changes.outputs.code == 'true'; the job forces true for
tags and for pull_request / workflow_dispatch, so only docs-only branch
pushes are skipped. Skipped required checks report green to branch
protection.
2026-09-02 20:21:06 -04:00
James Dansereau def0e0ac56 release: Windows alpha bundle pipeline
- tools_pc/bundle-win.sh: package a Windows build for distribution — exe +
  MinGW/SDL2/zlib runtime DLLs + README + license texts, into
  dist/goldeneye-pc-port-<ver>-win64/{,.zip,.zip.sha256}. Hard-fails if a
  ROM image or an oversized blob lands in the bundle; verifies the DLL
  closure with ldd.
- tools_pc/dist/README.md.in: the bundled README template (ROM-supply
  instructions, run steps, controls, legal), @VERSION@-substituted.
- CI: build tag trigger (v*); windows-build now packages the bundle every
  run and uploads it; new release job (tags only, contents: write scoped
  to it) attaches the bundle to a DRAFT pre-release for a human to
  smoke-test and publish.
- README: Download section + Legal reworded to cover pre-built binaries
  (engine only, no game data, permissive runtime libs bundled with their
  licenses).
- .gitignore: /dist/ (root bundle output; tools_pc/dist/ template stays
  tracked).

Cutting a release: tag vX.Y.Z-alpha, push; CI builds + drafts the
pre-release; smoke-test with a ROM, then Publish.

Claude-Session: https://claude.ai/code/session_01GULf6knbsqfsnW39tMr9WT
2026-09-02 00:44:54 -04:00
James Dansereau 0c2673f636 CI: bump actions/checkout and actions/upload-artifact v4 -> v7
Latest majors; clears the pending Dependabot bumps so the repo goes
public with a clean slate. setup-msys2@v2 is current.

Claude-Session: https://claude.ai/code/session_01GULf6knbsqfsnW39tMr9WT
2026-09-01 22:54:26 -04:00
James Dansereau 4ca11e4386 Prepare repository for public release
- README: attract-mode stills + demo GIF as the hero row, status/warning
  callouts, metrics table, "Contents" index, doc-index table; simplified
  the two-agent workflow diagram (LR -> TD, fewer edges) for GitHub web
- Table-of-contents indexes added to internals.md, porting-notes.md,
  agentic-development.md, AUDIO-PLAN.md
- CI: add Windows/MSYS2 build job, minimal token (contents: read),
  persist-credentials: false, concurrency group; run on main + master.
  validate job regenerates the US ROM-asset symbol file only and configures
  ntsc-final (PAL/JP need a region ROM; no ROM is used in CI)
- .github: SECURITY.md, issue forms + chooser config, PR template,
  labels.yml, dependabot (Actions, monthly)
- Do not track the proprietary SGI IRIX IDO toolchain or SGIImageViewer.exe;
  document in SetupGuide.md / building.md how to obtain IDO for N64 ROM
  builds (the PC port does not need it)
- Stop tracking two committed *.pyc files; drop stale screenshots and a
  redundant .gitignore line; misc doc cross-reference fixes

Claude-Session: https://claude.ai/code/session_01GULf6knbsqfsnW39tMr9WT
2026-09-01 22:42:52 -04:00
James Dansereau 81f02c7d3a docs: honesty pass on status + platform claims
- README: "not playable yet" callout under the screenshots (no audio,
  broken front-end models/text, expect crashes past the level intro).
- README/building.md/ci.yml: platform testing is Windows-only. The Linux
  build is provided but has had zero functional testing at runtime; the
  CI job is a CMake-configure smoke test, not a Linux-support claim.

Claude-Session: https://claude.ai/code/session_01UpTM1AcBRJuTetoZNcCD5V
2026-09-01 19:43:40 -04:00
James Dansereau 52539d10de Prepare for public release
- README, LICENSE (MIT for the port layer), NOTICE, CONTRIBUTING.
- Restructure docs: internals.md, porting-notes.md, dev-process.md +
  dev/agentic-development.md (the research write-up), dev/ (raw record).
- Replace decomp status-badge CI with a PC-port validate workflow.
- Remove session/agent scaffolding and stale planning docs from the tree.
- Add .gitattributes (normalize line endings to LF); add screenshots.

The pre-2026-08 history is the GoldenEye 007 decompilation by Larry Ficken
(KholdFuzion) and contributors, preserved unchanged. The PC-port work from
2026-08-17 on is mine.
2026-09-01 19:28:59 -04:00