Docs: public copy, site presentation, release-gate review (D533, D534)

Public-copy language pass, homepage restructure and Documentation rename,
404 page, dead-anchor and permalink fixes, release-gate sign-off, and the
pre-release review fixes of the 2026-10-05 batch (probe-doc drift,
build-path hygiene, verify.sh and capture safety).

Refs: D533 D534
This commit is contained in:
James Dansereau committed 2026-10-06 18:35:44 -04:00
1 parent 452fa1025a
commit d7b9371afb
33 files changed
+982 -468

No files matched your search

+1 -1
View File
@@ -12,7 +12,7 @@ surface is:
A full walkthrough of what a release actually installs on your machine, and A full walkthrough of what a release actually installs on your machine, and
what a from-source build pulls in, is in what a from-source build pulls in, is in
[`docs/security-and-fidelity-status.md`](../docs/security-and-fidelity-status.md). [`docs/security.md`](../docs/security.md).
### Why the binaries are unsigned ### Why the binaries are unsigned
+34 -33
View File
@@ -16,12 +16,12 @@ Region: **NTSC-U (US) only**. See [Known issues](#known-issues).
build was played on (e.g. "Played on Windows and Steam Deck: campaign build was played on (e.g. "Played on Windows and Steam Deck: campaign
spot-checks, 2-4P split-screen, a controller-only session"). --> spot-checks, 2-4P split-screen, a controller-only session"). -->
The headline is **the settings interface, rebuilt**. Both options screens are The headline is **one real options system**: both options
merged into one, laid out like the Perfect Dark PC port's menu, with plain-English screens merged into a single menu, laid out like the Perfect Dark PC port's,
wording, real-unit sliders and a one-line description under whichever option you with the game's own N64 control styles as a per-seat preset, emulator save
select. Alongside it: the game's own N64 control styles as a per-seat preset, files that load directly, and a scalable HUD overlay. A round of fidelity
emulator save files that load directly, a scalable HUD overlay, and a round of fixes, checked frame-by-frame against the N64 game, rounds out the feature
fidelity fixes checked frame-by-frame against the N64 game. list.
--- ---
@@ -37,15 +37,6 @@ fidelity fixes checked frame-by-frame against the N64 game.
- **Display mode** is a dropdown; **Backspace** goes back, matching the rest of - **Display mode** is a dropdown; **Backspace** goes back, matching the rest of
the game's menus (D504 follow-up). the game's menus (D504 follow-up).
### Menu wording, units and help text (D505–D507)
- 27 maintainer-approved wording edits across both menus: option names say what
they do, not what the internal variable is called (D505).
- Sliders carry **real units** — percent, frames, seconds, pixels — and their
values are standardised across the two menus (D506).
- Selecting an option shows a **one-line description** of it in the same menu
(D507).
### Control styles: the game's own N64 layouts (D513, D516, D518) ### Control styles: the game's own N64 layouts (D513, D516, D518)
- **Control style** offers **Ext** (this port's scheme, unchanged) and - **Control style** offers **Ext** (this port's scheme, unchanged) and
@@ -79,18 +70,6 @@ fidelity fixes checked frame-by-frame against the N64 game.
**crosshair colour by health** — the four settings the Perfect Dark port has **crosshair colour by health** — the four settings the Perfect Dark port has
that this port was missing. that this port was missing.
### Overlay controls are antialiased (D520)
- Slider wedges, slider markers and dropdown arrows no longer step in whole
canvas pixels (which grew visibly at large window sizes); they are drawn
smooth at every size.
### Watch menu keeps its own settings (D349, corrected)
- Closing the in-level **Watch** menu now saves the watch's own screen size and
ratio, and they no longer fight the front-end **Aspect ratio** setting. The
earlier note in the findings log was corrected.
--- ---
## Fidelity and stability fixes ## Fidelity and stability fixes
@@ -101,13 +80,19 @@ fidelity fixes checked frame-by-frame against the N64 game.
- **Aspect ratio:** forced ratios now letterbox/pillarbox without re-cropping the - **Aspect ratio:** forced ratios now letterbox/pillarbox without re-cropping the
play area (D508); the rare gun/hand model glitch after changing ratio play area (D508); the rare gun/hand model glitch after changing ratio
mid-level is largely fixed, a rare remainder is logged (D509). mid-level is largely fixed, a rare remainder is logged (D509).
- **Watch menu:** closing the in-level **Watch** menu now saves the watch's own
screen size and ratio, and they no longer fight the front-end **Aspect ratio**
setting; the earlier note in the findings log was corrected (D349).
- **Overlay controls:** slider wedges, slider markers and dropdown arrows no
longer step in whole canvas pixels (which grew visibly at large window sizes);
they are drawn smooth at every size (D520).
- **FPS counter:** holding left/right on a Bond settings row no longer drops the - **FPS counter:** holding left/right on a Bond settings row no longer drops the
FPS counter (D517). FPS counter (D517).
- **Build:** a fresh build directory no longer produces an untagged executable - **Build:** a fresh build directory no longer produces an untagged executable
name (D515). name (D515).
- **Tooling:** the asset converter's argument quoting and sidecar size check are - **Tooling:** the asset converter's argument quoting and sidecar size check are
tightened; the CI cache actions no longer carry stale ROM paths. The golden-frame tightened; the CI cache actions no longer carry stale ROM paths. The
tooling is now non-destructive and drift-free: a verification sweep used to reference-frame tooling is now non-destructive and drift-free: a verification sweep used to
overwrite your own `data/ge007.ini` and leave the previous level's save file overwrite your own `data/ge007.ini` and leave the previous level's save file
behind, and now pins both idempotently (your ini and save are restored whatever behind, and now pins both idempotently (your ini and save are restored whatever
the run does); the capture helper reads its frame windows out of the gate instead the run does); the capture helper reads its frame windows out of the gate instead
@@ -124,6 +109,16 @@ fidelity fixes checked frame-by-frame against the N64 game.
--- ---
## The small stuff
27 menu-wording edits across both menus (option names say what they do, not
what the internal variable is called, D505); sliders carrying **real units** —
percent, frames, seconds, pixels — standardised across the two menus (D506);
a **one-line description** of the selected option in the same menu (D507);
and menu spelling standardised to one convention across both menus.
---
## Known issues ## Known issues
| Issue | Impact | Workaround | | Issue | Impact | Workaround |
@@ -148,10 +143,16 @@ follow-ups.
sentence "these were merged and review-verified but not playtested live" sentence "these were merged and review-verified but not playtested live"
in the body; never imply a full playtest. --> in the body; never imply a full playtest. -->
**Golden-gate state for this release:** both platforms carry the full 21-level **Reference-frame gate for this release:** both platforms carry the full 21-level
reference-frame set (63 frames each) at the same stems, and each platform's gate reference-frame set (63 frames each) at the same stems. The Windows gate is green
is green against its own goldens. The cross-platform spread (0.348-3.983% of against its own goldens (21/21, three consecutive clean sweeps); on Linux the
pixels over tol 2 on the 20 non-Cuba levels, structural tier 21/21 clean) is crash gate is green and the pixel verdict is still owed (see below). The recipe pins the run for you: the save file's
CONTENT is pinned (the gate installs its own canonical save per level, the same
way it pins the display ini — D529) and the PRNG seed is hard-pinned (a stray
`GE_RSEED` in your environment warns and is ignored rather than re-seeding the
gate — D532), so a gate run and a capture run see the same starting state. The
cross-platform spread measured on the shipped pairs (0.380-5.120% of pixels over
tol 2 on the 20 non-Cuba levels, structural tier 21/21 clean) is
informational only — it is not a cross-platform pixel-parity claim, and the informational only — it is not a cross-platform pixel-parity claim, and the
linux *pixel* gate did not run on the capture box (its GL probe fails closed linux *pixel* gate did not run on the capture box (its GL probe fails closed
there; the linux crash gate did). The Dam ending cutscene has not been checked there; the linux crash gate did). The Dam ending cutscene has not been checked
+34 -4
View File
@@ -9,6 +9,33 @@
- **Current status:** the README "Status" section (`docs/dev/LEVEL-STATUS.md` is a historical per-level sweep record). Current task + environment: `docs/HANDOFF.md` (a rolling local working file — may be absent in a fresh clone; fall back to the README "Status" section). - **Current status:** the README "Status" section (`docs/dev/LEVEL-STATUS.md` is a historical per-level sweep record). Current task + environment: `docs/HANDOFF.md` (a rolling local working file — may be absent in a fresh clone; fall back to the README "Status" section).
- **Dispatching subagents?** `docs/dev-process.md` — task budgets/deadlines, file partitioning, pre-flight, the standard brief template. Every investigation subagent reads `docs/porting-notes.md` first and appends to it. - **Dispatching subagents?** `docs/dev-process.md` — task budgets/deadlines, file partitioning, pre-flight, the standard brief template. Every investigation subagent reads `docs/porting-notes.md` first and appends to it.
## Public site pages (`docs/`) — presentation layer, not a source of truth
The repo's homepage and sub-pages are published by GitHub Pages; the local
preview is `node scratch/build_preview.mjs site` → `scratch/_site/` (served
with `node scratch/serve_preview.mjs 8777`). The site is a **presentation
layer over the reference docs, kept in a separate area, and allowed to go
stale** — never let it poison a work item:
- **Pure site pages** — `docs/index.md`, `documentation.md`,
`the-software-rsp.md`, `the-asset-pipeline.md`, `framerate-and-pacing.md`,
`input-and-aim.md`, `saves.md`, `security.md`, `fidelity.md` —
summarise the ROADMAP / README / finding log / release notes. **Do not
consult them as work information, cross-check against them, or treat a
mismatch with `docs/ROADMAP.md` or the finding log as a bug** (that is
the expected, independent-staleness case). Update them only when the task
says so, and source every fact from the ROADMAP / README / finding log —
never the other way round. The footer "last updated" date in
`docs/_layouts/default.html` is the same class of site-only detail.
- **Shared files** — `docs/internals.md`, `porting-notes.md`,
`building.md`, `dev-process.md`, `dev/agentic-development.md` are
authoritative working docs that the site publishes verbatim; edit them
normally as part of dev work and the site picks up the change for free.
Keep the split intact: no working notes migrate into pure site pages, and
never edit a shared doc merely to make the site read better — if the site is
stale, fix the site page (or the fact upstream, as its own task).
## Non-negotiables ## Non-negotiables
1. **N64 build untouched.** `Makefile`, `tools/`, `rsp/`, `ld/` belong to the N64 build. Never modify them for the PC port. 1. **N64 build untouched.** `Makefile`, `tools/`, `rsp/`, `ld/` belong to the N64 build. Never modify them for the PC port.
@@ -45,8 +72,10 @@ mostly agent-authored.
documentary and small (bug shots, previews — downscaled), and never commit documentary and small (bug shots, previews — downscaled), and never commit
bulk ROM-derived captures: capture output dirs are gitignored bulk ROM-derived captures: capture output dirs are gitignored
(`tools_pc/sweep-captures/cap-*/`, `tools_pc/sweep-captures/**/*.ppm`); the (`tools_pc/sweep-captures/cap-*/`, `tools_pc/sweep-captures/**/*.ppm`); the
only bulk imagery in the tree is `tools_pc/golden/*.png`, which exists only bulk imagery in the tree is `tools_pc/golden/**/*.png`
because `verify.sh` consumes it. Downloads ship no game content at all. (63 frames × 2 platforms, 126 total, nested per level at
`tools_pc/golden/<level>/{win,linux}/`), which exists because `verify.sh`
consumes it. Downloads ship no game content at all.
5. **Batch, don't spam.** Accumulate approved doc/tree fixes across a session 5. **Batch, don't spam.** Accumulate approved doc/tree fixes across a session
into ONE commit; no per-item branches. into ONE commit; no per-item branches.
6. **Release gate.** Before pushing a release: the PII scrub and legal/copyright 6. **Release gate.** Before pushing a release: the PII scrub and legal/copyright
@@ -83,8 +112,9 @@ Needs CMake + SDL2 + zlib + OpenGL, and must run from the MSYS2 MINGW64 shell
1. **`Cannot create temporary file in C:\Windows\: Permission denied`** at the 1. **`Cannot create temporary file in C:\Windows\: Permission denied`** at the
link step. The PE toolchain (ninja → cmd → gcc/ld) needs a writable link step. The PE toolchain (ninja → cmd → gcc/ld) needs a writable
TMP/TEMP; the msys→native env conversion drops it in non-login shells TMP/TEMP; the msys→native env conversion drops it in non-login shells
(agent harnesses; the `C:/msys64` tree here was built for `D:/M/msys64`, (agent harnesses; the `C:/msys64` tree here was built for a relocated MSYS2
so its conversion is unreliable). `build-pc.sh` now **self-heals**: it root — `<msys>` in the placeholder legend — so its path conversion is
unreliable). `build-pc.sh` now **self-heals**: it
probes a native child's TMP (via a file — piped `cmd.exe` stdout is probes a native child's TMP (via a file — piped `cmd.exe` stdout is
unreliable under msys console emulation) and, if broken, re-runs unreliable under msys console emulation) and, if broken, re-runs
cmake+build under PowerShell with `TMP`/`TEMP` set natively (the cmake+build under PowerShell with `TMP`/`TEMP` set natively (the
+12 -9
View File
@@ -48,14 +48,17 @@ project is as much a study of that process as it is a port. See
## News ## News
- **2026-10-05** — **v0.5.0**: one options menu laid out like the Perfect Dark - **2026-10-05** — **v0.5.0**: one real options system: a
port's, with plain-English wording, real-unit sliders and a one-line description single menu (laid out like the Perfect Dark port's) covering every setting,
per option; the game's own N64 control styles as a per-seat preset; emulator save the game's own N64 control styles as a per-seat preset, and your emulator
files that load directly; a scalable HUD overlay; fullscreen mode, window centring saves loading directly; a scalable HUD overlay; fullscreen, window-centring
and crosshair settings; antialiased overlay controls; and a fidelity round checked and crosshair settings; and a fidelity round checked frame-by-frame against
frame-by-frame against the N64 game (fog, aspect-ratio letterboxing, the Watch the N64 game (fog, aspect-ratio letterboxing, the Watch menu's own
menu's own settings). The reference-frame gate was re-based on both platforms settings). The reference-frame gate was re-based on both platforms (21
(21 levels, 63 frames each). [Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0). levels, 63 frames each). Plus the small stuff: a menu wording, units and
help-text pass, standardised menu spelling, and antialiased overlay
controls.
[Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0).
- **v0.4.1**: 2–4 player split-screen multiplayer, controller presets and - **v0.4.1**: 2–4 player split-screen multiplayer, controller presets and
rebinding, PlayStation/Nintendo button names, master volume and audio rebinding, PlayStation/Nintendo button names, master volume and audio
device selection, a steady 60 fps on low-end GPUs, and fidelity fixes device selection, a steady 60 fps on low-end GPUs, and fidelity fixes
@@ -239,7 +242,7 @@ only in the release packages, and no macOS/ARM builds yet.
What a release installs (no networking, no telemetry, no ROM or game assets) What a release installs (no networking, no telemetry, no ROM or game assets)
and how faithfully the port tracks the original game's logic: and how faithfully the port tracks the original game's logic:
[Security & fidelity status](docs/security-and-fidelity-status.md). [Security](docs/security.md) and [fidelity](docs/fidelity.md) status.
The binaries are not code-signed; from v0.5.0 on each release artifact also The binaries are not code-signed; from v0.5.0 on each release artifact also
carries a GitHub build-provenance attestation you can check with carries a GitHub build-provenance attestation you can check with
`gh attestation verify <file> --repo jkdansereau/goldeneye-pc-port` `gh attestation verify <file> --repo jkdansereau/goldeneye-pc-port`
+2 -2
View File
@@ -45,7 +45,7 @@ BUILD_DIR="${BUILD_DIR:-build-pc}"
# MSYS2 install). Whatever `cmake`/`gcc` happen to be first on PATH is not # MSYS2 install). Whatever `cmake`/`gcc` happen to be first on PATH is not
# trustworthy: Git Bash's /mingw64 has no toolchain, and a pip-installed # trustworthy: Git Bash's /mingw64 has no toolchain, and a pip-installed
# cmake in a Python Scripts dir can shadow the MSYS2 one. GE_MSYS2_ROOT # cmake in a Python Scripts dir can shadow the MSYS2 one. GE_MSYS2_ROOT
# (e.g. D:\M\msys64) overrides the search. # (e.g. C:\msys64) overrides the search.
_ge_find_mingw_bin() { _ge_find_mingw_bin() {
local c root local c root
root="${GE_MSYS2_ROOT:-}" root="${GE_MSYS2_ROOT:-}"
@@ -67,7 +67,7 @@ _ge_find_mingw_bin() {
if [ -n "${MSYSTEM:-}" ] && [ -z "${GE_PC_BUILD_VIA_NATIVE:-}" ]; then if [ -n "${MSYSTEM:-}" ] && [ -z "${GE_PC_BUILD_VIA_NATIVE:-}" ]; then
_mingw_bin="$(_ge_find_mingw_bin)" || { _mingw_bin="$(_ge_find_mingw_bin)" || {
echo "ERROR: could not find the MSYS2 MinGW64 toolchain (mingw64/bin with cmake.exe + gcc.exe)." >&2 echo "ERROR: could not find the MSYS2 MinGW64 toolchain (mingw64/bin with cmake.exe + gcc.exe)." >&2
echo "Install it (see docs/building.md) or point GE_MSYS2_ROOT at the MSYS2 root, e.g. GE_MSYS2_ROOT='D:\M\msys64'." >&2 echo "Install it (see docs/building.md) or point GE_MSYS2_ROOT at the MSYS2 root, e.g. GE_MSYS2_ROOT='C:\msys64'." >&2
exit 1 exit 1
} }
# Failure mode 3 (AGENTS.md): the toolchain's DLL dir must be on PATH, # Failure mode 3 (AGENTS.md): the toolchain's DLL dir must be on PATH,
+20
View File
@@ -0,0 +1,20 @@
---
title: 404
description: Page not found.
layout: default
permalink: /404.html
---
## 404
This page doesn't exist. The site's real pages are linked from the
nav: [home]({{ '/' | relative_url }}) ·
[documentation]({{ '/documentation' | relative_url }}) ·
[building]({{ '/building' | relative_url }}).
*Note for anyone following a moved link: the old "under the hood" page now
lives at [documentation]({{ '/documentation' | relative_url }}).*
<!-- Links use the | relative_url filter on purpose: a 404 page is served for
ANY unknown path, so plain relative links would resolve against the
requested (dead) URL instead of the site root. -->
+13 -20
View File
@@ -140,15 +140,13 @@ below).
| Item | Status | Refs | Notes | | Item | Status | Refs | Notes |
|---|---|---|---| |---|---|---|---|
| Third-person Bond offset residual | partial; intro puppet explained (2026-10-02) | D173, D292 | Mostly fixed. On the level-start puppet the variance is tick/PRNG-dependent idle timing (D13 class, faithful, no sign-off requested); one 1-frame first-tick Y transient is untraced. If the residual is seen elsewhere (cutscene body model), the maintainer should note where. | | Third-person Bond offset residual | partial; intro puppet explained (2026-10-02) | D173, D292 | Mostly fixed. On the level-start puppet the variance is tick/PRNG-dependent idle timing (D13 class, faithful, no sign-off requested); one 1-frame first-tick Y transient is untraced. If the residual is seen elsewhere (cutscene body model), the maintainer should note where. |
| Dam ending cutscene: Bond placement; railing transparency | partial (railing/grate transparency confirmed faithful 2026-10-07; Bond-placement re-check pending) | D173, D292, D526; maintainer 2026-10-02 | **Railing/grate transparency CLOSED as faithful (D526):** the 2D edge-railing (grate) texture in the Dam ending shows "odd" transparency between its two anchors, confirmed identical on 1964/GEPD (port == N64) → the original 2D texture, not a port bug (D306/D291 class). **Remaining: re-check Bond placement at the end of Dam** (the D173 level-start probe found no defect; the last place a Bond offset was seen). | | Dam ending cutscene: Bond placement; railing transparency | partial (railing/grate transparency confirmed faithful 2026-10-05; Bond-placement re-check pending) | D173, D292, D526; maintainer 2026-10-02 | **Railing/grate transparency CLOSED as faithful (D526):** the 2D edge-railing (grate) texture in the Dam ending shows "odd" transparency between its two anchors, confirmed identical on 1964/GEPD (port == N64) → the original 2D texture, not a port bug (D306/D291 class). **Remaining: re-check Bond placement at the end of Dam** (the D173 level-start probe found no defect; the last place a Bond offset was seen). |
| Title-screen attract demo runs too fast; F10 box rescales while it plays | backlogged (after v0.5.0, maintainer 2026-10-04) | D87 (ramrom file struct); timing: D13, D248, D427, D451, D486 | **Reported 2026-10-04 (maintainer live pass):** the attract segment plays visibly too fast; not investigated. Lead: it is a ramrom demo replay whose recordings carry a per-frame tick count, which the port's 60 fps / 1-tick pacing may override. Rule out PC causes, then compare with 1964. Same pass: the F10 box briefly rescaled during the demo (not reproduced; candidate fix = overlay reads fast3d's native viewport, parked locally). | | Title-screen attract demo runs too fast; F10 box rescales while it plays | backlogged (after v0.5.0, maintainer 2026-10-04) | D87 (ramrom file struct); timing: D13, D248, D427, D451, D486 | **Reported 2026-10-04 (maintainer live pass):** the attract segment plays visibly too fast; not investigated. Lead: it is a ramrom demo replay whose recordings carry a per-frame tick count, which the port's 60 fps / 1-tick pacing may override. Rule out PC causes, then compare with 1964. Same pass: the F10 box briefly rescaled during the demo (not reproduced; candidate fix = overlay reads fast3d's native viewport, parked locally). |
| Dam: first-tower guard walks a small circle (glass collision polygon) | done | D490 | **Fixed 2026-10-02, merged into `release/v0.4.1` 2026-10-03:** a stack overflow in `sub_GAME_7F03ECC0` (flat-bbox objects, i.e. glass) corrupted the collision polygon; `rem[8]` under `AVOID_UB`. Headless probe: the guard now walks his whole patrol loop. Maintainer by-eye check in Dam passed 2026-10-02. The porting-notes D24 audit ran 2026-10-03 and found D491 (below); no other overflow of this kind. |
| Struct reads across adjacent globals: portal bbox seeds put props in extra rooms; casing spin seeded from trigger state | done | D491 | **Fixed 2026-10-03, merged into `release/v0.4.1`:** `bg.c` / `gunfire.c` read three separate scalar globals as one coord3d; mingw reverses their order. `#ifdef PORT` reads the named globals. Builds clean, 900-frame `-level_09` smoke clean. Nothing by eye is expected. Delete this row once released. |
| Sniper rifle: zoom level and speed vs 1964 | verify | #136, D484, D485, D494 | Crouch: **D494** (2026-10-03) makes the PC crouch key crouch/stand freely with the sniper, as GEPD does (superseding D483's freeze); maintainer-verified. Zoom level (D484, 20 -> 7 degrees) and speed (D485, tick-scaled, Rule-2) fixed 2026-10-02. **Owed:** 1964 A/B of zoom level and speed; close #136 after it. | | Sniper rifle: zoom level and speed vs 1964 | verify | #136, D484, D485, D494 | Crouch: **D494** (2026-10-03) makes the PC crouch key crouch/stand freely with the sniper, as GEPD does (superseding D483's freeze); maintainer-verified. Zoom level (D484, 20 -> 7 degrees) and speed (D485, tick-scaled, Rule-2) fixed 2026-10-02. **Owed:** 1964 A/B of zoom level and speed; close #136 after it. |
| Crash on save slots 1/3/4, plus a host BSOD (fltmgr.sys) | decided | #94 | Needs a repro. Two maintainer retest requests (v0.3.0, v0.4.0) got no reply. Likely D299/D301 (save-slot crash, fixed) and D344 (BSOD on exit, fixed). **Decided 2026-10-01: close as stale when the release ships**, pointing at D299/D301/D344; no GitHub activity before then. | | Crash on save slots 1/3/4, plus a host BSOD (fltmgr.sys) | decided | #94 | Needs a repro. Two maintainer retest requests (v0.3.0, v0.4.0) got no reply. Likely D299/D301 (save-slot crash, fixed) and D344 (BSOD on exit, fixed). **Decided 2026-10-01: close as stale when the release ships**, pointing at D299/D301/D344; no GitHub activity before then. |
| Authored mip chains not sampled for explicit-LOD textures | post-1.0 | D323 | Distant textures use driver mips instead of Rare's hand-authored chain (heaviest on Statue/Aztec). Parked as a fidelity enhancement. **Decided 2026-10-01:** after 1.0, together with the LOD-fraction approximation as one "real RDP LOD" project. | | Authored mip chains not sampled for explicit-LOD textures | post-1.0 | D323 | Distant textures use driver mips instead of Rare's hand-authored chain (heaviest on Statue/Aztec). Parked as a fidelity enhancement. **Decided 2026-10-01:** after 1.0, together with the LOD-fraction approximation as one "real RDP LOD" project. |
| Approximations in the software RSP | post-1.0 | `gfx_pc.cpp` `G_CCMUX_LOD_FRACTION`; D323 | The LOD-fraction CC input is an eyeballed approximation, bundled with D323 as one "real RDP LOD" project after 1.0 (2026-09-30 triage). **WrapFix settled 2026-10-02:** the maintainer checked the Depot building ceilings against 1964 with the default `Video.WrapFix = 0` and they look right, so the default stays off (the opt-in knob remains; RC3/D167). | | Approximations in the software RSP | post-1.0 | `gfx_pc.cpp` `G_CCMUX_LOD_FRACTION`; D323 | The LOD-fraction CC input is an eyeballed approximation, bundled with D323 as one "real RDP LOD" project after 1.0 (2026-09-30 triage). **WrapFix settled 2026-10-02:** the maintainer checked the Depot building ceilings against 1964 with the default `Video.WrapFix = 0` and they look right, so the default stays off (the opt-in knob remains; RC3/D167). |
| Latent 64-bit ABI hazards | partial | D441, #107, #108; AUDIT-M6 `struct player`/`struct hand` raw offsets (porting-notes §A1) | **State (2026-10-03, D441):** complete census (local `scratch/d441/`; many compiler hits are intentional `(s32)&ANIM_DATA_*` offsets, D34); 17 files widened to `uintptr_t` under `#ifdef PORT`; 35 sign-extension sites fixed; CI ratchet `tools_pc/abi_ratchet.py` (baseline 389); arena windows centralised (`port/include/portaddr.h`); tier-1 high-arena build (`GE_HIGHARENA_BASE=0x90000000`) runs the menu and `-level_09` pixel-identical to default. D478: nothing live on the current layout; the rest is harmless today but would bite on macOS/ARM/ASLR. **Sweep (2026-10-05):** tier-1 all-level sweep done — 21/21 PASS, 0 crashes, worst over-tol 2.38 % Jungle / 1.38 % Surface 2 (both under their 3 % limit), all 1 %-limit levels <= 0.24 %; no fix batches, ratchet unchanged (389); recipe + caveats in the D441 findings entry. **Owed:** tier 2 (above 4 GiB; u32 slots widened); store-to-u32 vs arithmetic-only tag per site (`portHostToN64` under macOS port_addr); `mema.c` widening (D453); `initanitable.c` heap slots; GE_DETERM wall-clock timers (D117 follow-up, blocks using determinism mode for frame gates). **#108:** widening the `sndPlaySfx` bound disables the guard everywhere; prefer a range check. Detail: findings D441, D457, D478. | | Latent 64-bit ABI hazards | partial | D441, #107, #108; AUDIT-M6 `struct player`/`struct hand` raw offsets (porting-notes §A1) | **State (2026-10-03, D441):** complete census (local `scratch/d441/`; many compiler hits are intentional `(s32)&ANIM_DATA_*` offsets, D34); 17 files widened to `uintptr_t` under `#ifdef PORT`; 35 sign-extension sites fixed; CI ratchet `tools_pc/abi_ratchet.py` (baseline 389); arena windows centralised (`port/include/portaddr.h`); tier-1 high-arena build (`GE_HIGHARENA_BASE=0x90000000`) runs the menu and `-level_09` pixel-identical to default. D478: nothing live on the current layout; the rest is harmless today but would bite on macOS/ARM/ASLR. **Sweep (2026-10-05):** tier-1 all-level sweep done, 21/21 PASS, no fix batches, ratchet unchanged (389) — recipe + caveats in the D441 entry. **Owed:** tier 2 (above 4 GiB; u32 slots widened); store-to-u32 vs arithmetic-only tag per site (`portHostToN64` under macOS port_addr); `mema.c` widening (D453); `initanitable.c` heap slots; GE_DETERM wall-clock timers (D117 follow-up, blocks using determinism mode for frame gates). **#108:** widening the `sndPlaySfx` bound disables the guard everywhere; prefer a range check. Detail: findings D441, D457, D478. |
## 3. Verification debt (fixed; a live check is owed) ## 3. Verification debt (fixed; a live check is owed)
@@ -179,11 +177,9 @@ A single campaign pass with these on the checklist would clear most of them.
| macOS (Intel + Apple Silicon) / ARM64 Linux | open (target 0.9.0/1.0, maintainer 2026-10-02) | PRs #88, #95; #101 | Outside drafts, parked for `main` until after 1.0. **Address model decided (2026-09-30): port_addr (#95)**, a `portN64ToHost`/`PORT_N64PTR` chokepoint with a `PORT_ADDR_STRICT` validator. The `macos` integration branch is on origin with #88 (merged), #132 and #95 (retargeted, open); nothing merges to `main` before the post-1.0 pass. **Open against `macos`:** #131 (self-hosted sweep scaffold, never run on a Mac; needs #95 first). **On the next rebase onto `main`:** take #131's `selfhosted.yml`; drop #95's `crouched_rifle` hunk (our #120/D445 is correct); relabel #95's D29x/D405-D421 labels. Needs the §2 ABI-hazard sweep; the maintainer tests firsthand before merging. | | macOS (Intel + Apple Silicon) / ARM64 Linux | open (target 0.9.0/1.0, maintainer 2026-10-02) | PRs #88, #95; #101 | Outside drafts, parked for `main` until after 1.0. **Address model decided (2026-09-30): port_addr (#95)**, a `portN64ToHost`/`PORT_N64PTR` chokepoint with a `PORT_ADDR_STRICT` validator. The `macos` integration branch is on origin with #88 (merged), #132 and #95 (retargeted, open); nothing merges to `main` before the post-1.0 pass. **Open against `macos`:** #131 (self-hosted sweep scaffold, never run on a Mac; needs #95 first). **On the next rebase onto `main`:** take #131's `selfhosted.yml`; drop #95's `crouched_rifle` hunk (our #120/D445 is correct); relabel #95's D29x/D405-D421 labels. Needs the §2 ABI-hazard sweep; the maintainer tests firsthand before merging. |
| Platform parity gate (Linux co-equal with Windows) | open | — | **Decided 2026-09-30:** yes. Every released platform carries the same gate: a 21-level sweep plus a campaign pass. Needs the golden baselines on both platforms first (§7). The last known Linux crash (D190) was closed as not-a-bug. | | Platform parity gate (Linux co-equal with Windows) | open | — | **Decided 2026-09-30:** yes. Every released platform carries the same gate: a 21-level sweep plus a campaign pass. Needs the golden baselines on both platforms first (§7). The last known Linux crash (D190) was closed as not-a-bug. |
| Low-end GPUs (~30 fps on Celeron/HD 400) | fixed, verify on N3060 class | D339, D481, D482, #92 | **D481 (2026-10-02):** fast3d ran inline on the scheduler thread, delaying retrace delivery so the tick gate skipped frames; with the render worker a Lenovo X220 (HD 3000) went 44-46 → 60.0 fps. **D482:** Atom/Celeron-class GPUs (HD 400-605, UHD 600/605, software renderers) get DrawDistance/LodDistance 100 and MSAA 1 once, where still at defaults. **D473:** uncached per-batch getenv fixed. Direction: real optimizations, not a preset. **Next only if N3060-class hardware still drops:** one `GE_PERFSTAT=1` run there (`gpu=` vs `run=`), then a lighter renderer-keyed default (GPU) or fast3d per-batch cuts (CPU; local `PERF-HOTSPOTS.md`). | | Low-end GPUs (~30 fps on Celeron/HD 400) | fixed, verify on N3060 class | D339, D481, D482, #92 | **D481 (2026-10-02):** fast3d ran inline on the scheduler thread, delaying retrace delivery so the tick gate skipped frames; with the render worker a Lenovo X220 (HD 3000) went 44-46 → 60.0 fps. **D482:** Atom/Celeron-class GPUs (HD 400-605, UHD 600/605, software renderers) get DrawDistance/LodDistance 100 and MSAA 1 once, where still at defaults. **D473:** uncached per-batch getenv fixed. Direction: real optimizations, not a preset. **Next only if N3060-class hardware still drops:** one `GE_PERFSTAT=1` run there (`gpu=` vs `run=`), then a lighter renderer-keyed default (GPU) or fast3d per-batch cuts (CPU; local `PERF-HOTSPOTS.md`). |
| Statue/Cradle hitching (maintainer, 2026-09-30) | parked (not player-visible, 2026-10-02) | `GE_PERFSTAT` spike counters (2026-10-01) | **Diagnosed (D475, D477, D480):** no sustained load. The ~33 ms frames are the game's frame limiter skipping a retrace after a slightly late gfx task (`boss.c`; D13-class timing). CPU bursts were CI-palette re-imports (ruled out, D477; CI4 D476) and in-play shader compiles (fixed by D480). **Parked 2026-10-02:** a maintainer play session with the timeline probe (`probe/hitch-timeline`, never merge) felt no hitching. Reopen only if a visible hitch is reported (lever: pre-warm at level load). | | Statue/Cradle hitching (maintainer, 2026-09-30) | parked (not player-visible, 2026-10-02) | `GE_PERFSTAT` spike counters | **Diagnosed (D475, D477, D480):** no sustained load — the ~33 ms frames are the frame limiter skipping a retrace after a late gfx task (`boss.c`, D13-class timing); CPU bursts were CI-palette re-imports (ruled out, D477) and in-play shader compiles (fixed, D480). **Parked 2026-10-02:** a play session with the timeline probe felt no hitching. Reopen only if a visible hitch is reported (lever: pre-warm at level load). |
| Steam Deck preset skipped when first launched from Desktop Mode | verify | D283 | Fixed on `release/v0.4.1`: the Deck is detected by DMI hardware id (Valve Jupiter/Galileo; `STEAMOS` as a second signal) and the preset applies once per ini, only while Fullscreen/Maximized are untouched. Only a Windows build and a Linux `-fsyntax-only` check ran. **Owed: one run on a real Deck** (Desktop-Mode-created ini, then Game Mode; expect fullscreen 1280x800 and the log line `video: Steam Deck (DMI Valve ...)`). The Known-issues row goes when this ships. | | Steam Deck preset skipped when first launched from Desktop Mode | verify | D283 | Fixed on `release/v0.4.1`: the Deck is detected by DMI hardware id (Valve Jupiter/Galileo; `STEAMOS` as a second signal) and the preset applies once per ini, only while Fullscreen/Maximized are untouched. Only a Windows build and a Linux `-fsyntax-only` check ran. **Owed: one run on a real Deck** (Desktop-Mode-created ini, then Game Mode; expect fullscreen 1280x800 and the log line `video: Steam Deck (DMI Valve ...)`). The Known-issues row goes when this ships. |
| Windows 7 | open | #98 | **Re-checked 2026-10-02: likely feasible around 1.0.** The exe imports no Windows 8+ functions and the bundled SDL2 2.32.10 still supports Windows 7. The real blocker is the first-run converter `ge007-convert.exe` (PyInstaller, Python 3.9+): the native C converter (#6 Part B) removes it, or a separate Python 3.8 build. Work: one Windows 7 VM test, then manual per-release checks (CI cannot test it). Supersedes the earlier 'won't-fix' call. || Linux golden baselines (P7) + two residual render bands | closed (2026-10-05 re-round) | D521/D525 | 21-level `<level>/linux/` set captured 2026-10-04 on a real-GL box (Mesa / Intel HD 3000), then **re-rounded 2026-10-05 (P7b, D525)**: all 21 levels, 63 frames, at the D522 windows with the save pinned present (the 2026-10-04 set had `data/ge007.eep` cleared, and D523 measures that save-file presence moves ~every level). Cross-platform framediff vs `win/` at the same stems: structural **21/21 clean** (worst cell mean 4.43, phash <= 6 except cradle at 40), exact **0.348-3.983%** over tol 2 on the 20 non-Cuba levels. **Both residual bands closed:** Archives 19.956-24.554% (cell means to 50.8) is now 3.590-3.859% (worst cell 2.31, phash 1) and Streets 1200's 16.0-148.4 cell-mean band is now 3.616-3.983% (worst cell 4.43, phash 0) — save state, not a renderer. Dam's 900 flyby offset is out of the set (Dam sits at 1500-1700, cross-platform 2.964-3.443%). Caveat: the box's own sweep is crash-detect only (`glxinfo -B` fails there, rc 255, so `verify.sh`'s probe fails closed); the cross-platform numbers are computed on Windows. | | Windows 7 | open | #98 | **Re-checked 2026-10-02: likely feasible around 1.0.** The exe imports no Windows 8+ functions and the bundled SDL2 2.32.10 still supports Windows 7. The real blocker is the first-run converter `ge007-convert.exe` (PyInstaller, Python 3.9+): the native C converter (#6 Part B) removes it, or a separate Python 3.8 build. Work: one Windows 7 VM test, then manual per-release checks (CI cannot test it). Supersedes the earlier 'won't-fix' call. |
## 5. Modern-remaster layer (port features beyond the N64) ## 5. Modern-remaster layer (port features beyond the N64)
@@ -208,9 +204,6 @@ Background research lives in the maintainer's local notes (gitignored):
| Item | Status | Refs | Notes | | Item | Status | Refs | Notes |
|---|---|---|---| |---|---|---|---|
| `All unlocked` rework: RAM override instead of save patching | done | D442, D387, D259 | **Landed 2026-09-30 (D442):** query-time hooks in `file2.c`, RULE-2-SIGNOFF recorded; the EEPROM patch and D387 merge are removed. **Verified 2026-10-03 (headless):** ON = all 20 levels and cheats unlocked; OFF = only real progress; `ge007.eep` byte-identical. Delete this row once released. |
| Settings units and values cleanup | done | D357, D443 | **Landed 2026-09-30 (D443):** mouse ×, whole-% deadzone/volume/vibration, FOV in horizontal degrees, MSAA 16×; verified 2026-10-03 (both UIs show the same values). FPS presets above 60 wait for the frame-rate-above-60 work. Delete this row once released. |
| Restart button in the settings menus | done | D443 | **Landed 2026-09-30 (D443):** a "Restart game" row (orderly D344 quit, then relaunch). **Owed:** click it once on Windows (no BSOD); the Linux relaunch path has never been compiled. |
| F10 / PC Options menu: PD-style dialog refactor + watch-consolidation review | verify | D504-D512, `MENU-PD-ALIGNMENT-PLAN.md` (maintainer's local notes) | **Built 2026-10-04 (D504); follow-ups merged into `release/v0.4.1`:** D505/D506/D507 (wording, real-unit sliders, descriptions); D508 forced aspect ratios (16:9 / 21:9); D509 2-frame hold after an aspect change (rare gun glitch = known issue); D510 overlay + FPS counter same size front end vs level; D512 `Game.HudScale` scales the F10 overlay. **Owed (live pass, `docs/dev/notes/MENU-LIVE-CHECKLIST.md`, launches A/B/C):** look-and-feel vs PD; mouse, keyboard and pad in a level and on the front end; HudScale 75/100/150; 21:9; display-mode round trip across a restart; split-screen 2P with the overlay open. **Gaps:** background blur (post-1.0, §5c); per-seat control scheme is #139 / D513. Watch consolidation: not cheaply feasible (parked as T5). | | F10 / PC Options menu: PD-style dialog refactor + watch-consolidation review | verify | D504-D512, `MENU-PD-ALIGNMENT-PLAN.md` (maintainer's local notes) | **Built 2026-10-04 (D504); follow-ups merged into `release/v0.4.1`:** D505/D506/D507 (wording, real-unit sliders, descriptions); D508 forced aspect ratios (16:9 / 21:9); D509 2-frame hold after an aspect change (rare gun glitch = known issue); D510 overlay + FPS counter same size front end vs level; D512 `Game.HudScale` scales the F10 overlay. **Owed (live pass, `docs/dev/notes/MENU-LIVE-CHECKLIST.md`, launches A/B/C):** look-and-feel vs PD; mouse, keyboard and pad in a level and on the front end; HudScale 75/100/150; 21:9; display-mode round trip across a restart; split-screen 2P with the overlay open. **Gaps:** background blur (post-1.0, §5c); per-seat control scheme is #139 / D513. Watch consolidation: not cheaply feasible (parked as T5). |
| Defaults/presets consolidation: one `Display mode` switch | verify | D504, D440, `MENU-PD-ALIGNMENT-PLAN.md` §5 (local notes) | **Landed 2026-10-04 (D504):** the derived `__DisplayMode` row shows Modern / Original N64 / Custom (no ini key); F10 dropdown + left/right stepping, front end steps too; one reset row per dialog covering exactly its keys; editing a non-bundled key does not flip Display mode. **Decided 2026-10-03: tri-state**, flipping to Custom when the user edits a bundled key. **Owed (live):** display-mode round trip across a restart; read of the regrouped pages and wording (MENU-LIVE-CHECKLIST.md A1/A2/A4). | | Defaults/presets consolidation: one `Display mode` switch | verify | D504, D440, `MENU-PD-ALIGNMENT-PLAN.md` §5 (local notes) | **Landed 2026-10-04 (D504):** the derived `__DisplayMode` row shows Modern / Original N64 / Custom (no ini key); F10 dropdown + left/right stepping, front end steps too; one reset row per dialog covering exactly its keys; editing a non-bundled key does not flip Display mode. **Decided 2026-10-03: tri-state**, flipping to Custom when the user edits a bundled key. **Owed (live):** display-mode round trip across a restart; read of the regrouped pages and wording (MENU-LIVE-CHECKLIST.md A1/A2/A4). |
| Control style Original shows the game's own N64 styles | verify | #139 follow-up, D516, D517 | **Landed 2026-10-04 (D516, merged @ 91595597):** "Controller style" row (Original only; the game's own 1.1-2.4 per seat, saved to the Bond file; front end reads "(in a mission)"); D498 presets hidden in Original. **D517:** hold-repeat on any Bond row dropped fps (EEPROM rewrite per detent); now staged like sliders. Live passes 2026-10-04 (maintainer): single player + split-screen 2P with different styles per seat. **Owed:** the 2.x second-pad pass (real second controller). | | Control style Original shows the game's own N64 styles | verify | #139 follow-up, D516, D517 | **Landed 2026-10-04 (D516, merged @ 91595597):** "Controller style" row (Original only; the game's own 1.1-2.4 per seat, saved to the Bond file; front end reads "(in a mission)"); D498 presets hidden in Original. **D517:** hold-repeat on any Bond row dropped fps (EEPROM rewrite per detent); now staged like sliders. Live passes 2026-10-04 (maintainer): single player + split-screen 2P with different styles per seat. **Owed:** the 2.x second-pad pass (real second controller). |
@@ -220,9 +213,7 @@ Background research lives in the maintainer's local notes (gitignored):
| Gamepad presets: duplicate-binding warning, Xbox stick behaviours | open (after v0.5.0; documented in the README) | D469, D498, D518, D394 | D469 (pad action table, Jinx 1.1 default, Custom per-seat bindings), **D498** (Xbox 1.2 Christmas / 1.3 Frost / 1.4 Elektra) and the per-seat preset (**D518**) are done and maintainer-verified with pads. Not done (maintainer 2026-10-04: skip in game for v0.5.0, document only): a warning when two actions share a button; the Xbox "left stick aims the crosshair" and "D-pad copies the left stick" behaviours (D394). | | Gamepad presets: duplicate-binding warning, Xbox stick behaviours | open (after v0.5.0; documented in the README) | D469, D498, D518, D394 | D469 (pad action table, Jinx 1.1 default, Custom per-seat bindings), **D498** (Xbox 1.2 Christmas / 1.3 Frost / 1.4 Elektra) and the per-seat preset (**D518**) are done and maintainer-verified with pads. Not done (maintainer 2026-10-04: skip in game for v0.5.0, document only): a warning when two actions share a button; the Xbox "left stick aims the crosshair" and "D-pad copies the left stick" behaviours (D394). |
| Pad button names on a Nintendo pad | verify | D471; local note `PAD-MENU-AUDIT.md` | Audit done 2026-10-01 (no controller-only trap; D472 fixed G1-G3). D471 family button names + player LEDs: **PS5 DualSense verified 2026-10-03.** **Owed:** a Nintendo (Switch) pad check; the maintainer has no such pad, so this waits for one or for a user report. | | Pad button names on a Nintendo pad | verify | D471; local note `PAD-MENU-AUDIT.md` | Audit done 2026-10-01 (no controller-only trap; D472 fixed G1-G3). D471 family button names + player LEDs: **PS5 DualSense verified 2026-10-03.** **Owed:** a Nintendo (Switch) pad check; the maintainer has no such pad, so this waits for one or for a user report. |
| Mute and auto-pause on focus loss; PNG screenshots to `screenshots/` | parked | D231, PR #56 (closed unmerged), `docs/dev/notes/parked/0001-QoL-*.patch` (local) | Deprioritised by the maintainer on 2026-09-25. F12 today is the dev PPM dump. | | Mute and auto-pause on focus loss; PNG screenshots to `screenshots/` | parked | D231, PR #56 (closed unmerged), `docs/dev/notes/parked/0001-QoL-*.patch` (local) | Deprioritised by the maintainer on 2026-09-25. F12 today is the dev PPM dump. |
| FPS tanks while adjusting F10 music volume with a controller | done | D489 | Maintainer, 2026-10-02 (seen on PAL; general, also on v0.4.0). Cause: every pad/arrow slider step saved to the EEPROM (3 joy-poll handshakes + file rewrite on the game thread). Fixed: steps stage, save once on release; merged into `release/v0.4.1` 2026-10-03. Maintainer pad check passed 2026-10-03. Delete this row once released. |
| Frame rate above 60 (120/144/uncapped with interpolation) | decision | [`dev/UNLOCKED-FPS-PLAN.md`](dev/UNLOCKED-FPS-PLAN.md) | The menu cap is {30, 60} (the ini accepts 0 = uncapped, but the sim ticks at the VI rate). The plan's Phase 0 is resolved by D248 (the default was a port bug; it is a real 60 fps) and its Phase 1 audit and Phase 2 slice scope are written (landed 2026-09-30), but the header still reads parked. Next step is a standing sim/render-rate measurement, not the old 30 fps investigation. Must stay compatible with netplay determinism. | | Frame rate above 60 (120/144/uncapped with interpolation) | decision | [`dev/UNLOCKED-FPS-PLAN.md`](dev/UNLOCKED-FPS-PLAN.md) | The menu cap is {30, 60} (the ini accepts 0 = uncapped, but the sim ticks at the VI rate). The plan's Phase 0 is resolved by D248 (the default was a port bug; it is a real 60 fps) and its Phase 1 audit and Phase 2 slice scope are written (landed 2026-09-30), but the header still reads parked. Next step is a standing sim/render-rate measurement, not the old 30 fps investigation. Must stay compatible with netplay determinism. |
| Swapping saves with emulators | done (D492) | D492; `tools_pc/eep_convert.py`; README "Using an emulator save" | **Implemented 2026-10-04:** `tools_pc/eep_convert.py` (`n64-to-pc`, `pc-to-n64`, `verify [--as n64|pc]`, auto-detect), bundled as `tools/eep_convert.py` in both release packages; README section added. **Why (D492):** the port stores checksum words and `options` little-endian, so an unconverted 1964 save fails validation and all five slots are wiped; converting (swap `options`, recompute the checksum pair) was proven in a headless A/B. On-disk format unchanged. Verified byte-identical and round-trip. |
| PD Extended Options parity: settings that need new dev work | done (reviewed 2026-10-04; two rows deferred) | `MENU-PARITY-SONNET-PLAN.md` §3 (local notes); pd_port `port/src/optionsmenu.c` @ 32a1cb9 | **Reviewed 2026-10-04 (maintainer decisions; local notes `PD-PARITY-DESIGN-REVIEW.md`, `WATCH-SCREEN-RATIO-DESIGN.md`).** **Done:** D511 fullscreen mode, Center window, crosshair opacity and color by health (live check owed, MENU-LIVE-CHECKLIST.md A4/A5/B3). **Watch Screen size/Ratio:** stay on the watch, no PC rows; the game saves watch settings on watch close (D349 correction) and they don't fight Aspect ratio (README). **Deferred past v0.5.0:** mouse lock mode (Auto/Always/Off; aim lock itself = `Input.AimMode`, D337); per-seat controller device select (needs a stable pad id; MP input layer). **Closed:** edge deadzone = `Input.AimRange` (D338); crosshair sway N/A (GE has none; gun sway is D428); use key reloads, no toggle (Ext keeps D378's GEPD split, Control style Original gives the N64 behaviour); per-seat options/binds (pad binds already per seat, D469/D518; keyboard/mouse is one device); no Detail textures toggle (`Video.DetailBaseTile` is the D236 fix); N/A confirmed: HUD centering (automatic, D335b), glare, overexposure, GE64 muzzle flashes, MP death music, radial menu speed, language filter, crosshair speed. **Other rows:** analog movement/stick scale/crouch → #139, T7; tickrate/framerate limit → frame rate above 60. | | PD Extended Options parity: settings that need new dev work | done (reviewed 2026-10-04; two rows deferred) | `MENU-PARITY-SONNET-PLAN.md` §3 (local notes); pd_port `port/src/optionsmenu.c` @ 32a1cb9 | **Reviewed 2026-10-04 (maintainer decisions; local notes `PD-PARITY-DESIGN-REVIEW.md`, `WATCH-SCREEN-RATIO-DESIGN.md`).** **Done:** D511 fullscreen mode, Center window, crosshair opacity and color by health (live check owed, MENU-LIVE-CHECKLIST.md A4/A5/B3). **Watch Screen size/Ratio:** stay on the watch, no PC rows; the game saves watch settings on watch close (D349 correction) and they don't fight Aspect ratio (README). **Deferred past v0.5.0:** mouse lock mode (Auto/Always/Off; aim lock itself = `Input.AimMode`, D337); per-seat controller device select (needs a stable pad id; MP input layer). **Closed:** edge deadzone = `Input.AimRange` (D338); crosshair sway N/A (GE has none; gun sway is D428); use key reloads, no toggle (Ext keeps D378's GEPD split, Control style Original gives the N64 behaviour); per-seat options/binds (pad binds already per seat, D469/D518; keyboard/mouse is one device); no Detail textures toggle (`Video.DetailBaseTile` is the D236 fix); N/A confirmed: HUD centering (automatic, D335b), glare, overexposure, GE64 muzzle flashes, MP death music, radial menu speed, language filter, crosshair speed. **Other rows:** analog movement/stick scale/crouch → #139, T7; tickrate/framerate limit → frame rate above 60. |
| One PC options UI: front-end "PC Options" opens the F10 overlay over the folder graphic | verify | D519, D343, D504, D510, D512 | **Landed 2026-10-04 (D519, branch `feat/one-options-ui`):** the file-select "PC Options" entry opens the F10 overlay over file select; the `MENU_PC_OPTIONS` screen and four old probes are gone; Bond-file rows and the watch chooser are keyed to file select. Headless checks pass (D519). **Owed:** by-eye mouse, keyboard and pad pass on file select; profile chooser + Controller style with a real profile; footer text overlaps the Copy/Erase bar. | | One PC options UI: front-end "PC Options" opens the F10 overlay over the folder graphic | verify | D519, D343, D504, D510, D512 | **Landed 2026-10-04 (D519, branch `feat/one-options-ui`):** the file-select "PC Options" entry opens the F10 overlay over file select; the `MENU_PC_OPTIONS` screen and four old probes are gone; Bond-file rows and the watch chooser are keyed to file select. Headless checks pass (D519). **Owed:** by-eye mouse, keyboard and pad pass on file select; profile chooser + Controller style with a real profile; footer text overlaps the Copy/Erase bar. |
| Emulator saves load directly in the game (no tool for import) | verify | D514, D492; `port/src/eepimport.c` called from `geEepromLoad`; D297 `legacycrc.c` same pattern | **Landed 2026-10-04 (D514, merged into `release/v0.4.1`).** Copying a 1964/Project64 `.eep` in as `data/ge007.eep` works: on first launch each region that validates in emulator format and not port format is converted in place (same rules as `eep_convert.py`); regions invalid in both are left to the game's wipe; port saves untouched; the original is backed up to `ge007.eep.emulator.bak`. Export stays with `eep_convert.py`. Headless verify 6/6 byte-identical to the in-game-proven reference. **Owed:** by-eye mission select after importing a real 1964 save. | | Emulator saves load directly in the game (no tool for import) | verify | D514, D492; `port/src/eepimport.c` called from `geEepromLoad`; D297 `legacycrc.c` same pattern | **Landed 2026-10-04 (D514, merged into `release/v0.4.1`).** Copying a 1964/Project64 `.eep` in as `data/ge007.eep` works: on first launch each region that validates in emulator format and not port format is converted in place (same rules as `eep_convert.py`); regions invalid in both are left to the game's wipe; port saves untouched; the original is backed up to `ge007.eep.emulator.bak`. Export stays with `eep_convert.py`. Headless verify 6/6 byte-identical to the in-game-proven reference. **Owed:** by-eye mission select after importing a real 1964 save. |
@@ -277,20 +268,22 @@ and a stage loader.
| Item | Status | Refs | Notes | | Item | Status | Refs | Notes |
|---|---|---|---| |---|---|---|---|
| Security review follow-ups | done | maintainer's local security review | All items done on `release/v0.4.1`: the Low hardening items, the Medium item (self-hosted workflow input handling), actions pinned by SHA, `pyinstaller` pinned to 6.22.3, and the ROM no longer stored in `actions/cache` by `selfhosted.yml` (staged from the runner's `_rom-seed` dir only). Dependabot bumps (#134, #135) landed as SHA pins. | | 1964-vs-port comparison harness | partial | `tools_pc/abpad/` | One millisecond timeline drives 1964 (virtual XInput pad) and the port (`GE_INPUTSCRIPT_MS`); both windows captured on one clock with side-by-side sheets, verified through intro skip, file select and folder open. Not frame-identical (1964 has no seed pin or frame dump). **Left:** in-level timelines (e.g. the D486 turret check); the two sides use different save files. |
| 1964-vs-port comparison harness | partial | `tools_pc/abpad/` | **2026-10-02/03:** one millisecond timeline drives 1964 (virtual XInput pad) and the port (`GE_INPUTSCRIPT_MS`), both windows captured on one clock with side-by-side sheets; verified through intro skip, file select and folder open. Not frame-identical (1964 has no seed pin or frame dump). Menu scripting dropped for `live_ab.ps1` (position-only, one real pad, `GE_PAD_BACKGROUND=1`). **Left:** in-level timelines (e.g. the D486 turret check); the two sides use different save files. | | Scripted-playthrough harness | post-1.0 (maintainer 2026-10-04: not a good use of current LLMs, revisit with newer models) | `GE_INPUTSCRIPT`, D117 | Input script + `GE_PCDUMP` + crash-log check for unattended regression runs. Levers: Invincibility + Invisibility cheats, closed-loop waypoint steering, pinned seed. Spike: one Dam route x5, measure end-position spread, then go/no-go. |
| Bond seems to move faster on the port than on 1964 (live A/B) | closed (2026-10-04, maintainer) | — | Seen 2026-10-03 in a live one-pad A/B. Closed as an input-mapping difference, not game speed: the GEPD 1964 bundle is set up for mouse and keyboard and the port then forced 1.2 SOLITARE (D513/D516 now offer the game's own styles). A valid future A/B is the port on a pad against a standard emulator with plain pad input. |
| Scripted-playthrough harness | post-1.0 (maintainer 2026-10-04: not a good use of current LLMs; revisit with newer models) | `GE_INPUTSCRIPT`, D117 | Input script + `GE_PCDUMP` + crash-log check for unattended regression runs. **Maintainer concern (2026-10-03):** aiming, PRNG guards and timed events may block open-loop scripts, and runs aren't deterministic (D117). Levers: Invincibility + Invisibility cheats, closed-loop waypoint steering, pinned seed (`GE_RSEED`), coverage routes. Spike: one Dam route x5, measure end-position spread, then go/no-go. |
| Cheap worker for mechanical, build-checked tasks | open | `delegate-local` MCP; memory of past Qwen issues | Birdman64's fast worker model wrote 44% of its commits while the lead planned and reviewed. Ours: pattern-applied edits (D441 fix batches, scaffolding strips, small tools), each gated by a clean build + a specific check + the lead's diff review, in the worker's own worktree. Local Qwen for edit-only tasks (it fabricates on reading tasks), or a hosted fast model via `delegate_to_provider` (the maintainer's cost call). | | Cheap worker for mechanical, build-checked tasks | open | `delegate-local` MCP; memory of past Qwen issues | Birdman64's fast worker model wrote 44% of its commits while the lead planned and reviewed. Ours: pattern-applied edits (D441 fix batches, scaffolding strips, small tools), each gated by a clean build + a specific check + the lead's diff review, in the worker's own worktree. Local Qwen for edit-only tasks (it fabricates on reading tasks), or a hosted fast model via `delegate_to_provider` (the maintainer's cost call). |
| Golden baselines | partial | `tools_pc/verify.sh`, `tools_pc/golden/README.md`, D117/D522/D529/D531 | **Windows gate GREEN (2026-10-05 re-base):** 21/21 PASS honest sequential. The recipe pins the save CONTENT (D529: `verify.sh` installs the canonical in-tree save `tools_pc/golden/ge007.eep` per level, the same way it pins the ini — D523's "presence" claim was refuted by the D529 A/B) and per-level windows — `900-1500:300` on 14 levels, `1000-1400:200` on Surface 2/Streets/Depot/Cradle/Frigate, `1500-1700:100` on Dam — because the 900 stem sits inside the wall-clock-paced intro flyby (D117; dam measured 1.6–7.2 % run to run). No tol limit raised. **Linux set (D525 → D530 → D531):** the 2026-10-04 round cleared the save, the box re-rounded 2026-10-05 (D530 — but under the box-LOCAL save: `capture_p7.sh`'s per-level re-pin silently overwrote D529's canonical install, the D531 blocker), and D531 (2026-10-07) fixed the tool and re-captured all 21 levels under the canonical eep (47/63 frames moved). **Owed:** the pixel-gated linux verify — the box's WSLg GPU display is session-state-dependent (its 10-05 capture was GPU-backed; 10-07's session reads back black even with `DISPLAY=:0`, so `verify.sh`'s probe fails closed to crash-detect); run `verify.sh sweep` on the box when its GPU display is up and check the four D117 flaky levels' first stems (never-do 6: exclude/widen, don't re-capture). | | Golden baselines | partial | `tools_pc/verify.sh`, `tools_pc/golden/README.md`, D117/D522/D529/D531 | **Windows gate GREEN (2026-10-05 re-base):** 21/21 PASS honest sequential. The recipe pins the save CONTENT (D529: `verify.sh` installs the canonical in-tree save `tools_pc/golden/ge007.eep` per level, the same way it pins the ini — D523's "presence" claim was refuted by the D529 A/B) and per-level windows — `900-1500:300` on 14 levels, `1000-1400:200` on Surface 2/Streets/Depot/Cradle/Frigate, `1500-1700:100` on Dam — because the 900 stem sits inside the wall-clock-paced intro flyby (D117; dam measured 1.6–7.2 % run to run). No tol limit raised. **Linux set (D525 → D530 → D531):** the 2026-10-04 round cleared the save, the box re-rounded 2026-10-05 (D530 — but under the box-LOCAL save: `capture_p7.sh`'s per-level re-pin silently overwrote D529's canonical install, the D531 blocker), and D531 (2026-10-05) fixed the tool and re-captured all 21 levels under the canonical eep (47/63 frames moved). **Cross-platform spread recomputed 2026-10-05** from the committed pairs (`framediff.py` win-vs-linux at the stems, tol 2): exact **0.380–5.120 %** on the 20 non-Cuba levels (silo's 900 stem is the outlier: cell mean 34.3, phash 10; streets 3.223–4.566), structural **21/21 clean**, max phash 40 (cradle, at threshold); Cuba 1.357–12.663 % is the structural-tier-only level. The D525 figures above predate the D531 linux re-capture. **Owed:** the pixel-gated linux verify — the box's WSLg GPU display is session-state-dependent (its 10-05 capture was GPU-backed; 10-07's session reads back black even with `DISPLAY=:0`, so `verify.sh`'s probe fails closed to crash-detect); run `verify.sh sweep` on the box when its GPU display is up and check the four D117 flaky levels' first stems (never-do 6: exclude/widen, don't re-capture). |
| Flicker scan (A/B/A frame alternation) | parked (2026-10-03: tooling, nothing blocked on it; spec in the local investigation report `scratch/birdman64-rows-investigation.md` §4) | `GE_PCDUMP`, `GE_INPUTSCRIPT` | Dump **every** frame of a scripted run at low resolution and flag frame n when it differs from n-1 but matches n-2. For any old-vs-new pixel diff outside the golden gate, run a same-commit control first. Reference: Birdman64 `tools/flicker_scan.py`. | | Flicker scan (A/B/A frame alternation) | parked (2026-10-03: tooling, nothing blocked on it; spec in the local investigation report `scratch/birdman64-rows-investigation.md` §4) | `GE_PCDUMP`, `GE_INPUTSCRIPT` | Dump **every** frame of a scripted run at low resolution and flag frame n when it differs from n-1 but matches n-2. For any old-vs-new pixel diff outside the golden gate, run a same-commit control first. Reference: Birdman64 `tools/flicker_scan.py`. |
| Release build-provenance attestation | verify | `.github/workflows/ci.yml` release job; `.github/SECURITY.md`; README Status section | **Implemented 2026-10-04:** SHA-pinned `actions/attest-build-provenance` attests `dist/*.zip[.sha256]` + `dist/*.tar.gz[.sha256]` in the tag-only release job (`id-token: write` + `attestations: write` on that job only). Backs SECURITY.md's "unsigned, but reproducible" stance with `gh attestation verify <file> --repo jkdansereau/goldeneye-pc-port`; documented in SECURITY.md and the README. **Owed:** the v0.5.0 tag build is the first real run; confirm the step passes and verification succeeds on a downloaded asset, then delete this row. | | Release build-provenance attestation | verify | `.github/workflows/ci.yml` release job; `.github/SECURITY.md`; README Status section | **Implemented 2026-10-04:** SHA-pinned `actions/attest-build-provenance` attests `dist/*.zip[.sha256]` + `dist/*.tar.gz[.sha256]` in the tag-only release job (`id-token: write` + `attestations: write` on that job only). Backs SECURITY.md's "unsigned, but reproducible" stance with `gh attestation verify <file> --repo jkdansereau/goldeneye-pc-port`; documented in SECURITY.md and the README. **Owed:** the v0.5.0 tag build is the first real run; confirm the step passes and verification succeeds on a downloaded asset, then delete this row. |
| Self-hosted CI runner link failure | open | D244 | Needs a `pacman -Syu` on the runner (maintainer-only access). Release tag builds use GitHub runners, so it doesn't block a release. | | Self-hosted CI runner link failure | open | D244 | Needs a `pacman -Syu` on the runner (maintainer-only access). Release tag builds use GitHub runners, so it doesn't block a release. |
| Remove temporary scaffolding before a release | partial | [`dev/GE-ENV-PROBES.md`](dev/GE-ENV-PROBES.md), D302 | Passes 2026-09-30 to 2026-10-03 removed the closed-finding probe suites (registry in `GE-ENV-PROBES.md`, `gen_env_probes.py --check` passing); TEMP probes `GE_TESTSTYLE` / `GE_D516` removed 2026-10-04. **Left:** D104 (kept while D294 is in verify); the M-183/M-185 clamps, **in scope 2026-10-03 (maintainer)**: re-verify all scripted-camera cutscenes with the clamps compiled out (intro flyover, per-level endings incl. the Dam abseil), then delete both blocks in `model.c`. | | Remove temporary scaffolding before a release | partial | [`dev/GE-ENV-PROBES.md`](dev/GE-ENV-PROBES.md), D302 | Passes 2026-09-30 to 2026-10-03 removed the closed-finding probe suites (registry in `GE-ENV-PROBES.md`, `gen_env_probes.py --check` passing); TEMP probes `GE_TESTSTYLE` / `GE_D516` removed 2026-10-04. **Left:** D104 (kept while D294 is in verify); the M-183/M-185 clamps, **in scope 2026-10-03 (maintainer)**: re-verify all scripted-camera cutscenes with the clamps compiled out (intro flyover, per-level endings incl. the Dam abseil), then delete both blocks in `model.c`. |
| P12 U5 review of `tools_pc/**` (release-diff, B10) | partial | `docs/dev/notes/RELEASE-BLOCKERS-v050.md` §F, D531 | **2026-10-07 (local session):** U5 reviewed (the unit that owed the P7 merge). **Blocker found + fixed in-tree:** `capture_p7.sh`'s per-level re-pin restored the local save, so the D530 box re-round ran under the box-local save — D531 (fixed + re-captured). **Applied 2026-10-07 as D532 (tooling-only):** (1) `verify.sh`'s `pin_ini_640x480` now fails closed like `pin_eep` (the old `2>/dev/null || true` call sites ran the gate under an unpinned ini on write failure — a spurious-verdict source); (2) `GOLDEN_SEED` hard-pinned with a warning for a differing stray `GE_RSEED` (the old `:-` form let the env var re-seed the gate; capture's `eval grep` still picks up the same line, so capture and gate stay consistent); (3) `audiodebug.ps1`'s dead `-AB`/`-Old` switches removed with a one-line note. **Still open on this row:** the pixel-gated box verify in a WSLg GPU-display window (D531) — crash-detect only until then. Clean: `p7_report.py`, `eep_convert.py`, `abi_ratchet.py`, `docs_budget.py`, `abpad/`, the D258/D416/PII#7 tool diffs, probe/capture deletions (`scan_op12/13.py`, the 433k-line `sweep-captures/` PPM set). | | P12 U5 review of `tools_pc/**` (release-diff, B10) | partial | D531/D532/D533 | Reviewed 2026-10-05 (the unit that owed the P7 merge). **Blocker found + fixed (D531):** `capture_p7.sh`'s per-level re-pin restored the local save, so the D530 box re-round ran under the box-local save — fixed + re-captured under the canonical eep (47/63 frames moved). **Should-fixes applied as D532 (tooling-only):** `verify.sh`'s `pin_ini_640x480` fails closed like `pin_eep`; `GOLDEN_SEED` hard-pinned with a warning for a stray `GE_RSEED`; `audiodebug.ps1`'s dead `-AB`/`-Old` switches removed. **Still open:** the pixel-gated box verify in a WSLg GPU-display window (D531) — crash-detect only until then. |
| Findings log and doc size | partial | `tools_pc/docs_budget.py` | The budget checker exists (per-file and tier-1 token budgets; `--toc FILE`). ROADMAP.md was trimmed under budget 2026-10-04. `findings.md` is still about 2 MB (~500k tokens), so agents must keep using the index. Nothing blocks; trim only if the budget check starts failing. | | Findings log and doc size | partial | `tools_pc/docs_budget.py` | Budget checker (per-file and tier-1 token budgets; `--toc FILE`). `findings.md` is still about 2 MB (~500k tokens), so agents must keep using the index. Nothing blocks; trim only when a budget check fails. |
| Branch and PR housekeeping | open | — | 30 landed local branches pruned 2026-09-30 (tips in `prune-branches-2026-09-30.txt`, notes archive). **On hold by the maintainer (do not prune yet):** probe-only `d243-verify-local`, `investigate/d243-cutscene-race`, `park/d236-probes-m139`. Local `main` and `release/v0.4.1` are deliberately not pushed. PR #62 (mouse dt-decouple) stays held until mouse feel is fundamentally better. | | Branch and PR housekeeping | open | — | 30 landed local branches pruned 2026-09-30 (tips in `prune-branches-2026-09-30.txt`, notes archive). **On hold by the maintainer (do not prune yet):** probe-only `d243-verify-local`, `investigate/d243-cutscene-race`, `park/d236-probes-m139`. Local `main` and `release/v0.4.1` are deliberately not pushed. PR #62 (mouse dt-decouple) stays held until mouse feel is fundamentally better. |
| Docs site: Web 1.0 phase 2 | decision | — | Phase 1 shipped. Phase 2 (centred serif page) is plan-only. | | Docs site: Web 1.0 phase 2 | decision | — | Phase 1 shipped. Phase 2 (centred serif page) is plan-only. |
| Docs site: press/SEO pass (2026-10-05) | partial | `docs/` site pages | Landed on the pure site pages + presentation layer: real `<h1>` masthead on every page, `color-scheme`/`theme-color`/`max-image-preview`/`rel=me` in the layout, ink-mute >=4.5:1, focus-visible + selection, 15px body, mobile padding; `date`/`modified_time` front matter on the pure pages. Home-page additions (elevator-pitch pull-quote, Overview fact table, press/coverage section) were **removed on review 2026-10-05** — each restated the tagline/intro or duplicated a section below. The five short topic notes (the-software-rsp, the-asset-pipeline, framerate-and-pacing, input-and-aim, saves) were dropped from the published set (the PD port documents the same subjects; files stay in the repo as working material). **Open:** the same front matter on the *shared* docs (`internals.md`, `porting-notes.md`, `building.md`, `dev-process.md`, `dev/agentic-development.md`) is deliberately untouched — authoritative working docs, not edited for site polish. |
| Agentic-development deep dive (doc) | queued — not yet (2026-10-05) | `docs/dev/agentic-development.md` | Write-up owed for the public case study: per-agent commit estimates / work estimates (the manual attribution pass over the session log, incl. the D350-style commit-date divergences), a code-quality audit of the trial models (GPT-6 (Sol) et al.), and the process feedback / findings. Deferred by the maintainer; pick it up when scheduled — nothing here blocks. |
| Docs site: split Security & fidelity -> two pages + v0.5.0 update pass (2026-10-05) | done (local, unpushed) | `docs/security.md`, `docs/fidelity.md` (was `security-and-fidelity-status.md`) | Split on review (the homepage pointer sat near Known issues and read as if there were security *issues*); both pages cross-linked and linked from the hub and index.md's Download section. Update pass 2026-10-05 against the `release/v0.4.1` tree: no network includes/symbols/HTTP literals in compiled `src/`+`port/`; no registry or library-loading calls; converter imports no network module; bundle manifests re-checked (allowlist + ROM/oversized-blob hard-fail); region macros re-compared vs the Makefile (all three regions); library classification re-checked (CMake globs libultra+libultrare audio, gu, `io/vitbl.c` only). Full game-logic audit not re-run; recent `src/game` edits are finding-gated. |
| Docs site: final sanity sweep + anchor fixes (2026-10-05) | done (local, unpushed) | `docs/porting-notes.md` (3 TOC hrefs), `docs/404.html` (permalink) | Audit of the 10-page published set: one h1 per page, no heading-level skips, all 42 in-page anchors resolve, titles/descriptions unique and <=160 chars, og:image/canonical present, JSON-LD parses, no local paths/usernames, served == built. Three `porting-notes.md` TOC hrefs carried a double hyphen where kramdown emits one (headings whose punctuation leaves a single separator: `(32->64):`, `D114/D116):`, `"off":`) — dead on the live GitHub Pages site, corrected at source against the live ids. `docs/404.html` needed `permalink: /404.html` (else canonical/og:url read `/404.html.html`). Preview-builder slug rule fixed to kramdown: strip punctuation, map **each** whitespace char to `-` (so ` / ` -> `--`), no run-collapsing; headings with inline markup now get ids too. |
## Community forks (not ours; reference only) ## Community forks (not ours; reference only)
+19 -9
View File
@@ -36,19 +36,29 @@ plugins:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# The site publishes a small curated set: # The site publishes a small curated set:
# index.md, under-the-hood.md (the "under the hood" hub), building.md, plus # index.md, documentation.md (the documentation hub), building.md, plus
# 404.html (themed not-found page),
# the four docs grouped behind that hub: internals.md, porting-notes.md, # the four docs grouped behind that hub: internals.md, porting-notes.md,
# dev-process.md, dev/agentic-development.md, the five short topic notes # dev-process.md, dev/agentic-development.md, and
# grouped under it (the-software-rsp.md, the-asset-pipeline.md, # security-and-fidelity-status.md (split on review 2026-10-05 into
# framerate-and-pacing.md, input-and-aim.md, saves.md), and # security.md + fidelity.md, linked from index.md's Download section and
# security-and-fidelity-status.md (linked from index.md's Known issues). # the hub).
# Everything else under docs/ is working material - the finding log, level # The five short topic notes (the-software-rsp.md, the-asset-pipeline.md,
# status, backlogs, plans, session notes, inherited decomp guides. It stays in # framerate-and-pacing.md, input-and-aim.md, saves.md) were dropped from the
# the repo (and on GitHub) but is excluded from the site build so it never # site on review 2026-10-05: the Perfect Dark port documents the same
# shows up as a published page or in sitemap.xml. # subjects and nothing here was significantly new; they stay in the repo as
# working material. Everything else under docs/ is working material - the
# finding log, level status, backlogs, plans, session notes, inherited
# decomp guides. It stays in the repo (and on GitHub) but is excluded from
# the site build so it never shows up as a published page or in sitemap.xml.
# NOTE: keep this list in sync as dev/ working docs are added; a new unlisted # NOTE: keep this list in sync as dev/ working docs are added; a new unlisted
# .md under docs/ is silently published to the site + sitemap.xml. # .md under docs/ is silently published to the site + sitemap.xml.
exclude: exclude:
- the-software-rsp.md
- the-asset-pipeline.md
- framerate-and-pacing.md
- input-and-aim.md
- saves.md
- HANDOFF.md - HANDOFF.md
- ROADMAP.md - ROADMAP.md
- SetupGuide.md - SetupGuide.md
+117 -16
View File
@@ -21,7 +21,9 @@
--bg-panel: #121316; /* code / cards / tables */ --bg-panel: #121316; /* code / cards / tables */
--ink: #e6e4df; /* warm off-white */ --ink: #e6e4df; /* warm off-white */
--ink-soft: #a9a7a0; /* secondary text */ --ink-soft: #a9a7a0; /* secondary text */
--ink-mute: #70706a; /* captions, footer */ --ink-mute: #8a8a83; /* captions, footer (>=4.5:1 on --bg-frame:
the old #70706a measured 3.9:1 and failed
WCAG AA on the tagline + legal line) */
--line: #26282c; /* 1px borders */ --line: #26282c; /* 1px borders */
--line-2: #3a3d44; /* stronger borders */ --line-2: #3a3d44; /* stronger borders */
--accent: #e8a13a; /* GoldenEye gold (amber) */ --accent: #e8a13a; /* GoldenEye gold (amber) */
@@ -40,8 +42,9 @@
margin: 0; margin: 0;
color: var(--ink); color: var(--ink);
font-family: var(--sans); font-family: var(--sans);
font-size: 14px; font-size: 15px; /* 14px read as console chrome, but the
line-height: 1.62; body is prose people actually read */
line-height: 1.6;
/* faint starfield (the old-school "space" tile, softened) */ /* faint starfield (the old-school "space" tile, softened) */
background-color: var(--bg); background-color: var(--bg);
background-image: background-image:
@@ -63,6 +66,14 @@
} }
a:hover { color: var(--accent-hi); text-decoration-color: currentColor; } a:hover { color: var(--accent-hi); text-decoration-color: currentColor; }
/* keyboard focus + selection: the amber thread again, so a focused
control is visible on the near-black ground (a11y / keyboard users) */
:focus-visible {
outline: 2px solid var(--accent-hi);
outline-offset: 2px;
}
::selection { background: var(--accent); color: #0b0b0d; }
/* ---- the centred "page" frame -------------------------------------- */ /* ---- the centred "page" frame -------------------------------------- */
.frame { .frame {
max-width: 50rem; max-width: 50rem;
@@ -75,11 +86,13 @@
/* ---- banner -------------------------------------------------------- */ /* ---- banner -------------------------------------------------------- */
.banner { text-align: center; padding: 2.4rem 1rem 1.4rem; } .banner { text-align: center; padding: 2.4rem 1rem 1.4rem; }
.banner .t { .banner .t {
margin: 0; /* it is an <h1> now (see the layout) */
font-family: var(--mono); font-family: var(--mono);
font-weight: 700; font-weight: 700;
font-size: 1.7rem; font-size: 1.7rem;
letter-spacing: .05em; letter-spacing: .05em;
color: var(--ink); color: var(--accent); /* brand name in goldeneye gold -- the amber
thread (masthead -> nav -> rule -> page title) */
} }
.banner .tag { color: var(--ink-mute); font-size: .82rem; margin-top: .55rem; } .banner .tag { color: var(--ink-mute); font-size: .82rem; margin-top: .55rem; }
@@ -131,6 +144,23 @@
border-bottom: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
} }
.doc-content h2::before { content: "\25aa "; color: var(--accent); } .doc-content h2::before { content: "\25aa "; color: var(--accent); }
/* Page-title look: the 2026-09 SEO pass demoted page headings to h2
(the masthead owns h1; no duplicate page titles) -- see the SEO
conventions note in scratch/pr-seo-revise-prompt.md. The first
content h2 of each page gets the h1 look; presentation only, the
heading levels stay per-convention. (On the home page the masthead
itself is the title, so its first h2 -- Status -- leads as a section.) */
/* .flat-title (front matter on the home page): the masthead IS the
page title there, so the first h2 must read as a plain section --
otherwise masthead-h1 + amber first-h2 stack as a double header. */
.doc-content:not(.flat-title) > h2:first-of-type {
font-size: 1.5rem;
font-weight: 700;
color: var(--accent);
margin: .2rem 0 1rem;
padding-bottom: 0;
border-bottom: 0;
}
.doc-content h3 { .doc-content h3 {
font-family: var(--mono); font-family: var(--mono);
font-size: .92rem; font-size: .92rem;
@@ -189,21 +219,88 @@
} }
.doc-content tr:nth-child(2n) td { background: var(--zebra); } .doc-content tr:nth-child(2n) td { background: var(--zebra); }
/* ---- console blocks ------------------------------------------------ */
/* Status / News / Download / Known issues panels (home page). Same
amber-terminal language as the code blocks above, but the content
keeps its semantic list/table markup (SEO + screen readers).
Site formatting rules (2026-10-05 PR pass + 2026-09 SEO conventions)
— keep these:
- Heading LEVELS follow the SEO pass: the page heading is h2 (the
masthead owns h1; no duplicate page titles), sections are h2,
h3 labels a real sub-topic only (e.g. the current-release line
under Status). The first content h2 gets the amber "page-title"
look via CSS only (.doc-content > h2:first-of-type) -- never by
promoting the markup to h1.
- h2 = the section, outside the panel.
- Directives ("always use the latest release") are .callouts inside
panels, or a .warn line (amber rule, ink text) where no panel
exists; never headings — headings label topics,
never emphasis.
- List intros ("what a player will notice…") stay plain paragraphs.
- Dated list-item leads ("2026-10-05 — v0.5.0") stay <strong> leads
inside the <li>, not headings.
- Headings must be single source lines: marked ends an ATX heading at
the line break, so a wrapped "### …" silently becomes a heading plus
a stray paragraph (Jekyll/other renderers differ — don't rely on
multi-line headings at all). */
.doc-content .cblock {
background: var(--bg-panel);
border: 1px solid var(--line);
padding: 1.1rem 1.3rem .9rem;
margin: 1.6rem 0;
}
/* Expandable panels (<details>, e.g. the release history folded under
Status): same panel language as .cblock; the summary line is the
amber handle. The content is in the DOM either way -- collapsing is
presentation, not hiding from search. */
.doc-content details {
background: var(--bg-panel);
border: 1px solid var(--line);
padding: .3rem 1.3rem .8rem;
margin: 1.6rem 0;
}
.doc-content summary {
font-family: var(--mono);
font-size: .9rem;
font-weight: 600;
color: var(--accent);
letter-spacing: .03em;
cursor: pointer;
}
.cblock h3 { margin-top: 0; color: var(--ink); }
.cblock p, .cblock ul, details p, details ul {
font-family: var(--mono);
font-size: .88rem;
line-height: 1.6;
}
.cblock li, details li { margin: .5rem 0; }
.cblock li::marker, details li::marker { color: var(--accent); }
.cblock strong, details strong { color: var(--accent); font-weight: 600; }
.cblock code, details code { background: transparent; border: 0; padding: 0; }
.doc-content .callout {
border-left: 3px solid var(--accent);
padding: .15rem 0 .15rem .8rem;
margin: 0 0 1rem;
}
.doc-content .callout p { color: var(--ink-soft); }
/* Inline directive marker -- "Warning:" leading a sentence, amber like
the rest of the accent thread, no panel around it. */
.doc-content details .warn {
border-left: 3px solid var(--accent);
padding: .1rem 0 .1rem .7rem;
margin: .2rem 0 .9rem;
font-weight: 600;
}
.cblock table { background: transparent; margin: 1rem 0 .4rem; }
.cblock > p:last-child { margin-bottom: 0; }
/* ---- images -------------------------------------------------------- */ /* ---- images -------------------------------------------------------- */
.doc-content img { .doc-content img {
border: 1px solid var(--line); border-radius: 0; max-width: 100%; border: 1px solid var(--line); border-radius: 0; max-width: 100%;
} height: auto; /* no squashed stills when a width= is set */
/* ---- details / summary (the "full gallery" collapse) --------------- */
.doc-content details {
max-width: var(--measure);
border: 1px solid var(--line);
background: var(--bg-panel);
padding: .6rem .9rem; margin: 1.5rem 0;
}
.doc-content summary {
cursor: pointer; color: var(--accent);
font-family: var(--mono); font-size: .85rem; letter-spacing: .03em;
} }
/* ---- console-viewer carousel (home page media) --------------------- */ /* ---- console-viewer carousel (home page media) --------------------- */
@@ -261,7 +358,11 @@
@media (max-width: 40rem) { @media (max-width: 40rem) {
.frame { margin: 8px; } .frame { margin: 8px; }
.banner { padding: 1.4rem .8rem 1rem; }
.banner .t { font-size: 1.35rem; } .banner .t { font-size: 1.35rem; }
.doc-content { padding: 1.1rem 1rem .5rem; }
.doc-content table { font-size: .82rem; }
.doc-content pre { padding: .7rem .8rem; }
} }
</style> </style>
+25 -6
View File
@@ -3,26 +3,44 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Paint the browser chrome (scrollbars, form controls, new-tab cards)
dark before CSS loads, so the page never flashes white on mobile. -->
<meta name="color-scheme" content="dark">
<meta name="theme-color" content="#050607">
<!-- Indexing is NOT restricted: this only asks Google/Bing to show the
large image preview in search cards, which is what makes the
in-engine stills legible in a coverage roundup. -->
<meta name="robots" content="max-image-preview:large">
<link rel="icon" type="image/jpeg" href="{{ '/img/shots/shot-28.jpg' | relative_url }}"> <link rel="icon" type="image/jpeg" href="{{ '/img/shots/shot-28.jpg' | relative_url }}">
<!-- Entity disambiguation: the maintainer behind every page. -->
<link rel="me" href="https://github.com/jkdansereau">
{%- seo -%} {%- seo -%}
{%- include head-custom.html -%} {%- include head-custom.html -%}
</head> </head>
<body> <body>
<div class="frame"> <div class="frame">
<!-- The masthead IS the page's h1: every page gets exactly one h1
(the brand), and the page's own heading starts at h2. A <div>
here left the document with no h1 at all, which is what search
and screen readers key on. Presentation only -- the CSS class
carries the look. -->
<header class="banner"> <header class="banner">
<div class="t">{{ site.title }}</div> <h1 class="t">{{ site.title }}</h1>
<div class="tag">{{ site.description }}</div> <p class="tag">{{ site.description }}</p>
</header> </header>
<nav class="sitenav"> <nav class="sitenav" aria-label="Site navigation">
<a href="{{ '/' | relative_url }}">home</a><span class="sep">/</span> <a href="{{ '/' | relative_url }}">home</a><span class="sep">/</span>
<a href="{{ '/under-the-hood' | relative_url }}">under the hood</a><span class="sep">/</span> <a href="{{ '/documentation' | relative_url }}">documentation</a><span class="sep">/</span>
<a href="{{ '/building' | relative_url }}">building</a> <a href="{{ '/building' | relative_url }}">building</a>
</nav> </nav>
<div class="rule g"></div> <div class="rule g"></div>
<main class="doc-content"> <!-- flat_title: this page's masthead IS its title, so the layout opts
out of the amber first-h2 "page-title" look (no double header).
Jekyll + the preview builder both honour this conditional. -->
<main class="doc-content{% if page.flat_title %} flat-title{% endif %}">
{{ content }} {{ content }}
</main> </main>
@@ -30,7 +48,8 @@
<footer class="site-footer"> <footer class="site-footer">
<div class="footer-stamp"> <div class="footer-stamp">
last updated: 2026-10-07 &middot; v0.5.0 <a href="https://github.com/jkdansereau">maintained by jkdansereau</a>
&nbsp;&middot;&nbsp; last updated: 2026-10-05 &middot; v0.5.0
&nbsp;&middot;&nbsp; <a href="https://github.com/jkdansereau/goldeneye-pc-port">GitHub</a> &nbsp;&middot;&nbsp; <a href="https://github.com/jkdansereau/goldeneye-pc-port">GitHub</a>
&nbsp;&middot;&nbsp; <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases">releases</a> &nbsp;&middot;&nbsp; <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases">releases</a>
</div> </div>
+3 -2
View File
@@ -51,7 +51,7 @@ toolchain is involved in extraction or in the PC build.** (The IDO toolchain is
only needed to build the N64 ROM itself, and its proprietary SGI binaries are only needed to build the N64 ROM itself, and its proprietary SGI binaries are
not distributed here; see [`SetupGuide.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/SetupGuide.md) "Recompile IDO".) not distributed here; see [`SetupGuide.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/SetupGuide.md) "Recompile IDO".)
On Windows this is easiest under WSL or a Linux VM. Full details and On Windows this is easiest under WSL or a Linux VM. Full details and
alternatives (Docker) are in [`SetupGuide.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/SetupGuide.md). alternatives (Docker) are in `SetupGuide.md`.
--- ---
@@ -98,7 +98,8 @@ On Windows, `build-pc.sh` also locates the MSYS2 MinGW64 toolchain itself
`cmake` earlier on PATH) and, if native child processes would get an `cmake` earlier on PATH) and, if native child processes would get an
unwritable `TMP`, re-runs the configure+build under PowerShell with a unwritable `TMP`, re-runs the configure+build under PowerShell with a
writable one. If MSYS2 is not installed at `C:\msys64`, set writable one. If MSYS2 is not installed at `C:\msys64`, set
`GE_MSYS2_ROOT` (e.g. `GE_MSYS2_ROOT='D:\M\msys64'`). Re-exec logs: `GE_MSYS2_ROOT` (e.g. `GE_MSYS2_ROOT='C:\tools\msys64'` for a custom
install location). Re-exec logs:
`build-pc/ge007-native-reexec-*.log`. `build-pc/ge007-native-reexec-*.log`.
For PAL/JP you must first generate that region's ROM-asset symbol file For PAL/JP you must first generate that region's ROM-asset symbol file
+1
View File
@@ -120,6 +120,7 @@ Two classes:
| `GE_FILESELECT_OVERLAY` | `port/src/frontoptions.c:96` | One-PC-options-UI (D519) test hook: opens the F10 overlay over file select without a click; value `n` > 1 also closes it `n` label-frames later. Replaces the retired front-screen probes (the FRONTOPTIONS_SECTION, FRONTNAVLOG, FRONTOPTS_WIDTHS and FRONTOPTIONS_AUTO probes). | **live** (harness) | | `GE_FILESELECT_OVERLAY` | `port/src/frontoptions.c:96` | One-PC-options-UI (D519) test hook: opens the F10 overlay over file select without a click; value `n` > 1 also closes it `n` label-frames later. Replaces the retired front-screen probes (the FRONTOPTIONS_SECTION, FRONTNAVLOG, FRONTOPTS_WIDTHS and FRONTOPTIONS_AUTO probes). | **live** (harness) |
| `GE_WSPROBE` (+ `GE_WSPROBE_FRONT`, `GE_WSPROBE_RESET`, `GE_WSPROBE_F10FRONT`) | `port/src/watchsettings.c:616,568,512`, `port/src/optionsoverlay.c:1566` | D354 watch-settings probe family: `WSPROBE[=tick]` logs before/after the queued settings commit one tick apart; `_FRONT[=tick]` drives a headless front-end change scenario; `_RESET` prepares an options-reset after 120 front ticks and verifies persistence once the stage drains; `_F10FRONT` fires a one-shot F10→front poll after the file-select save becomes available (avoids the joyDisablePoll deadlock). | **live** (diagnostic) | | `GE_WSPROBE` (+ `GE_WSPROBE_FRONT`, `GE_WSPROBE_RESET`, `GE_WSPROBE_F10FRONT`) | `port/src/watchsettings.c:616,568,512`, `port/src/optionsoverlay.c:1566` | D354 watch-settings probe family: `WSPROBE[=tick]` logs before/after the queued settings commit one tick apart; `_FRONT[=tick]` drives a headless front-end change scenario; `_RESET` prepares an options-reset after 120 front ticks and verifies persistence once the stage drains; `_F10FRONT` fires a one-shot F10→front poll after the file-select save becomes available (avoids the joyDisablePoll deadlock). | **live** (diagnostic) |
| `GE_ZF` (+ `GE_ZFTOL`, `GE_ZFBOX`) | `port/fast3d/gfx_pc.cpp:1653-1657` | Z-fight grid probe: per tri emit, buckets the centroid cell and flags cells that fight ≥5 times (cap 600 hits); `ZFTOL`=tolerance, `ZFBOX="x0 y0 x1 y1"`=world-box filter. | **live** (diagnostic) | | `GE_ZF` (+ `GE_ZFTOL`, `GE_ZFBOX`) | `port/fast3d/gfx_pc.cpp:1653-1657` | Z-fight grid probe: per tri emit, buckets the centroid cell and flags cells that fight ≥5 times (cap 600 hits); `ZFTOL`=tolerance, `ZFBOX="x0 y0 x1 y1"`=world-box filter. | **live** (diagnostic) |
| `GE_D526` (+ `GE_D526BOX`, `GE_D526MAX`) | `port/fast3d/gfx_pc.cpp:1895,2024,2032,2034` | D526 per-triangle draw-state census probe (text-only): `GE_D526="lo-hi"` = sim-frame range (same dash syntax as `GE_D75D`); `GE_D526BOX="x0 y0 x1 y1"` = NDC region filter (same syntax as `GE_ZFBOX`, default on-screen); `GE_D526MAX` caps per-triangle lines (default 400). Per emitted in-region tri: frame, NDC bbox, z/w, geometry_mode, other_mode_l/h, combine word, sampled tile tmem/fmt/siz, first_tile_index, prim alpha, vertex alpha min/max, use_alpha/modulate/invisible — plus one per-frame line aggregating in-region tris by (comb, oml, omh, alpha) signature. Retained as a generic transparency/texture triage tool (D195/D266/D268/D273 class); the D526 grate case itself was confirmed faithful N64 behaviour, so no fix shipped. Zero cost unless `GE_D75D`/`GE_ZF`/`GE_D303`/`GE_D526` is set (folded into the D474 `tri_dbg` gate). | **live** (diagnostic) |
## Dxx diagnostic probes — finding closed unless noted ## Dxx diagnostic probes — finding closed unless noted
+216 -1
View File
@@ -3,7 +3,8 @@
> **Local machine paths are genericised** in this archive: `<repo>` = this repo's > **Local machine paths are genericised** in this archive: `<repo>` = this repo's
> working directory, `<repos>` = the local source-repos root, `<games>` / `<videos>` > working directory, `<repos>` = the local source-repos root, `<games>` / `<videos>`
> = the local games / video roots, `<python>` = the local CPython install, `<temp>` > = the local games / video roots, `<python>` = the local CPython install, `<temp>`
> = a writable native temp dir. Session facts are unchanged. > = a writable native temp dir, `<msys>` = the local MSYS2 install root.
> Session facts are unchanged.
> **Reference only.** Current state lives in the [README](../../README.md) > **Reference only.** Current state lives in the [README](../../README.md)
> "Status" section and `docs/dev/LEVEL-STATUS.md`; per-finding detail is in > "Status" section and `docs/dev/LEVEL-STATUS.md`; per-finding detail is in
@@ -6168,3 +6169,217 @@ Run from the **repo root**, not `build-pc/`.
rating, don't hack it in. rating, don't hack it in.
3. Prefer an **offline sidecar converter** (`tools_pc/d*_emit.py`, 3. Prefer an **offline sidecar converter** (`tools_pc/d*_emit.py`,
D43/D69/D88 pattern) over a runtime fixup for a whole ROM-asset format. D43/D69/D88 pattern) over a runtime fixup for a whole ROM-asset format.
---
# Appended 2026-10-05 (session 07j) — moved verbatim from `docs/HANDOFF.md` (briefs 2026-10-05 (session 07d) → 2026-10-05 (session 07g))
# HANDOFF — 2026-10-05 (session 07d)
## Branch
`release/v0.4.1` @ `e9cf2ddf` (D530 addendum), tree clean.
Local-only commits on top of `442eb2ff`: `aa19b354` (site SEO/redundancy),
`2c378e7e`+`24b084d0` (Known issues), `ada7bbb1` (D530 goldens), `e9cf2ddf`
(D530 addendum). **Nothing pushed.**
## This session (2026-10-05 (session 07d), user stepped away ~10:45, returns ~14:00 EDT)
1. **HANDOFF 07c item 1 (critical path) — DONE, committed (`ada7bbb1`):**
- The X220 P7 re-round had completed on the box 2026-10-05 (tree `442eb2ff`,
worktree `~/gh-fullhist-wt-p7`, `~/p7-reround.log` hit `P7 re-round DONE`
12:53 EDT, **21/21 levels rc=0** under the canonical `ge007.eep`).
- Pulled the 63 PNGs (15 MB tarball → `scratch/p7-pull/`, log →
`scratch/p7-reround-pull.log`) and committed them into
`tools_pc/golden/<level>/linux/`, replacing the D525 cleared-eep set:
**51/63 differ; 12/63 byte-identical** (save-independent scenes,
including frigate's first stem 001000 — a D117 stability signal).
- **D117 flaky-four first-stem check (D529 never-do 6, first cross-machine
test):** dam@1500 worst_cell 1.70 (phash 0), frigate@1000 byte-identical,
streets@1000 1.78 (phash 0), jungle@900 5.12 (phash 3) — all in
stable-level range, **none red → NO first-stem exclusion/widening**.
- Structural tier all `ok` (cradle@40 documented exception; Cuba 26.4%
within the documented 23.7–36.3% structural-only range). The `fail` rows
in the box report are the expected cross-eep diffs vs the old set.
- **Closes D529 never-do 3:** the index/README v0.5.0 "re-based on both
platforms (21 levels, 63 frames each)" line now stands on a
canonical-eep linux set → linux numbers unblocked (B7 satisfied).
- Wrote **D530** (findings.md detail + §F table: D523 now SUPERSEDED-by-
D529, D529 row was missing from the table — the 07c CSV had been
hand-patched, which is why `gen_findings_index.py --check` drifted;
regenerated) + `tools_pc/golden/README.md` linux-set text + History.
2. **DONE: fresh `verify.sh sweep` on the box against the NEW goldens**
(shipped the 51 PNGs to `~/gh-fullhist-wt-p7`, box diff = 51 = the
tree delta; fired 10:5x EDT, finished ~11:10 EDT): **21/21 PASS, 0
FAIL** — but the run was **crash-detect only** (GE_PCDUMP reads black
on the box's llvmpipe/WSLg, the D244 note; no pixel gate). So it is a
stability re-check; the D117 cross-machine *pixel* evidence remains the
re-round capture itself (the D530 first-stem check). Recorded as the
D530 addendum (`e9cf2ddf`) with the residual: a pixel-gated box verify
needs a working WSLg GPU session (the 10-05 re-round's pixel comparisons
ran fine, so one exists).
- Log pulled: `scratch/p7-verify-new-pull.log` (tail: `21` PASS, `0`
FAIL, `SWEEP DONE`).
3. **DONE (partial, at push time still owed): PII scrub addendum for the 51
new golden PNGs** — EXIF/text metadata sweep over all 63 linux PNGs:
**0 metadata tags** (PIL); new doc text (D530, golden README) uses
"X220" + `~/` paths only — no absolute paths/usernames/private IPs in
tracked files (the box LAN address lives only in the gitignored
HANDOFF + scratch logs). Addendum appended to
`docs/dev/notes/PII-SCRUB-REPORT.md` (gitignored). The full
LEGAL-review pass (game-content rule for screenshots) is still owed at
push time.
## User to review at ~14:00 EDT
- Local batch of 5 doc/golden commits (`aa19b354` SEO/redundancy;
`2c378e7e`+`24b084d0` Known issues; `ada7bbb1` D530 goldens; `e9cf2ddf`
D530 addendum — box sweep 21/21 crash-detect PASS).
- Then the standing HANDOFF 07c items: 2. maintainer review of the 12-file
batch; 3. P12 U2/U5/U6/U7 (deferred light-unit mechanical review);
4. re-cut squash → B7/B8/B9 (README linux numbers now unblocked);
5. push `release/v0.5.0` + tag.
## Environment
- Preview: `:8777` (PID may be stale after a reboot — `node
scratch/build_preview.mjs site && node scratch/serve_preview.mjs 8777`).
- Box ssh: `ssh the test box` (Windows→box works; box has no sshd —
everything rides the same session's stdin/stdout; pushes via
`cat f | ssh ... 'cat > dest'` or tar pipes).
- 3 parked worktrees (ci/d441/modpatch) untouched.
---
# HANDOFF — 2026-10-05 (session 07e) (D531 + P12 U5)
## Branch
`release/v0.4.1` @ `164920c6`, tree clean. Three more local-only commits on
top of `e9cf2ddf`: `4829fd94` (D531 blocker fix + canonical re-capture),
`d2d75e11` (ROADMAP rows), `164920c6` (D531 addendum). **Nothing pushed.**
## This session (2026-10-05 (session 07e))
**D531 — `capture_p7.sh` canonical-re-pin blocker (P12 U5 review finding),
fixed + re-captured. AMENDS D530.**
- U5 reviewed `tools_pc/**` (the release-diff unit that owed the P7 merge):
small diffs all mechanical/clean; `p7_report.py`, `eep_convert.py`,
`abi_ratchet.py`, `docs_budget.py`, `abpad/` clean (list-arg subprocess,
raw_decode JSON, no shell, no destructive ops); deletions clean (probe
tools + the 433k-line sweep-capture PPM set). **But** `capture_p7.sh`'s
D529 adaptation was incomplete: the D524-era per-level re-pin
(`cp "$EEP_ORIG" "$EEP"`, restoring the pre-capture LOCAL save) silently
overwrote D529's pre-loop canonical install from level 1 — so **the
10-05 box re-round (D530) ran under the box-local save, not the
canonical eep**. D530's "canonical eep" provenance claim and first-stem
table are void as canonical-save evidence (D530 entry + README amended in
place; the table's numbers do check out against the 10-05 report).
**The win set is unaffected** — `verify.sh`'s `pin_eep` was correct.
- Fix: the loop now re-pins `cp "$CANON_EEP" "$EEP"` per level (EEP_ORIG
kept for the exit-restore only); `cd "$ROOT"` added (the loop's
dump/golden paths are root-relative, contradicting the header's
"invoked from anywhere" claim).
- **Re-captured:** shipped the fixed script to the box (sha matched), fresh
21-level round with `DISPLAY=:0` → 21/21 rc=0, 63 frames. **47/63 differ
from the D530 box-local-save set** (save content demonstrably moves
frames), 16 byte-identical. Committed into the linux goldens.
- **Renderer finding (corrects the 07d item-2 note):** even with
`DISPLAY=:0` the box today reports no usable glxinfo renderer (software
fallback → black read-backs) — the WSLg GPU display is
**session-state-dependent** (the 10-05 re-round's p7_report pixel table
proves it was GPU-backed then). Today's `verify.sh sweep` against the new
goldens: **21/21 PASS, 0 FAIL, crash-detect only** (log
`scratch/p7-verify-pixel-pull.log`). The pixel-gated verdict (incl. the
four D117 flaky first stems) is owed for a GPU-display window.
- Docs: D531 entry + §F row (regenerated CSV, 394 lines, `--check` OK),
D530 amended in place, golden README intro + History, ROADMAP Golden
baselines row (was still on D523 framing) + new P12 U5 row. PII addendum
#2 (63 PNGs, 0 metadata tags).
**U5 should-fixes (rows on the ROADMAP, not yet applied):**
1. `verify.sh` `pin_ini_640x480 2>/dev/null || true` fails OPEN (pin_eep
fails closed) — a failed ini write runs the gate under the user's
personal ini → spurious verdicts. Make it abort.
2. `GOLDEN_SEED="${GE_RSEED:-…}"` lets a stray env var re-seed the gate —
warn or hard-pin (capture inherits the same override via its eval out
of verify.sh, so gate/capture stay consistent either way).
3. `audiodebug.ps1` `-AB`/`-Old` are documented dead no-ops (nit).
## User to review at ~14:00 EDT (supersedes the 07d list)
- 8 local commits: `aa19b354` (site SEO/redundancy), `2c378e7e` +
`24b084d0` (Known issues), `ada7bbb1` (D530 goldens — now AMENDED BY
D531), `e9cf2ddf` (D530 addendum), `4829fd94` (D531), `d2d75e11`
(ROADMAP), `164920c6` (D531 addendum).
- Preview: `node scratch/build_preview.mjs site` → `scratch/_site/` on :8777.
## Still owed (unchanged, plus)
- Pixel-gated box verify in a WSLg GPU-display window (never-do 6 applies
if the flaky four go red: exclude/widen, do NOT recapture).
- The three U5 should-fixes above; P12 U2/U6/U7; HANDOFF 07c item 2
(maintainer review of the 12-file docs batch); squash → B7/B8/B9; push
`release/v0.5.0` + tag.
- LEGAL review pass at push time (screenshots rule — 47 new linux PNGs are
the same class: box-captured, no metadata).
---
# HANDOFF — 2026-10-05 (session 07f) (D532 + squash re-cut + PUSH)
## Pushed (2026-10-05 (session 07e)/f, maintainer approved)
- **GitHub** `origin`: new branch `release/v0.5.0` (the re-cut squashed
chain, 33 commits, tip `f077435a`) + annotated tag `v0.5.0`.
**`origin/main` untouched** (`0e8c2ce2`) — main merge + public release
wait for the maintainer's playtest.
- **Forgejo mirror**: `release/v0.5.0-squashed` + tag `v0.5.0`.
- Squash re-cut: `scratch/p11b-squash.py` (p11 + new tip `4dd1d56d`,
assert 488, new group 33 covering D529-D532 + the site/amber pass).
Tip tree byte-identical (B7), LAN scrub of intermediate trees
re-applied, `pre-squash-v050` -> `4dd1d56d` (B6), tag message in
`scratch/tag-msg-v050.txt` (B8), PII/legal addenda on the final tree
(B9: clean; 4 pre-existing toolchain-path sites only).
- **D532** (`4dd1d56d`) landed before the cut: verify.sh fail-closed
ini pin + hard-pinned seed (warn on stray `GE_RSEED`), audiodebug
dead switches removed. Docs: D532 entry/row, ROADMAP U5 row applied.
## Now owed (in order)
1. **Maintainer playtest** (C6 list: D511-D514/D519 items) on the
`release/v0.5.0` build → then remove the "not yet playtested live"
block and cut the `gh release` (C1-C9; bundles built FROM the pushed
tree).
2. **Pixel-gated box verify** in a WSLg GPU-display window (D531; the
box worktree `~/gh-fullhist-wt-p7` is still at `442eb2ff` — needs a
bundle transfer of the new tip; no LAN route, options per the P7
handback §8).
3. **P12 U2/U6/U7** quick passes (U1/U3/U4/U5 PASS; U6 = build+CI
diff, U7 = docs diff — read-only, ROADMAP rows for should-fixes).
4. CI on the new GitHub branch: first real run of the SLSA
build-provenance attestation (ROADMAP "Release build-provenance
attestation" row: confirm, then delete).
5. Box-side parallel: self-gate on the release branch (crash-detect
until the GPU window).
## Local state
`release/v0.4.1` @ `4dd1d56d` (== the pushed squashed tip tree), tree
clean. `release/v0.5.0` / `release/v0.5.0-squashed` @ `f077435a`.
`pre-squash-v050` @ `4dd1d56d`. Nothing else pending locally.
---
# HANDOFF — 2026-10-05 (session 07g) (push reverted; held local)
- **GitHub push REVERTED** (branch `release/v0.5.0` + tag `v0.5.0` deleted,
verified via `git ls-remote`); backup lives on the private Forgejo mirror
(`release/v0.5.0-squashed` + tag `v0.5.0` @ `f077435a`). Local refs:
`release/v0.5.0` / `release/v0.5.0-squashed` @ `f077435a`,
`pre-squash-v050` @ `4dd1d56d`.
- **Standing rule (maintainer):** backups → Forgejo, never GitHub; GitHub
pushes only after the maintainer approves everything.
- **Docs finalization owed:** the batch review (`scratch/docs-batch-review.txt`,
commit `ba29c558` — 16 text files) and the **PR/SEO language pass**
(brief written: `scratch/pr-seo-revise-prompt.md` — tiers T1/T2/T3, voice,
SEO parity checklist, hard rules; example fix = the v0.5.0 News tagline
leading with "plain-English wording" + the UK/US spelling item demoted to
"small stuff").
- Then: playtest (C6) → `gh release` (C1–C9) → the ONE approved GitHub push
(release branch + tag + release) → main.
---
+3 -20
View File
@@ -12,8 +12,8 @@ part-time direction. The goal, the setup, the timeline, and an honest read on
what did and didn't work.* what did and didn't work.*
> *Snapshot as of the v0.3.0 milestone (20 Sep 2026; findings through D321). > *Snapshot as of the v0.3.0 milestone (20 Sep 2026; findings through D321).
> v0.4.0 (28 Sep) extended the timeline with the options/input work -- the > v0.4.0 (28 Sep) extended the timeline with the options/input work — the
> README's Background section carries the final project numbers.* > README's "How it was made" section carries the final project numbers.*
## Contents ## Contents
@@ -300,25 +300,8 @@ last few weeks), which has driven the most recent work. The local menu:
**mostly deprecated now**: hand-offs between agents are done by hand for now, **mostly deprecated now**: hand-offs between agents are done by hand for now,
pending a better parallel-agent handoff system that drops the MCP overhead. pending a better parallel-agent handoff system that drops the MCP overhead.
- **GPT-6 (Sol)** via [OpenRouter](https://openrouter.ai) — a frontier hosted - **GPT-6 (Sol)** via [OpenRouter](https://openrouter.ai) — a frontier hosted
model, **trialed** to see how it held up (not the hardest-work tool). Its model, **trialed** to see how it held up (not the hardest-work tool).
code output is still owed a code-quality audit in this doc.
The practical effect: the project stopped depending on any one model or its The practical effect: the project stopped depending on any one model or its
usage limits. The local GPU is now the default path for high-volume work, with usage limits. The local GPU is now the default path for high-volume work, with
hosted frontier models reserved for the problems the local models can't close. hosted frontier models reserved for the problems the local models can't close.
**Measurement owed.** Which of these was best on a given task — and each
model's rough cost-to-performance ratio — has not yet been measured properly;
attributing individual commits to the model that produced them is still a
manual pass. That includes a **code-quality audit of the GPT-6 (Sol) trial**.
All of it is pending and will be added here when it lands.
A concrete reason the commit-date route is unreliable: the `D350` commit
(`1303c0eb`, "expose watch-backed Bond settings in PC options and F10")
carries a **27 Sep** timestamp on both its author and committer dates, but
the session notes place that work on **4 Oct**. Because the two git dates
agree, this is **not** a rebase artifact (a rebase would have moved the
committer date while preserving the author date); it is a genuine divergence
between the recorded commit time and the working session, and resolving it
takes the session log, not the commit date. This is the class of edge case
the attribution pass has to walk by hand.
+8 -6
View File
@@ -382,14 +382,16 @@ D519,FIXED,"One PC options UI: the file-select ""PC Options"" entry opens the F1
D520,FIXED,"F10 overlay slider wedge, slider marker and dropdown arrow antialiased (they stepped in whole canvas pixels that grow with the window) —",FIXED (headless before/after capture; by-eye owed) D520,FIXED,"F10 overlay slider wedge, slider marker and dropdown arrow antialiased (they stepped in whole canvas pixels that grow with the window) —",FIXED (headless before/after capture; by-eye owed)
D521,PARTIAL,A fixed-frame golden window that overlaps the intro flyby is platform-nondeterministic (cross-platform goldens); verify.sh's linux pixel-gate skip is driver-co…,PARTIAL (rule recorded 2026-10-04; the two residual bands CLOSED 2026-10-05 by D525's box re-round — D521,PARTIAL,A fixed-frame golden window that overlaps the intro flyby is platform-nondeterministic (cross-platform goldens); verify.sh's linux pixel-gate skip is driver-co…,PARTIAL (rule recorded 2026-10-04; the two residual bands CLOSED 2026-10-05 by D525's box re-round —
D522,FIXED,The golden window's frame-900 stem is not settled gameplay on several levels —,FIXED 2026-10-05 (recipe-side re-base: D522,FIXED,The golden window's frame-900 stem is not settled gameplay on several levels —,FIXED 2026-10-05 (recipe-side re-base:
D523,CLOSED,The golden recipe does not pin save state:,SUPERSEDED by D529 (2026-10-07) — D523,CLOSED,The golden recipe does not pin save state:,SUPERSEDED by D529 (2026-10-05) —
D524,FIXED,The golden tooling was destructive and drift-prone:,FIXED 2026-10-05 (both pins idempotent — D524,FIXED,The golden tooling was destructive and drift-prone:,FIXED 2026-10-05 (both pins idempotent —
D525,FIXED,"The whole <level>/linux/ golden set was stale, not just on the six re-based levels —","FIXED 2026-10-05 (21-level box re-round, 63 frames, save pinned present; structural parity 21/21, Archives/Streets bands attributed to save state, not a renderer)" D525,FIXED,"The whole <level>/linux/ golden set was stale, not just on the six re-based levels —","FIXED 2026-10-05 (21-level box re-round, 63 frames, save pinned present; structural parity 21/21, Archives/Streets bands attributed to save state, not a renderer)"
D526,CLOSED,P13 Dam-ending grate / edge-railing transparency is faithful N64 behaviour (port == 1964/GEPD); the per-triangle census probe is retained as a generic draw-sta…,"CLOSED — faithful, confirmed on 1964/GEPD (2026-10-07):" D526,CLOSED,P13 Dam-ending grate / edge-railing transparency is faithful N64 behaviour (port == 1964/GEPD); the per-triangle census probe is retained as a generic draw-sta…,"CLOSED — faithful, confirmed on 1964/GEPD (2026-10-05):"
D527,OPEN,GE_PCDUMP written first:last (a colon where the dash belongs) silently dumps EVERY frame —,OPEN (harness documentation; a log-or-fail-closed fix is owed in the port layer) D527,OPEN,GE_PCDUMP written first:last (a colon where the dash belongs) silently dumps EVERY frame —,OPEN (harness documentation; a log-or-fail-closed fix is owed in the port layer)
D528,OPEN,"GE_STARTMENU skips the EEPROM read, so front-end-only sessions never import the emulator save —",OPEN (harness documentation; the D514 imported-save test must run from a normal boot; a log-or-import fix is owed in the port layer) D528,OPEN,"GE_STARTMENU skips the EEPROM read, so front-end-only sessions never import the emulator save —",OPEN (harness documentation; the D514 imported-save test must run from a normal boot; a log-or-import fix is owed in the port layer)
D529,FIXED,The golden gate depends on the save file's CONTENT —,FIXED 2026-10-07 (canonical save in-tree at tools_pc/golden/ge007.eep; verify.sh installs it like the ini pin; all 21 win sets re-captured under it — D529,FIXED,The golden gate depends on the save file's CONTENT —,FIXED 2026-10-05 (canonical save in-tree at tools_pc/golden/ge007.eep; verify.sh installs it like the ini pin; all 21 win sets re-captured under it —
D530,?,The box (X220) linux golden re-round landed —,AMENDED BY D531 (2026-10-07) — D530,?,The box (X220) linux golden re-round landed —,AMENDED BY D531 (2026-10-05) —
D531,FIXED,capture_p7.sh's D529 adaptation was incomplete —,"FIXED 2026-10-07 (loop re-pins the canonical save per level + cd ""$ROOT""; fresh 21/21 box re-capture committed —" D531,FIXED,capture_p7.sh's D529 adaptation was incomplete —,"FIXED 2026-10-05 (loop re-pins the canonical save per level + cd ""$ROOT""; fresh 21/21 box re-capture committed —"
D532,FIXED,The three P12 U5 should-fixes applied —,FIXED 2026-10-07 (tooling-only: D532,FIXED,The three P12 U5 should-fixes applied —,FIXED 2026-10-05 (tooling-only:
D533,FIXED,"The probe-doc drift that would have failed CI, plus three tracked-file accuracy/hygiene fixes (release-sweep spot-check) —",FIXED 2026-10-05 (GE-ENV-PROBES.md missing the GE_D526 family → gen_env_probes.py --check rc 1 = a CI-failing step; build-pc.sh local MSYS2 root in two messages; docs/fidelity.md og line; release-not…
D534,FIXED,Pre-release review of the 2026-10-05 local batch —,FIXED 2026-10-05 (verify.sh/capture_p7.sh INT/TERM trap; release-notes linux-gate wording; dead security-and-fidelity-status.md links; future-dated 2026-10-07 labels normalised; D526 probe dangling-e…
D450,FIXED,"Unplugging and replugging a controller was not picked up (user, GameSir-G7 Pro; 2026-09-29).","FIXED — port-only: the render thread's gfx_sdl_handle_events drains the same SDL queue as video.c's host pump but had no case for SDL_CONTROLLERDEVICEADDED/REMOVED, so it usually swallowed them and i…" D450,FIXED,"Unplugging and replugging a controller was not picked up (user, GameSir-G7 Pro; 2026-09-29).","FIXED — port-only: the render thread's gfx_sdl_handle_events drains the same SDL queue as video.c's host pump but had no case for SDL_CONTROLLERDEVICEADDED/REMOVED, so it usually swallowed them and i…"
1 # GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.
382 D520
383 D521
384 D522
385 D523
386 D524
387 D525
388 D526
389 D527
390 D528
391 D529
392 D530
393 D531
394 D532
395 D533
396 D534
397 D450
+103 -18
View File
@@ -790,16 +790,18 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
| D520 | **F10 overlay slider wedge, slider marker and dropdown arrow antialiased (they stepped in whole canvas pixels that grow with the window)** — Port-only; D504 follow-up, P4k investigation; full `## D520` entry at file tail | FIXED (headless before/after capture; by-eye owed) | | D520 | **F10 overlay slider wedge, slider marker and dropdown arrow antialiased (they stepped in whole canvas pixels that grow with the window)** — Port-only; D504 follow-up, P4k investigation; full `## D520` entry at file tail | FIXED (headless before/after capture; by-eye owed) |
| D521 | **A fixed-frame golden window that overlaps the intro flyby is platform-nondeterministic (cross-platform goldens); verify.sh's linux pixel-gate skip is driver-conditional** — Port-only (docs + verify.sh probe); D117 class, P7; full `## D521` entry at the end of this file | PARTIAL (rule recorded 2026-10-04; the two residual bands CLOSED 2026-10-05 by D525's box re-round — save state, not a renderer; cross-platform parity stays informational, the gate is per platform) | | D521 | **A fixed-frame golden window that overlaps the intro flyby is platform-nondeterministic (cross-platform goldens); verify.sh's linux pixel-gate skip is driver-conditional** — Port-only (docs + verify.sh probe); D117 class, P7; full `## D521` entry at the end of this file | PARTIAL (rule recorded 2026-10-04; the two residual bands CLOSED 2026-10-05 by D525's box re-round — save state, not a renderer; cross-platform parity stays informational, the gate is per platform) |
| D522 | **The golden window's frame-900 stem is not settled gameplay on several levels — the win golden gate is not green (5/21 REGRESSION honest sequential, 7/21 concurrent)** — Golden gate; D117 follow-up; full `## D522` entry at file tail | FIXED 2026-10-05 (recipe-side re-base: per-level windows settled on every level; win gate 21/21 PASS honest sequential; no tol limit raised) | | D522 | **The golden window's frame-900 stem is not settled gameplay on several levels — the win golden gate is not green (5/21 REGRESSION honest sequential, 7/21 concurrent)** — Golden gate; D117 follow-up; full `## D522` entry at file tail | FIXED 2026-10-05 (recipe-side re-base: per-level windows settled on every level; win gate 21/21 PASS honest sequential; no tol limit raised) |
| D523 | **The golden recipe does not pin save state: `verify.sh` pins the ini but never touches `data/ge007.eep`, and the goldens were captured with a save present** — Golden gate; D514/D522 follow-up; full `## D523` entry at file tail | SUPERSEDED by D529 (2026-10-07) — the frame depends on the save's *content*, not its presence (the presence claim was only ever measured on Archives); the gate now installs the canonical in-tree save `tools_pc/golden/ge007.eep` | | D523 | **The golden recipe does not pin save state: `verify.sh` pins the ini but never touches `data/ge007.eep`, and the goldens were captured with a save present** — Golden gate; D514/D522 follow-up; full `## D523` entry at file tail | SUPERSEDED by D529 (2026-10-05) — the frame depends on the save's *content*, not its presence (the presence claim was only ever measured on Archives); the gate now installs the canonical in-tree save `tools_pc/golden/ge007.eep` |
| D524 | **The golden tooling was destructive and drift-prone: `verify.sh`'s per-level ini/save pin snapshotted the previous level's game-written file (a sweep overwrites the user's own `data/ge007.ini`), and `capture_p7.sh` hardcoded the pre-D522 windows while deleting the save it captures with** — Golden tooling (U5 review of `tools_pc/**`); D522/D523 follow-up; full `## D524` entry at file tail | FIXED 2026-10-05 (both pins idempotent — first call snapshots the user's files, every level re-pins from that snapshot; `capture_p7.sh` reads the recipe out of `verify.sh` and requires the save present) | | D524 | **The golden tooling was destructive and drift-prone: `verify.sh`'s per-level ini/save pin snapshotted the previous level's game-written file (a sweep overwrites the user's own `data/ge007.ini`), and `capture_p7.sh` hardcoded the pre-D522 windows while deleting the save it captures with** — Golden tooling (U5 review of `tools_pc/**`); D522/D523 follow-up; full `## D524` entry at file tail | FIXED 2026-10-05 (both pins idempotent — first call snapshots the user's files, every level re-pins from that snapshot; `capture_p7.sh` reads the recipe out of `verify.sh` and requires the save present) |
| D525 | **The whole `<level>/linux/` golden set was stale, not just on the six re-based levels — re-rounding it closes D521's two residual render bands** — Golden gate (P7b, box); D521/D522/D523 follow-up; full `## D525` entry at file tail | FIXED 2026-10-05 (21-level box re-round, 63 frames, save pinned present; structural parity 21/21, Archives/Streets bands attributed to save state, not a renderer) | | D525 | **The whole `<level>/linux/` golden set was stale, not just on the six re-based levels — re-rounding it closes D521's two residual render bands** — Golden gate (P7b, box); D521/D522/D523 follow-up; full `## D525` entry at file tail | FIXED 2026-10-05 (21-level box re-round, 63 frames, save pinned present; structural parity 21/21, Archives/Streets bands attributed to save state, not a renderer) |
| D526 | **P13 Dam-ending grate / edge-railing transparency is faithful N64 behaviour (port == 1964/GEPD); the per-triangle census probe is retained as a generic draw-state diagnostic** — P13 Dam ending (B1 lead); full `## D526` entry at file tail | CLOSED — faithful, confirmed on 1964/GEPD (2026-10-07): the show-through is in both (port == N64), so no port bug, no fix (D306/D291 class); the per-triangle census probe (GE_D526/GE_D526BOX/GE_D526MAX) is retained as a generic diagnostic | | D526 | **P13 Dam-ending grate / edge-railing transparency is faithful N64 behaviour (port == 1964/GEPD); the per-triangle census probe is retained as a generic draw-state diagnostic** — P13 Dam ending (B1 lead); full `## D526` entry at file tail | CLOSED — faithful, confirmed on 1964/GEPD (2026-10-05): the show-through is in both (port == N64), so no port bug, no fix (D306/D291 class); the per-triangle census probe (GE_D526/GE_D526BOX/GE_D526MAX) is retained as a generic diagnostic |
| D527 | **`GE_PCDUMP` written `first:last` (a colon where the dash belongs) silently dumps EVERY frame** — harness trap (`port/src/video.c`); full `## D527` entry at file tail | OPEN (harness documentation; a log-or-fail-closed fix is owed in the port layer) | | D527 | **`GE_PCDUMP` written `first:last` (a colon where the dash belongs) silently dumps EVERY frame** — harness trap (`port/src/video.c`); full `## D527` entry at file tail | OPEN (harness documentation; a log-or-fail-closed fix is owed in the port layer) |
| D528 | **`GE_STARTMENU` skips the EEPROM read, so front-end-only sessions never import the emulator save** — harness trap; D514 follow-up; full `## D528` entry at file tail | OPEN (harness documentation; the D514 imported-save test must run from a normal boot; a log-or-import fix is owed in the port layer) | | D528 | **`GE_STARTMENU` skips the EEPROM read, so front-end-only sessions never import the emulator save** — harness trap; D514 follow-up; full `## D528` entry at file tail | OPEN (harness documentation; the D514 imported-save test must run from a normal boot; a log-or-import fix is owed in the port layer) |
| D529 | **The golden gate depends on the save file's CONTENT — the D523 "presence, not which save" claim is refuted; the gate must pin a canonical save** — Golden gate; D523 follow-up (D525/D524); full `## D529` entry at file tail | FIXED 2026-10-07 (canonical save in-tree at `tools_pc/golden/ge007.eep`; `verify.sh` installs it like the ini pin; all 21 win sets re-captured under it — three consecutive clean 21/21 sweeps are the valid green record; the no-arg `verify.sh` path now exits 1; the box linux re-round under it landed as D530) | | D529 | **The golden gate depends on the save file's CONTENT — the D523 "presence, not which save" claim is refuted; the gate must pin a canonical save** — Golden gate; D523 follow-up (D525/D524); full `## D529` entry at file tail | FIXED 2026-10-05 (canonical save in-tree at `tools_pc/golden/ge007.eep`; `verify.sh` installs it like the ini pin; all 21 win sets re-captured under it — three consecutive clean 21/21 sweeps are the valid green record; the no-arg `verify.sh` path now exits 1; the box linux re-round under it landed as D530) |
| D530 | **The box (X220) linux golden re-round landed — first cross-machine test of the four D117 flaky levels** — Golden gate (P7, box); D529 never-do 3/6 follow-up; full `## D530` entry at file tail | AMENDED BY D531 (2026-10-07) — the "canonical eep" provenance claim was wrong: the re-round ran under the box-LOCAL save (the `capture_p7.sh` per-level re-pin bug); the D531 re-capture under the true canonical eep supersedes this set | | D530 | **The box (X220) linux golden re-round landed — first cross-machine test of the four D117 flaky levels** — Golden gate (P7, box); D529 never-do 3/6 follow-up; full `## D530` entry at file tail | AMENDED BY D531 (2026-10-05) — the "canonical eep" provenance claim was wrong: the re-round ran under the box-LOCAL save (the `capture_p7.sh` per-level re-pin bug); the D531 re-capture under the true canonical eep supersedes this set |
| D531 | **`capture_p7.sh`'s D529 adaptation was incomplete — the per-level re-pin restored the local save, so the 2026-10-05 box re-round ran under the box-local save; fixed + re-captured under the canonical eep** — Golden gate (P7, box); D529/D530 follow-up, P12 U5 review finding; full `## D531` entry at file tail | FIXED 2026-10-07 (loop re-pins the canonical save per level + `cd "$ROOT"`; fresh 21/21 box re-capture committed — 47/63 frames differ from the box-local-save set; pixel-gated box verify owed for a window with the box's WSLg GPU display active — today's session is on the software fallback, black read-backs) | | D531 | **`capture_p7.sh`'s D529 adaptation was incomplete — the per-level re-pin restored the local save, so the 2026-10-05 box re-round ran under the box-local save; fixed + re-captured under the canonical eep** — Golden gate (P7, box); D529/D530 follow-up, P12 U5 review finding; full `## D531` entry at file tail | FIXED 2026-10-05 (loop re-pins the canonical save per level + `cd "$ROOT"`; fresh 21/21 box re-capture committed — 47/63 frames differ from the box-local-save set; pixel-gated box verify owed for a window with the box's WSLg GPU display active — today's session is on the software fallback, black read-backs) |
| D532 | **The three P12 U5 should-fixes applied — the gate's ini pin now fails closed, the seed is hard-pinned (stray `GE_RSEED` warns), and `audiodebug.ps1`'s dead A/B switches are gone** — golden gate + tooling; D531/U5 follow-up; full `## D532` entry at file tail | FIXED 2026-10-07 (tooling-only: `pin_ini_640x480` fails closed like `pin_eep`; `GOLDEN_SEED` literal + warning, capture `eval` unaffected; `-AB`/`-Old`/`-OldMode` removed with a note) | | D532 | **The three P12 U5 should-fixes applied — the gate's ini pin now fails closed, the seed is hard-pinned (stray `GE_RSEED` warns), and `audiodebug.ps1`'s dead A/B switches are gone** — golden gate + tooling; D531/U5 follow-up; full `## D532` entry at file tail | FIXED 2026-10-05 (tooling-only: `pin_ini_640x480` fails closed like `pin_eep`; `GOLDEN_SEED` literal + warning, capture `eval` unaffected; `-AB`/`-Old`/`-OldMode` removed with a note) |
| D533 | **The probe-doc drift that would have failed CI, plus three tracked-file accuracy/hygiene fixes (release-sweep spot-check)** — release gate (P12 U2/U6/U7 spot-checks); full `## D533` entry at file tail | FIXED 2026-10-05 (`GE-ENV-PROBES.md` missing the `GE_D526` family → `gen_env_probes.py --check` rc 1 = a CI-failing step; `build-pc.sh` local MSYS2 root in two messages; `docs/fidelity.md` og line; release-notes gate paragraph quoted a pre-D531 spread) |
| D534 | **Pre-release review of the 2026-10-05 local batch — Ctrl-C in the golden gate could leave the user's save replaced, plus doc accuracy fixes** — release gate; full `## D534` entry at file tail | FIXED 2026-10-05 (`verify.sh`/`capture_p7.sh` INT/TERM trap; release-notes linux-gate wording; dead `security-and-fidelity-status.md` links; future-dated `2026-10-07` labels normalised; D526 probe dangling-else; verify.sh usage range) |
| D407 | **Tanks cannot be boarded/exited on PC — the v0.4.0 use/reload split (D378/D393) removed the B-button tap the engine's tank handlers in `bondview2.c` consume (user report 2026-09-28, Runway/Streets)** — full `## D407` entry at file tail | PARTIAL (fix landed in v0.4.0, port-only): present `GE_CONT_B` on the use (E / pad A) rising edge only while `g_PlayerIsInTank == 1` or `g_BondCanEnterTank != 0`; E keeps its D378 no-reload-fallback semantics elsewhere, N64 layout unaffected. D407(b) same cycle: front PC Options page-edge highlight clamp + mouse-wheel / W-S paging (wheel queue consumed on the menu, D223); its wheel mapping shipped inverted and was fixed to match W/S (wheel up = step up). D407(c): board-animation lockout, menu-accept B gate in tank states, in-tank aim routed through the legacy velocity stick + `Input.TankAimScale` knob. RESOLVED 2026-09-28: all port-only (src/game zero-diff), 10 TANKDBG probes stripped, release binary verified clean, user live tank drive signed off (board + exit OK, aim feel good). | | D407 | **Tanks cannot be boarded/exited on PC — the v0.4.0 use/reload split (D378/D393) removed the B-button tap the engine's tank handlers in `bondview2.c` consume (user report 2026-09-28, Runway/Streets)** — full `## D407` entry at file tail | PARTIAL (fix landed in v0.4.0, port-only): present `GE_CONT_B` on the use (E / pad A) rising edge only while `g_PlayerIsInTank == 1` or `g_BondCanEnterTank != 0`; E keeps its D378 no-reload-fallback semantics elsewhere, N64 layout unaffected. D407(b) same cycle: front PC Options page-edge highlight clamp + mouse-wheel / W-S paging (wheel queue consumed on the menu, D223); its wheel mapping shipped inverted and was fixed to match W/S (wheel up = step up). D407(c): board-animation lockout, menu-accept B gate in tank states, in-tank aim routed through the legacy velocity stick + `Input.TankAimScale` knob. RESOLVED 2026-09-28: all port-only (src/game zero-diff), 10 TANKDBG probes stripped, release binary verified clean, user live tank drive signed off (board + exit OK, aim feel good). |
| D408 | **`Game.SkipIntro` skips the post-mission failure dossier: with it on, entering a level then aborting (watch Z+A) or dying (KIA) returns straight to the menus — no REPORT / "Mission status: KILLED IN ACTION / ABORTED" screen** (user report 2026-09-28; save/AllUnlocked ruled out) — full `## D408` entry at file tail | OPEN (cosmetic, not root-caused past the handoff site). v0.4.0 decision: SkipIntro stays EXPERIMENTAL / not recommended for regular users — F10 row relabelled "Skip intro (EXPERIMENTAL)". | | D408 | **`Game.SkipIntro` skips the post-mission failure dossier: with it on, entering a level then aborting (watch Z+A) or dying (KIA) returns straight to the menus — no REPORT / "Mission status: KILLED IN ACTION / ABORTED" screen** (user report 2026-09-28; save/AllUnlocked ruled out) — full `## D408` entry at file tail | OPEN (cosmetic, not root-caused past the handoff site). v0.4.0 decision: SkipIntro stays EXPERIMENTAL / not recommended for regular users — F10 row relabelled "Skip intro (EXPERIMENTAL)". |
| D450 | **Unplugging and replugging a controller was not picked up (user, GameSir-G7 Pro; 2026-09-29).** — full `## D450` entry at file tail | FIXED — port-only: the render thread's `gfx_sdl_handle_events` drains the same SDL queue as video.c's host pump but had no case for `SDL_CONTROLLERDEVICEADDED/REMOVED`, so it usually swallowed them and `inputRescanPads` never ran. Both pumps now post a request; the rescan runs at the top of `inputUpdate`, on the thread that reads the pads. | | D450 | **Unplugging and replugging a controller was not picked up (user, GameSir-G7 Pro; 2026-09-29).** — full `## D450` entry at file tail | FIXED — port-only: the render thread's `gfx_sdl_handle_events` drains the same SDL queue as video.c's host pump but had no case for `SDL_CONTROLLERDEVICEADDED/REMOVED`, so it usually swallowed them and `inputRescanPads` never ran. Both pumps now post a request; the rescan runs at the top of `inputUpdate`, on the thread that reads the pads. |
@@ -17155,7 +17157,7 @@ keep: the next `./build-pc.sh` run reconfigures in place and picks up x86_64.
**Fix owed (recipe-side only; no game-code change):** either (a) move the capture window to stems settled on every level (1200–1800:300 is the measured candidate) and re-capture the 63 `win/` PNGs plus the box's linux set, or (b) keep the set and state the gate honestly (structural green + per-pixel marginal at 900) in `golden/README.md`, the ROADMAP row and the known-issues table. Driver: `scratch/sweep-par.sh` (gitignored; mirrors `verify.sh`'s ini pin, `GE_*` recipe, framediff flags and per-level limits, one cwd per level so runs can overlap — parallel verdicts are diagnosis only, the honest numbers come from the `JOBS=1` pass). **Fix owed (recipe-side only; no game-code change):** either (a) move the capture window to stems settled on every level (1200–1800:300 is the measured candidate) and re-capture the 63 `win/` PNGs plus the box's linux set, or (b) keep the set and state the gate honestly (structural green + per-pixel marginal at 900) in `golden/README.md`, the ROADMAP row and the known-issues table. Driver: `scratch/sweep-par.sh` (gitignored; mirrors `verify.sh`'s ini pin, `GE_*` recipe, framediff flags and per-level limits, one cwd per level so runs can overlap — parallel verdicts are diagnosis only, the honest numbers come from the `JOBS=1` pass).
## D523: The golden recipe does not pin save state — `verify.sh` pins the ini but never touches `data/ge007.eep` (golden gate; D514/D522 follow-up) — **SUPERSEDED by D529 (2026-10-07): the frame depends on the save's CONTENT, not its presence; the gate now installs the canonical in-tree save** ## D523: The golden recipe does not pin save state — `verify.sh` pins the ini but never touches `data/ge007.eep` (golden gate; D514/D522 follow-up) — **SUPERSEDED by D529 (2026-10-05): the frame depends on the save's CONTENT, not its presence; the gate now installs the canonical in-tree save**
**FIXED 2026-10-05 — `verify.sh` now pins the save file** (back up + require `data/ge007.eep`, mirroring the ini pin; it exits 2 with a message when a clone has none, rather than silently measuring a different scene), and `tools_pc/golden/README.md` states the pin. The measurements below are the record of why the gap mattered. **FIXED 2026-10-05 — `verify.sh` now pins the save file** (back up + require `data/ge007.eep`, mirroring the ini pin; it exits 2 with a message when a clone has none, rather than silently measuring a different scene), and `tools_pc/golden/README.md` states the pin. The measurements below are the record of why the gap mattered.
@@ -17193,7 +17195,7 @@ keep: the next `./build-pc.sh` run reconfigures in place and picks up x86_64.
## D526: P13 Dam-ending grate / edge-railing transparency is faithful N64 behaviour (port == 1964/GEPD); the per-triangle census probe is retained as a generic draw-state diagnostic ## D526: P13 Dam-ending grate / edge-railing transparency is faithful N64 behaviour (port == 1964/GEPD); the per-triangle census probe is retained as a generic draw-state diagnostic
**CLOSED as faithful 2026-10-07 (no port bug; no fix).** The P13 "Dam-ending grate show-through" (2nd POSENDS camera: the area under the grate Bond stands on shows through — the 2D edge-railing/grate texture's between-anchors region) was triaged as a suspected B1 port bug (the grate quad's texture stage taking an alpha/blend path it shouldn't — D195/D268 class). To bucket it, a per-triangle draw-state census probe was built (this D526) and smoke-tested. The 1964/GEPD reference of the same 2nd-POSENDS shot then showed **the port and the N64 look the same** — the show-through is in *both*. So it is the original game's 2D grate/railing texture rendering, reproduced faithfully: a known issue that **closes in the D306/D291 class** (a "bug" that 1964 shows is intended behaviour). There is nothing to fix in `port/fast3d/`. **CLOSED as faithful 2026-10-05 (no port bug; no fix).** The P13 "Dam-ending grate show-through" (2nd POSENDS camera: the area under the grate Bond stands on shows through — the 2D edge-railing/grate texture's between-anchors region) was triaged as a suspected B1 port bug (the grate quad's texture stage taking an alpha/blend path it shouldn't — D195/D268 class). To bucket it, a per-triangle draw-state census probe was built (this D526) and smoke-tested. The 1964/GEPD reference of the same 2nd-POSENDS shot then showed **the port and the N64 look the same** — the show-through is in *both*. So it is the original game's 2D grate/railing texture rendering, reproduced faithfully: a known issue that **closes in the D306/D291 class** (a "bug" that 1964 shows is intended behaviour). There is nothing to fix in `port/fast3d/`.
**Probe (retained as a generic tool):** `d526_note_emit()` in `port/fast3d/gfx_pc.cpp`, folded into the D474 `tri_dbg()` gate (zero player cost when off). Env: `GE_D526="lo-hi"` (sim-frame window), `GE_D526BOX="x0 y0 x1 y1"` (NDC region, y-up; default whole screen), `GE_D526MAX=N` (cumulative per-triangle line cap, 400; the per-frame `D526F:` signature aggregate is uncapped). Emits to stderr: per-triangle NDC bbox, z/w, `gm`, `oml`, `omh`, combine mode, first-tile tmem/fmt/siz, prim + vertex alpha, use_alpha/modulate/invisible/2-cycle, plus a per-frame `D526F:` signature map. It is the only per-triangle *draw-state* census (D474/D75D/ZF/D303 are specialized) and is the right tool for the alpha/texture bug class (D195/D266/D268/D273). **Probe (retained as a generic tool):** `d526_note_emit()` in `port/fast3d/gfx_pc.cpp`, folded into the D474 `tri_dbg()` gate (zero player cost when off). Env: `GE_D526="lo-hi"` (sim-frame window), `GE_D526BOX="x0 y0 x1 y1"` (NDC region, y-up; default whole screen), `GE_D526MAX=N` (cumulative per-triangle line cap, 400; the per-frame `D526F:` signature aggregate is uncapped). Emits to stderr: per-triangle NDC bbox, z/w, `gm`, `oml`, `omh`, combine mode, first-tile tmem/fmt/siz, prim + vertex alpha, use_alpha/modulate/invisible/2-cycle, plus a per-frame `D526F:` signature map. It is the only per-triangle *draw-state* census (D474/D75D/ZF/D303 are specialized) and is the right tool for the alpha/texture bug class (D195/D266/D268/D273).
@@ -17221,7 +17223,7 @@ Decision owed: document it (a NOTE log line when `GE_STARTMENU` is active: "EEPR
## D529: The golden gate depends on the save file's CONTENT — the D523 "presence, not which save" claim is refuted; the gate must pin a canonical save (golden gate; refines D523; follow-up to D525/D524) ## D529: The golden gate depends on the save file's CONTENT — the D523 "presence, not which save" claim is refuted; the gate must pin a canonical save (golden gate; refines D523; follow-up to D525/D524)
**2026-10-07 (pre-push session).** The D523 pin installed *whichever* local save existed ("presence, not which save — Archives measures worst_cell 0.175625 on each of the four candidate saves and 21.557% with none"). That claim had only ever been measured **on Archives**. The 2026-10-07 sweep refutes it: the local `data/ge007.eep` had been rewritten by the live Dam-ending playtest sessions (md5 `a41d7ab…`, mtime 2026-10-05 07:27), and the honest sequential sweep under it produced **6/21 REGRESSION** on a *byte-identical binary* (the 2026-10-04 run had been 21/21). **2026-10-05 (pre-push session).** The D523 pin installed *whichever* local save existed ("presence, not which save — Archives measures worst_cell 0.175625 on each of the four candidate saves and 21.557% with none"). That claim had only ever been measured **on Archives**. The 2026-10-05 sweep refutes it: the local `data/ge007.eep` had been rewritten by the live Dam-ending playtest sessions (md5 `a41d7ab…`, mtime 2026-10-05 07:27), and the honest sequential sweep under it produced **6/21 REGRESSION** on a *byte-identical binary* (the 2026-10-04 run had been 21/21).
**The A/B (facility, window 900-1500:300):** **The A/B (facility, window 900-1500:300):**
@@ -17238,7 +17240,7 @@ Two distinct classes in the 6-failure sweep, proven apart by the A/B:
1. **Save-content dependent (facility, streets, jungle, cradle):** same failure signature (177.2–177.5 at the 1200/1500 stems — a *different scene* in-window, not a jitter class) only on the two saves with that content (the 2001 dexdrive save and the 10-05 local save share it; 2001-vintage saves apparently hold state that routes facility's intro differently). The other four candidates pass. **This is what D529 fixes: the gate installs ONE canonical save, so "which save" can never vary.** 1. **Save-content dependent (facility, streets, jungle, cradle):** same failure signature (177.2–177.5 at the 1200/1500 stems — a *different scene* in-window, not a jitter class) only on the two saves with that content (the 2001 dexdrive save and the 10-05 local save share it; 2001-vintage saves apparently hold state that routes facility's intro differently). The other four candidates pass. **This is what D529 fixes: the gate installs ONE canonical save, so "which save" can never vary.**
2. **D117 wall-clock flyby (dam@1500 4.9%, frigate@1000 3.2–8.3%, streets@1000 2.5–25.7%):** fails *identically on every save* — the window's first stem is inside the real-time-paced intro flyby, so the content at a given sim frame varies with machine load (D117, long-known, previously masked because the Oct-4 goldens happened to be captured the same way). 2. **D117 wall-clock flyby (dam@1500 4.9%, frigate@1000 3.2–8.3%, streets@1000 2.5–25.7%):** fails *identically on every save* — the window's first stem is inside the real-time-paced intro flyby, so the content at a given sim frame varies with machine load (D117, long-known, previously masked because the Oct-4 goldens happened to be captured the same way).
**Resolution (FIXED 2026-10-07, same session):** **Resolution (FIXED 2026-10-05, same session):**
- **Canonical save in-tree: `tools_pc/golden/ge007.eep`** (2 KB, = `ge007 copy.eep`, the stable pre-live-sessions save the Oct-4 gate was green on). In-tree = a fresh clone or CI can run the gate with zero external state, and the D523 "fresh clone has no save → exit 2" failure branch is gone for good. - **Canonical save in-tree: `tools_pc/golden/ge007.eep`** (2 KB, = `ge007 copy.eep`, the stable pre-live-sessions save the Oct-4 gate was green on). In-tree = a fresh clone or CI can run the gate with zero external state, and the D523 "fresh clone has no save → exit 2" failure branch is gone for good.
- **`verify.sh` installs it like the ini pin** (snapshot the local `data/ge007.eep` if any → install the canonical → restore-or-remove on exit). The local playtest save is never the gate's input. - **`verify.sh` installs it like the ini pin** (snapshot the local `data/ge007.eep` if any → install the canonical → restore-or-remove on exit). The local playtest save is never the gate's input.
- **All 21 win golden sets re-captured under the canonical save** (`scratch/golden-recapture-win-v050.sh`; 21/21 rc=0). The first four flaky levels (dam/frigate/streets/jungle — the D117 flyby stems) were re-captured again **clean** (no concurrent processes) after the first interleaved capture. - **All 21 win golden sets re-captured under the canonical save** (`scratch/golden-recapture-win-v050.sh`; 21/21 rc=0). The first four flaky levels (dam/frigate/streets/jungle — the D117 flyby stems) were re-captured again **clean** (no concurrent processes) after the first interleaved capture.
@@ -17247,11 +17249,11 @@ Two distinct classes in the 6-failure sweep, proven apart by the A/B:
**Why this is not a renderer drift:** the binary is byte-identical to the 2026-10-04 21/21 run; the only variable that changed is `data/ge007.eep`, and the A/B is save-keyed (same binary, four passing saves, one failing save). No renderer code changed. **Why this is not a renderer drift:** the binary is byte-identical to the 2026-10-04 21/21 run; the only variable that changed is `data/ge007.eep`, and the A/B is save-keyed (same binary, four passing saves, one failing save). No renderer code changed.
**Never do:** (1) run the golden gate against a local playtest save — it is exactly this class of drift; always the in-tree canonical eep. (2) claim "the frame depends on save *presence*" again — it depends on *content*; the D523 claim survives only as the (superseded) measurement on Archives. (3) treat the linux 63-frame set as valid under the canonical eep before the box re-round lands — it is the D525 cleared-eep round, and **no linux number may be cited (e.g. in the README pass) until that re-round lands**. (4) cite `verify.sh` with **no arguments** as a green run — a sweep is `verify.sh sweep` (the no-arg path now exits 1, closing the trap in code). (5) run a re-capture concurrently with a sweep (contention moves the D117 flyby stems). (6) treat **same-session** sweeps as proof the four D117 flaky levels (dam/frigate/streets/jungle) are stable across wall-clock: the first-stem content is time-dependent and the pin was fixed to "now" — the cross-machine test is the box re-round; **if those four go red there, the fix is to exclude or widen the first-stem cell for those levels, NOT to re-capture again** (an independent reviewer's 2026-10-07 verification flagged this; same-session worst_cell swings were streets 8.38→4.41, jungle 1.42→3.87). (7) trust a `capture_p7.sh` round's provenance claim without checking WHICH save state the loop actually installed — the D524-era per-level re-pin restored the local save and silently overwrote D529's pre-loop canonical install (D531); the linux set is only "canonical" if the loop line says `cp "$CANON_EEP"`. **Never do:** (1) run the golden gate against a local playtest save — it is exactly this class of drift; always the in-tree canonical eep. (2) claim "the frame depends on save *presence*" again — it depends on *content*; the D523 claim survives only as the (superseded) measurement on Archives. (3) treat the linux 63-frame set as valid under the canonical eep before the box re-round lands — it is the D525 cleared-eep round, and **no linux number may be cited (e.g. in the README pass) until that re-round lands**. (4) cite `verify.sh` with **no arguments** as a green run — a sweep is `verify.sh sweep` (the no-arg path now exits 1, closing the trap in code). (5) run a re-capture concurrently with a sweep (contention moves the D117 flyby stems). (6) treat **same-session** sweeps as proof the four D117 flaky levels (dam/frigate/streets/jungle) are stable across wall-clock: the first-stem content is time-dependent and the pin was fixed to "now" — the cross-machine test is the box re-round; **if those four go red there, the fix is to exclude or widen the first-stem cell for those levels, NOT to re-capture again** (an independent reviewer's 2026-10-05 verification flagged this; same-session worst_cell swings were streets 8.38→4.41, jungle 1.42→3.87). (7) trust a `capture_p7.sh` round's provenance claim without checking WHICH save state the loop actually installed — the D524-era per-level re-pin restored the local save and silently overwrote D529's pre-loop canonical install (D531); the linux set is only "canonical" if the loop line says `cp "$CANON_EEP"`.
## D531: `capture_p7.sh`'s D529 adaptation was incomplete — the per-level re-pin restored the local save, so the 2026-10-05 box re-round ran under the box-local save (not the canonical one); fixed + re-captured (golden gate; D529/D530 follow-up; P12 U5 review finding) ## D531: `capture_p7.sh`'s D529 adaptation was incomplete — the per-level re-pin restored the local save, so the 2026-10-05 box re-round ran under the box-local save (not the canonical one); fixed + re-captured (golden gate; D529/D530 follow-up; P12 U5 review finding)
**Blocker found in the 2026-10-07 P12 U5 review (local session).** `tools_pc/capture_p7.sh`'s per-level loop had `cp "$EEP_ORIG" "$EEP"` (introduced by D524 to make the tool non-destructive): it restored the pre-capture **local** save — or a 0-byte eep when `data/ge007.eep` did not exist — before every level. D529's adaptation (`8fbf8aa0`) installed the canonical save (`cp "$CANON_EEP" "$EEP"`) **once, before the loop** and added the canonical-missing guard, but left the D524-era re-pin line in place — so from level 1 the canonical install was silently overwritten and every capture ran under the local save state. The header comment ("the pinned save, restored before every level") asserted what the code did not do. **Blocker found in the 2026-10-05 P12 U5 review (local session).** `tools_pc/capture_p7.sh`'s per-level loop had `cp "$EEP_ORIG" "$EEP"` (introduced by D524 to make the tool non-destructive): it restored the pre-capture **local** save — or a 0-byte eep when `data/ge007.eep` did not exist — before every level. D529's adaptation (`8fbf8aa0`) installed the canonical save (`cp "$CANON_EEP" "$EEP"`) **once, before the loop** and added the canonical-missing guard, but left the D524-era re-pin line in place — so from level 1 the canonical install was silently overwritten and every capture ran under the local save state. The header comment ("the pinned save, restored before every level") asserted what the code did not do.
**Impact — D530's provenance claim is wrong:** the 2026-10-05 box re-round (`~/p7-reround.log`, "P7 re-round DONE") ran under the box-local save (`sha256 d9f306…`, 2 KB — distinct from the in-tree canonical `65247b…`), not the canonical eep. D530's / the golden README's / the commit message's "63 PNGs under the canonical eep" did not hold, and D530's first-stem table (measured in that re-round's report against the old D525 goldens — its numbers do check out against the report) is not canonical-save evidence. **The win set is unaffected** — `verify.sh`'s `pin_eep` re-installs the canonical save on every call (that code was right); the bug was capture-side only. **Impact — D530's provenance claim is wrong:** the 2026-10-05 box re-round (`~/p7-reround.log`, "P7 re-round DONE") ran under the box-local save (`sha256 d9f306…`, 2 KB — distinct from the in-tree canonical `65247b…`), not the canonical eep. D530's / the golden README's / the commit message's "63 PNGs under the canonical eep" did not hold, and D530's first-stem table (measured in that re-round's report against the old D525 goldens — its numbers do check out against the report) is not canonical-save evidence. **The win set is unaffected** — `verify.sh`'s `pin_eep` re-installs the canonical save on every call (that code was right); the bug was capture-side only.
@@ -17259,13 +17261,13 @@ Two distinct classes in the 6-failure sweep, proven apart by the A/B:
**Re-capture (this batch):** a fresh 21-level box re-round under the canonical eep (21/21 rc=0, 63 frames), committed into `tools_pc/golden/<level>/linux/` replacing the D530 box-local-save set: **47/63 frames differ** from it (save content demonstrably moves the frames — D529's drift class), 16 byte-identical (save-independent scenes). **Note on the box's pixel capability:** the 10-05 re-round's p7_report diff table (1–26% over on real content) proves its WSLg GPU display was active then; today the box reads back **black even with `DISPLAY=:0`** (`glxinfo -B` under `:0` reports no usable renderer — the WSLg GPU display is session-state-dependent, and today's session is on the software fallback), so today's `verify.sh` runs (D530's crash-detect sweep and this batch's `~/p7-verify-pixel.log`) are legitimately crash-detect-only. The pixel-gated cross-machine verify is owed for a window in which the box's GPU display is up again. **Re-capture (this batch):** a fresh 21-level box re-round under the canonical eep (21/21 rc=0, 63 frames), committed into `tools_pc/golden/<level>/linux/` replacing the D530 box-local-save set: **47/63 frames differ** from it (save content demonstrably moves the frames — D529's drift class), 16 byte-identical (save-independent scenes). **Note on the box's pixel capability:** the 10-05 re-round's p7_report diff table (1–26% over on real content) proves its WSLg GPU display was active then; today the box reads back **black even with `DISPLAY=:0`** (`glxinfo -B` under `:0` reports no usable renderer — the WSLg GPU display is session-state-dependent, and today's session is on the software fallback), so today's `verify.sh` runs (D530's crash-detect sweep and this batch's `~/p7-verify-pixel.log`) are legitimately crash-detect-only. The pixel-gated cross-machine verify is owed for a window in which the box's GPU display is up again.
**Pixel-gated cross-machine gate (the real D117 datum):** `verify.sh sweep` on the box against the new canonical goldens — **2026-10-07 attempt (log `~/p7-verify-pixel.log`): 21/21 PASS, 0 FAIL, crash-detect only** (the run's renderer probe correctly failed closed on today's software-fallback session, so it adds stability, not, pixel data); the pixel verdict — including the four flaky levels' first stems — is owed for a window in which the box's WSLg GPU display is active. If the four flaky levels (dam/frigate/streets/jungle) go red there, the never-do 6 decision stands: exclude or widen the first-stem cell, do NOT re-capture. **Pixel-gated cross-machine gate (the real D117 datum):** `verify.sh sweep` on the box against the new canonical goldens — **2026-10-05 attempt (log `~/p7-verify-pixel.log`): 21/21 PASS, 0 FAIL, crash-detect only** (the run's renderer probe correctly failed closed on today's software-fallback session, so it adds stability, not, pixel data); the pixel verdict — including the four flaky levels' first stems — is owed for a window in which the box's WSLg GPU display is active. If the four flaky levels (dam/frigate/streets/jungle) go red there, the never-do 6 decision stands: exclude or widen the first-stem cell, do NOT re-capture.
**U5 review notes from the same pass (non-blockers):** the three should-fixes below were applied 2026-10-07 as D532 (gate hardening: fail-closed ini pin, hard-pinned seed, dead A/B switches removed). **U5 review notes from the same pass (non-blockers):** the three should-fixes below were applied 2026-10-05 as D532 (gate hardening: fail-closed ini pin, hard-pinned seed, dead A/B switches removed).
## D532: the three P12 U5 should-fixes applied — the golden gate's ini pin now fails closed, the seed is hard-pinned (a stray `GE_RSEED` warns instead of re-seeding), and `audiodebug.ps1`'s dead A/B switches are gone (golden gate + tooling; D531/U5 follow-up) ## D532: the three P12 U5 should-fixes applied — the golden gate's ini pin now fails closed, the seed is hard-pinned (a stray `GE_RSEED` warns instead of re-seeding), and `audiodebug.ps1`'s dead A/B switches are gone (golden gate + tooling; D531/U5 follow-up)
**2026-10-07 (local session).** Three tooling-only fixes, no game logic: **2026-10-05 (local session).** Three tooling-only fixes, no game logic:
1. **`verify.sh` `pin_ini_640x480` failed OPEN** — the three call sites (`single`/`sweep`/`parity`) were `pin_ini_640x480 2>/dev/null || true`, so a failed ini write (missing `data/`, read-only tree, failed snapshot) ran the gate under an **unpinned ini** — the frame depends on a defaults-only 640x480 ini exactly like the save pin (D529), so that was a spurious-verdict source, not a skipped nicety. The pin now fails closed (snapshot and write both `error + exit 2`, matching `pin_eep`'s style) and the call sites are plain. 1. **`verify.sh` `pin_ini_640x480` failed OPEN** — the three call sites (`single`/`sweep`/`parity`) were `pin_ini_640x480 2>/dev/null || true`, so a failed ini write (missing `data/`, read-only tree, failed snapshot) ran the gate under an **unpinned ini** — the frame depends on a defaults-only 640x480 ini exactly like the save pin (D529), so that was a spurious-verdict source, not a skipped nicety. The pin now fails closed (snapshot and write both `error + exit 2`, matching `pin_eep`'s style) and the call sites are plain.
2. **`GOLDEN_SEED` hard-pinned** — it was `"${GE_RSEED:-0x0123456789abcdef}"`, so a stray `GE_RSEED` in the environment silently re-seeded the documented-as-pinned gate (frames shift → spurious verdicts). It is now the literal, with a warning when a differing env var is present (verified: `GE_RSEED=0xdead` warns, the pinned value is silent). `capture_p7.sh`'s `eval grep -m1 '^GOLDEN_SEED='` still picks up the same line, so capture and gate stay consistent. 2. **`GOLDEN_SEED` hard-pinned** — it was `"${GE_RSEED:-0x0123456789abcdef}"`, so a stray `GE_RSEED` in the environment silently re-seeded the documented-as-pinned gate (frames shift → spurious verdicts). It is now the literal, with a warning when a differing env var is present (verified: `GE_RSEED=0xdead` warns, the pinned value is silent). `capture_p7.sh`'s `eval grep -m1 '^GOLDEN_SEED='` still picks up the same line, so capture and gate stay consistent.
@@ -17273,9 +17275,9 @@ Two distinct classes in the 6-failure sweep, proven apart by the A/B:
PS parse: 0 errors; `bash -n` clean; the warning path verified. **Owed (unchanged):** the pixel-gated box verify in a WSLg GPU-display window (D531). PS parse: 0 errors; `bash -n` clean; the warning path verified. **Owed (unchanged):** the pixel-gated box verify in a WSLg GPU-display window (D531).
## D530: The box (X220) linux golden re-round landed — first cross-machine test of the four D117 flaky levels (golden gate; D529 never-do 3/6 follow-up) — **AMENDED BY D531 (2026-10-07): the 10-05 re-round ran under the box-LOCAL save, not the canonical one (the capture_p7.sh bug); the true canonical re-capture is D531** ## D530: The box (X220) linux golden re-round landed — first cross-machine test of the four D117 flaky levels (golden gate; D529 never-do 3/6 follow-up) — **AMENDED BY D531 (2026-10-05): the 10-05 re-round ran under the box-LOCAL save, not the canonical one (the capture_p7.sh bug); the true canonical re-capture is D531**
**2026-10-07 (local session).** The box re-round D529 owed (never-do 3: the linux set was the D525 *cleared*-eep round and no linux number could be cited until it was re-rounded under `tools_pc/golden/ge007.eep`) ran on X220 on 2026-10-05 (tree `442eb2ff`, worktree `~/gh-fullhist-wt-p7`, log `~/p7-reround.log` hit `P7 re-round DONE` 12:53 EDT). **21/21 levels rc=0** (the box self-gate is crash-detect only — the pixel probe fails closed on the box, D244). This session pulled the 63 PNGs (21 levels × 3 frames) and committed them into `tools_pc/golden/<level>/linux/`, replacing the D525 set: 51/63 differ from the D525 round; the 12/63 that are byte-identical are save-independent scenes — including **frigate's first stem (001000)**, a direct D117 stability signal. **AMENDED BY D531: that re-round ran under the box-local save (the `capture_p7.sh` bug), so the "canonical eep" provenance claim — and the first-stem table below, as canonical-save evidence — does not hold; the D531 re-capture supersedes this set.** **2026-10-05 (local session).** The box re-round D529 owed (never-do 3: the linux set was the D525 *cleared*-eep round and no linux number could be cited until it was re-rounded under `tools_pc/golden/ge007.eep`) ran on X220 on 2026-10-05 (tree `442eb2ff`, worktree `~/gh-fullhist-wt-p7`, log `~/p7-reround.log` hit `P7 re-round DONE` 12:53 EDT). **21/21 levels rc=0** (the box self-gate is crash-detect only — the pixel probe fails closed on the box, D244). This session pulled the 63 PNGs (21 levels × 3 frames) and committed them into `tools_pc/golden/<level>/linux/`, replacing the D525 set: 51/63 differ from the D525 round; the 12/63 that are byte-identical are save-independent scenes — including **frigate's first stem (001000)**, a direct D117 stability signal. **AMENDED BY D531: that re-round ran under the box-local save (the `capture_p7.sh` bug), so the "canonical eep" provenance claim — and the first-stem table below, as canonical-save evidence — does not hold; the D531 re-capture supersedes this set.**
The `fail` rows in the box report are the expected cross-eep diffs against the *old* in-tree set, not regressions: structural tier is all `ok` (phash ≤ 3, cradle@40 the documented exception; Cuba 26.4% inside its documented 23.7–36.3% structural-only range). The `fail` rows in the box report are the expected cross-eep diffs against the *old* in-tree set, not regressions: structural tier is all `ok` (phash ≤ 3, cradle@40 the documented exception; Cuba 26.4% inside its documented 23.7–36.3% structural-only range).
@@ -17290,4 +17292,87 @@ The `fail` rows in the box report are the expected cross-eep diffs against the *
All four sit in the stable-levels' range (e.g. silo 0.41–0.84% over, worst_cell 0.41–0.42 is the quietest; archives 1.51–2.31 is noisier). **None went red → the never-do 6 decision closes with NO recipe change** (no first-stem cell excluded or widened on the linux side). All four sit in the stable-levels' range (e.g. silo 0.41–0.84% over, worst_cell 0.41–0.42 is the quietest; archives 1.51–2.31 is noisier). **None went red → the never-do 6 decision closes with NO recipe change** (no first-stem cell excluded or widened on the linux side).
**Unblocked (D529 never-do 3):** the README/index v0.5.0 line "re-based on both platforms (21 levels, 63 frames each)" now stands on a canonical-eep linux set (D531's re-capture; the D530 set it first pointed at was the box-local-save round — see D531). **Fresh box sweep (crash-detect):** with the new goldens staged on the box, `verify.sh sweep` (2026-10-07) is **21/21 PASS** — but that run was crash-detect only (GE_PCDUMP reads black on the box's llvmpipe/WSLg, the D244 note), so it is a stability re-check, not a pixel datum. **AMENDED BY D531:** the "black frames" were **not** simply the no-DISPLAY llvmpipe path — the box's WSLg display is session-state-dependent: its 10-05 session was GPU-backed (the re-round's p7_report pixel table proves real frames), while today's reads back black even with `DISPLAY=:0` (software fallback; `glxinfo -B` reports no usable renderer). D531's pixel-gated attempt (21/21 crash-detect, `~/p7-verify-pixel.log`) is valid as a stability re-check; the pixel datum is owed for a GPU-display window. **Unblocked (D529 never-do 3):** the README/index v0.5.0 line "re-based on both platforms (21 levels, 63 frames each)" now stands on a canonical-eep linux set (D531's re-capture; the D530 set it first pointed at was the box-local-save round — see D531). **Fresh box sweep (crash-detect):** with the new goldens staged on the box, `verify.sh sweep` (2026-10-05) is **21/21 PASS** — but that run was crash-detect only (GE_PCDUMP reads black on the box's llvmpipe/WSLg, the D244 note), so it is a stability re-check, not a pixel datum. **AMENDED BY D531:** the "black frames" were **not** simply the no-DISPLAY llvmpipe path — the box's WSLg display is session-state-dependent: its 10-05 session was GPU-backed (the re-round's p7_report pixel table proves real frames), while today's reads back black even with `DISPLAY=:0` (software fallback; `glxinfo -B` reports no usable renderer). D531's pixel-gated attempt (21/21 crash-detect, `~/p7-verify-pixel.log`) is valid as a stability re-check; the pixel datum is owed for a GPU-display window.
## D533: release-sweep spot-check — the probe-doc drift that would have failed CI, plus three tracked-file accuracy/hygiene fixes (release gate; P12 U2/U6/U7 spot-checks)
**What was checked (P12 U2/U6/U7 spot-checks, read-only until a defect was found):**
the EEP import path (`eepimport.c`: fixed-size `save_data[96]` + `smallSave[32]`
copies, the 6-region backup rotation bounded at `.bak99`), the seat model
(`MAX_PADS = 4` with `seat < 0 || seat >= MAX_PADS` guards, per-seat arrays
`padPreset`/`padActPrev`/`padSelectPrev` all `[MAX_PADS]`), the ini/config
buffers (`configRegisterString`'s `bufSize-1` `strncpy`, `padStr[MAX_PADS][PA_COUNT][32]`
filled by `snprintf` with `sizeof`), the build's region-macro set against the
N64 Makefile's `LCDEFS` (exact match for ntsc/pal/jpn-final), and the published
docs' claims against the findings index.
**The CI-blocking one:** `tools_pc/gen_env_probes.py --check` returned **rc 1** —
three probe vars in `port/fast3d/gfx_pc.cpp` (`GE_D526`, `GE_D526BOX`,
`GE_D526MAX`, the D526 box-tolerance family) had no row in
`docs/dev/GE-ENV-PROBES.md`. The self-hosted workflow runs that check as a hard
step ("Check generated dev indexes are current"), so the pushed branch would
have carried a red CI step. Fixed by documenting the family (it was already
listed in the `docs/porting-notes.md` §F10 probe table — the drift is between
the two generated-doc sources, not a missing record).
**`build-pc.sh` carried a local machine path.** Two messages named the
maintainer's alternate MSYS2 root (`D:\<games>\msys64` form — the tree here was
built for a different drive letter than the one it runs from). AGENTS rule 1
forbids local absolute paths in tracked files; both sites now say `C:\msys64`,
which is what the surrounding "add `C:\msys64\mingw64\bin` to your PATH" advice
already says. No behaviour change (the strings are diagnostics only; the toolchain
discovery itself is path-derived via `_ge_find_mingw_bin()`).
**`docs/fidelity.md` og description.** It read "…the one `#ifdef PORT` fix…" —
misleading: `src/` carries 736 `#ifdef PORT` gates (the §A1 class), and the
finding's claim is that exactly **one** of them is a game-logic-adjacent change.
The description now reads "one game-logic-adjacent change", and the trim keeps it
under the 160-char og limit (158). The body's precise claim is unchanged.
**The release notes quoted a stale measurement.** The Reference-frame-gate
paragraph carried the D525 cross-platform spread (0.348–3.983 %, worst cell mean
4.43, phash ≤6 except cradle 40) — measured before D531 re-captured all 21 linux
sets under the canonical save (47/63 frames moved). Recomputed from the
**committed** pairs (`framediff.py` win-vs-linux at the stems, tol 2): exact
**0.380–5.120 %** on the 20 non-Cuba levels (silo's 900 stem is the outlier —
cell mean 34.3, phash 10; streets 3.223–4.566), structural **21/21 clean**, max
phash 40 (cradle, at the threshold); Cuba 1.357–12.663 % is the structural-tier-only
level. The notes now carry the recomputed band and name the two gate pins a
reader would otherwise have to look up (canonical save content — D529; hard-pinned
seed — D532). The D525 figures stay in the ROADMAP row as the historical record
for closing the two residual bands; the row now also carries the recomputed band.
**Not changed (judgement calls left alone):** the `eepimport.c` `.bak99`
overwrite-on-rotation nit (cosmetic, 99-deep rotation is unreachable in practice),
the `docs/ROADMAP.md` "Known issues" heading anchor (valid), and the site pages'
own staleness (presentation layer, per AGENTS).
## D534: pre-release review of the 2026-10-05 local batch — Ctrl-C in the golden gate could leave the user's save replaced, plus doc accuracy fixes (release gate)
**Scope:** a read-only review of the 23 local commits of 2026-10-05
(`8fbf8aa0^..0b0f610c`) before the v0.5.0 cut; defects fixed in one batch.
**The real one — an interrupted gate run could clobber `data/ge007.eep`.**
`verify.sh` armed `trap 'restore_ini; restore_eep; kill_ours' EXIT INT TERM`
(`capture_p7.sh` the same shape). Bash runs an INT/TERM trap and then
*continues* the script: the restore put the user's save back and deleted the
snapshot, but `EEP_PIN_BAK` stayed set, so the next level's `pin_eep` skipped
the snapshot and installed the canonical save, and the final EXIT restore
copied from a deleted file — the user's own save was left replaced on disk.
Fix: restore on `EXIT` only, `INT`/`TERM` just `exit 130`/`143` (which fires
EXIT once); `restore_eep`/`restore_ini` now clear their snapshot state, so
they are idempotent. Tooling-only; the recipe is unchanged.
**Doc accuracy:** the release notes said "each platform's gate is green"
while the same paragraph said the linux pixel gate did not run — now "Windows
green; linux crash gate green, pixel verdict owed". `docs/security-and-fidelity-status.md`
was split into `security.md` + `fidelity.md` but still linked from `README.md`,
`.github/SECURITY.md` and the AGENTS.md site-page list (dead on publish) —
repointed. Fifty-odd `2026-10-07` dates (session labels "07a…07k" that leaked
in as calendar dates; every commit is dated 2026-10-05) normalised to
2026-10-05; lettered labels became "2026-10-05 (session 07x)".
**Nits:** the D526 census probe had a dangling `else` (bound to the inner
`if`, so with no `GE_D526BOX` the off-screen filter never ran) — braced;
`verify.sh`'s usage print (`sed -n '2,32p'`) cut the `--json`/`--against`
lines — now `2,34p`; an unbalanced bold in the ROADMAP Golden-baselines row.
@@ -1,16 +1,17 @@
--- ---
title: Under the Hood title: Documentation
description: The technical documentation for the GoldenEye 007 PC port; the architecture, the N64-to-PC bug catalogue, and how the project is developed. description: The technical documentation for the GoldenEye 007 PC port; the architecture, the N64-to-PC bug catalogue, and how the project is developed.
date: '2026-10-05'
modified_time: '2026-10-05'
--- ---
## Under the hood ## Documentation
The technical documentation for the port: how it works under the covers, the The technical documentation for the port: the **architecture** and how the
catalogue of N64→PC bugs it had to fix, and how the project is developed. project is **developed**. (Building and running from source live on the
(Building and running from source live on the separate separate [Building](building.md) page.)
[Building](building.md) page.)
### How it works ## Architecture
- **[Internals](internals.md)** — the architecture: the software RSP, the - **[Internals](internals.md)** — the architecture: the software RSP, the
port layer, the asset pipeline, and the phased plan. The single reference port layer, the asset pipeline, and the phased plan. The single reference
@@ -18,7 +19,7 @@ catalogue of N64→PC bugs it had to fix, and how the project is developed.
- **[Porting notes](porting-notes.md)** — the catalogue of N64→PC bugs: the - **[Porting notes](porting-notes.md)** — the catalogue of N64→PC bugs: the
recurring classes of defect and the ground-truth pattern each fix follows. recurring classes of defect and the ground-truth pattern each fix follows.
### How it's developed ## Development
- **[Development process](dev-process.md)** — the investigation workflow: - **[Development process](dev-process.md)** — the investigation workflow:
task budgets, file partitioning, the finding-log discipline, and the rules task budgets, file partitioning, the finding-log discipline, and the rules
@@ -26,18 +27,7 @@ catalogue of N64→PC bugs it had to fix, and how the project is developed.
- **[Agentic development](dev/agentic-development.md)** — the case study: - **[Agentic development](dev/agentic-development.md)** — the case study:
how the two-AI-agent setup ran, its timeline and numbers, and an honest how the two-AI-agent setup ran, its timeline and numbers, and an honest
read on what did and didn't work. read on what did and didn't work.
- **[Security status](security.md)** — what the release packages install
### Topic notes (and don't): no networking, no telemetry, no ROM, no system writes.
- **[Fidelity status](fidelity.md)** — how faithfully the port reproduces
Short, single-topic notes — the quick-orientation version of the longer docs the N64 game's logic, and what was audited to back that claim.
above:
- **[The software RSP](the-software-rsp.md)** — how the N64's graphics
coprocessor is emulated in software.
- **[The asset pipeline](the-asset-pipeline.md)** — how ROM assets become the
files the port loads at runtime.
- **[Framerate and pacing](framerate-and-pacing.md)** — the steady 60 fps,
frame pacing and per-frame timing.
- **[Input and aim](input-and-aim.md)** — controllers, keyboard, mouse aim
and rebinding.
- **[Saves](saves.md)** — the file-backed N64 save.
+72
View File
@@ -0,0 +1,72 @@
---
title: Fidelity status
description: How faithfully the port reproduces the N64 game: unmodified decompiled logic, Makefile-mirrored region macros, one game-logic-adjacent change, and PRNG notes.
date: '2026-10-05'
modified_time: '2026-10-05'
---
## Fidelity status
This page answers one question plainly: *how faithfully does the port
actually reproduce the original N64 game's logic*?
The audit was run end-to-end on 2026-09-15 and re-verified for the v0.3.0
release bundles on 2026-09-18.
**v0.5.0 update pass, 2026-10-05:** two of the checks were re-run
directly against the current tree — the region build macros were
compared line-by-line against the original N64 Makefile's macro sets
(all three regions match exactly), and the library file classification
(which original files compile versus get PC-shimmed) was re-checked
against the project's own ground-truth manifest (the CMake build
compiles the libultra and libultrare audio sets, the gu matrix helpers,
and `io/vitbl.c` only — no silent gaps, no silent duplicates). The
full game-logic audit was not re-run in this pass; recent `src/game`
edits on the release branch are finding-gated (for example the D519
front-end options work, and a model-c scripted-camera clamp removal
that returned those files to pure decompilation). The full engineering
record behind each item is in the project's finding log
([`docs/dev/findings.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/dev/findings.md)).
## The rule and what was checked
The port's non-negotiable rule is that decompiled game logic is never
changed — only genuine N64-hardware dependencies get a PC-side
replacement, in the `port/` layer. This was audited directly:
- **Region build macros** exactly mirror the original N64 Makefile's macro
sets for all three regions — verified line-by-line (re-run 2026-10-05).
- **The audio/library file classification** (which original files compile
vs. get PC-shimmed) exactly matches the project's own ground-truth
manifest — no silent gaps, no silent duplicates (re-run 2026-10-05).
- **The one shipped game-logic-adjacent change** (a portal-culling
float-precision fix, D271) is `#ifdef PORT`-gated, documented in the
finding log, and moves *toward* matching N64 behavior, not away from it.
Every other deviation from the decompiled source is one of the documented
32→64-bit pointer-width ABI corrections described above.
## One issue, found and fixed before v0.3.0 shipped
The port's random-number generator (`port/src/random.c`) was documented
as a bit-exact port of the N64's PRNG, but wasn't — a shift-operation
helper didn't match the real MIPS64 instruction semantics it was meant to
mirror. This was independently confirmed by hand-tracing the assembly
against the C port, tracked as finding D284, and fixed before the release
(verified clean across a full level sweep — all 20 missions plus the
ending sequence — no crashes). It affected loot placement, AI behavior
variance, and replay-state determinism from the very first random draw,
in every release before v0.3.0. Because of the fix, RNG-derived output —
including the save-file CRC — changed, which meant existing save files
and any previously recorded replays no longer validate; v0.3.0's release
notes describe the automatic save migration that handles this. We'd
rather say this plainly than let a "verified bit-exact" claim stand
uncorrected, both when it was wrong and now that it's fixed.
Everything else checked (the documented ABI/pointer-width exceptions used
for the 32-to-64-bit transition, a sample of the finding log's own claimed
fixes against the actual current code) matched what's documented.
---
*This page is kept current alongside future releases. Its source review is a
manual, human-reviewed process today — see the project roadmap for plans to
partially automate the mechanical parts of it.*
+2
View File
@@ -1,6 +1,8 @@
--- ---
title: Framerate and pacing title: Framerate and pacing
description: How the GoldenEye 007 PC port holds a steady 60 fps and keeps per-frame game timing correct on a fast CPU. description: How the GoldenEye 007 PC port holds a steady 60 fps and keeps per-frame game timing correct on a fast CPU.
date: '2026-10-05'
modified_time: '2026-10-05'
--- ---
## Framerate and pacing ## Framerate and pacing
+158 -164
View File
@@ -5,6 +5,16 @@ description: >-
A native PC port of GoldenEye 007 (Nintendo 64, 1997), built from A native PC port of GoldenEye 007 (Nintendo 64, 1997), built from
decompiled source with a software RSP. v0.5.0 for Windows, Linux and decompiled source with a software RSP. v0.5.0 for Windows, Linux and
Steam Deck. Steam Deck.
# Freshness signals for jekyll-seo-tag (article:published_time / modified_time
# and the WebPage JSON-LD dates). Keep these equal to the last real content
# change of THIS page, not to the last release.
date: '2026-10-05'
modified_time: '2026-10-05'
locale: en_US
# The masthead is this page's title, so its first content h2 must NOT get the
# amber page-title look (double header). See the .flat-title rule in
# _includes/head-custom.html.
flat_title: true
--- ---
A native PC port of _GoldenEye 007_ (Rare, 1997, Nintendo 64), compiled from A native PC port of _GoldenEye 007_ (Rare, 1997, Nintendo 64), compiled from
@@ -16,60 +26,82 @@ in a dedicated `port/` layer, following the architecture of the
[Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark), the same [Perfect Dark PC port](https://github.com/fgsfdsfgs/perfect_dark), the same
Rare "Indy" engine family, one hardware generation apart. Rare "Indy" engine family, one hardware generation apart.
[Download](#download) · [News](#news) · [See it running](#see-it-running) · [Known issues](#known-issues) · [Documentation](#documentation) [Status](#status) · [Download](#download) · [See it running](#see-it-running) · [Known issues](#known-issues) · [Documentation](#documentation)
**Status: v0.5.0 (2026-10-05) — fully playable, with a small set of known ## Status
caveats.** The single-player campaign and the 2–4 player split-screen
multiplayer both run at a steady 60 fps. The single-player campaign is
completable end to end (all 20 missions plus the ending-credits sequence),
and the 2–4 player split-screen campaign is supported on every multiplayer
map; both were playtested on Windows, Linux and Steam Deck. This release
adds **one
options menu** (laid out like the Perfect Dark port's, with plain-English
wording, real-unit sliders and a one-line description per option), the game's
own **N64 control styles as a per-seat preset**, **direct loading of
emulator save files**, a **scalable HUD overlay**, fullscreen and
window-centring controls, and a **fidelity round checked frame-by-frame
against the N64 game** (fog, aspect-ratio letterboxing, the Watch menu's own
settings). What remains is a short list, under
[Known issues](#known-issues).
**This is a pre-1.0 release, not a finished product** — v1.0 is the target <div class="cblock">
### v0.5.0 (2026-10-05) — the campaign and split-screen both run end to end.
- **Single-player campaign complete.** All 20 missions plus the
ending-credits sequence, completable end to end at a steady 60 fps.
- **2–4 player split-screen multiplayer.** Supported on every multiplayer
map; playtested on Windows, Linux and Steam Deck.
- **One real options system.** A single menu, laid out like the Perfect
Dark port's — plain-English wording, real-unit sliders, a one-line
description per option — with the game's own **N64 control styles as a
per-seat preset**.
- **Emulator save files load directly.** Copy a 1964 / Project64 save into
`data/` and it is converted on first launch.
- **A scalable HUD overlay**, fullscreen and window-centring controls, and
antialiased overlay controls.
- **A fidelity round checked frame-by-frame against the N64 game** (fog,
aspect-ratio letterboxing, the Watch menu's own settings), with the
reference-frame gate re-based on both platforms (21 levels, 63 frames
each).
- The small stuff: a menu wording, units and help-text pass, and
standardised menu spelling.
</div>
What remains is a short list, under [Known issues](#known-issues).
**This is a pre-1.0 release, not a finished product.** v1.0 is the target
for a polished, feature-complete build; expect missing features and the for a polished, feature-complete build; expect missing features and the
occasional breaking change until then. See the occasional breaking change until then. The [README's Roadmap
[README's Roadmap section](https://github.com/jkdansereau/goldeneye-pc-port#roadmap) section](https://github.com/jkdansereau/goldeneye-pc-port#roadmap) is the
for direction (PAL/JP ROM support, macOS and ARM builds, the remaining small single tracker for what comes next.
accuracy differences, and post-1.0 opt-in extras).
## News <details id="known-issues">
<summary>Known issues</summary>
- **2026-10-05** — **v0.5.0**: one options menu with plain-English wording, <p>Full table in the <a href="https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/ROADMAP.md#known-issues">roadmap's known-issues section</a>; root causes in the <a href="https://github.com/jkdansereau/goldeneye-pc-port/tree/main/docs/dev">finding log</a>.</p>
real-unit sliders and a one-line description per option; the N64 control
styles as a per-seat preset; direct emulator-save loading; a scalable HUD <ul>
overlay; fullscreen and window-centring controls; and a fidelity round <li><strong>NTSC-U ROMs only in the release packages.</strong> PAL and JP ROMs convert, build and run from source, but release packages ship the US (NTSC-U) ROM. On the roadmap.</li>
checked frame-by-frame against the N64 game. The reference-frame gate was <li><strong>Changing the aspect ratio in a level can briefly glitch the gun/hand model</strong> (cosmetic, one-off). Change the ratio from the front-end PC Options, or accept it (D509).</li>
re-based on both platforms (21 levels, 63 frames each). <li><strong>No macOS or ARM builds yet.</strong> Today the release ships Windows, Linux and Steam Deck (keyboard, mouse and controller-button rebinding are all supported, defaults in the <a href="https://github.com/jkdansereau/goldeneye-pc-port#controls">README's Controls section</a>); macOS and ARM are on the roadmap.</li>
[Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0) · <li><strong><code>Skip intro</code> and <code>All unlocked</code> are experimental</strong> — leave them off for a normal playthrough. <code>All unlocked</code> has not written your save since v0.4.1, but saves made while it was on in builds before v0.4.1 can hold fake unlocks and are not repaired; back up <code>data/ge007.eep</code> if you used it on an older build (D442, D387).</li>
[downloads](#download). <li><strong>The first frame of a level takes a little longer</strong> while its textures upload — a brief FPS-counter dip; nothing to fix (D475, D480).</li>
- **2026-09-28** — **v0.4.0**: native widescreen, a complete aim system for <li><strong>In widescreen, far objects almost fully in fog can still show a faint distant building edge</strong> (4:3 matches the N64). Cosmetic (D503).</li>
mouse and controller, in-game key rebinding, crosshair customization, </ul>
rumble-pak haptics, a rebuilt options overlay, and a broad fidelity-fix
pass (water, particles, billboard trees, front-end logo, gunshot SFX, a </details>
true stable 60 fps). [Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.4.0) ·
[downloads](#download). <details>
- **2026-09-20** — **v0.3.0**: the first release with the complete campaign <summary>Release history</summary>
playable end to end at 60 fps on Windows, Linux, and Steam Deck.
[Release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.3.0). <p class="warn"><strong>Warning:</strong> always use the latest release — earlier builds are kept in the release history for reference only; they lack the features and fixes of newer versions, so don't install an older release.</p>
- **2026-09-04 → 2026-09-16** — **v0.1.0 – v0.2.2**: the alpha and beta
cycle — build chain, software RSP, first rendered frames, front end, and <ul>
per-level stabilization across the campaign. <li><strong>2026-10-05 — v0.5.0</strong>: what it adds is the Status list above. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.5.0">Release notes</a>.</li>
<li><strong>2026-09-28 — v0.4.0</strong>: native widescreen, a complete aim system for mouse and controller, in-game key rebinding, crosshair customization, rumble-pak haptics, a rebuilt options overlay, and a broad fidelity-fix pass. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.4.0">Release notes</a>.</li>
<li><strong>2026-09-20 — v0.3.0</strong>: the first release with the complete campaign playable end to end at 60 fps on Windows, Linux, and Steam Deck. <a href="https://github.com/jkdansereau/goldeneye-pc-port/releases/tag/v0.3.0">Release notes</a>.</li>
<li><strong>2026-09-04 → 2026-09-16 — v0.1.0 – v0.2.2</strong>: the alpha and beta cycle — build chain, software RSP, first rendered frames, front end, and per-level stabilization across the campaign.</li>
</ul>
</details>
## Download ## Download
<div class="cblock">
| Platform | Bundle | Notes | | Platform | Bundle | Notes |
|---|---|---| |---|---|---|
| **Windows** (x86_64) | [win64.zip](https://github.com/jkdansereau/goldeneye-pc-port/releases) | Engine + runtime DLLs + the one-time asset tool. | | **Windows** (x86_64) | [win64.zip](https://github.com/jkdansereau/goldeneye-pc-port/releases) | Engine + runtime DLLs + the one-time asset tool. |
| **Linux** (x86_64) / **Steam Deck** | [linux tarball](https://github.com/jkdansereau/goldeneye-pc-port/releases) | SDL2 is bundled, so it runs as-is on any distro, and sideloads onto a Deck with nothing installed. | | **Linux** (x86_64) / **Steam Deck** | [linux tarball](https://github.com/jkdansereau/goldeneye-pc-port/releases) | SDL2 is bundled, so it runs as-is on any distro, and sideloads onto a Deck with nothing installed. |
| macOS / ARM Linux | — | Roadmap: not shipped yet. |
**Bring your own ROM.** Both bundles contain no ROM and no game assets: you **Bring your own ROM.** Both bundles contain no ROM and no game assets: you
supply your own GoldenEye 007 N64 ROM (the supply your own GoldenEye 007 N64 ROM (the
@@ -79,8 +111,16 @@ ROM; PAL and JP are on the roadmap. Then: unpack, drop the ROM in `data/`,
and launch; the first run generates the derived assets automatically (no and launch; the first run generates the derived assets automatically (no
Python or other tooling needed). The full steps are in the Python or other tooling needed). The full steps are in the
[Quick start](https://github.com/jkdansereau/goldeneye-pc-port#quick-start); [Quick start](https://github.com/jkdansereau/goldeneye-pc-port#quick-start);
pre-built releases are legal to distribute precisely because they're useless the packages carry no ROM or game assets, and run only with a ROM you
without a ROM you already own. already own. The binaries are not code-signed; each
release artifact carries a GitHub build-provenance attestation you can
verify with `gh attestation verify <file> --repo
jkdansereau/goldeneye-pc-port`.
</div>
What the release actually installs is covered on [Security status](security.md);
how faithfully it tracks the N64 game, on [Fidelity status](fidelity.md).
## See it running ## See it running
@@ -91,74 +131,17 @@ without a ROM you already own.
<span class="idx" id="vIdx">1 / 12</span> <span class="idx" id="vIdx">1 / 12</span>
</div> </div>
<div class="vstage"> <div class="vstage">
<img id="vImg" src="img/shots/shot-01.jpg" alt="in-engine capture"> <img id="vImg" src="img/shots/shot-01.jpg" alt="GoldenEye 007 PC port — Dam (v0.4.0 intro attract), in-engine capture">
<button class="vbtn prev" id="vPrev" aria-label="previous capture">&#8249;</button> <button class="vbtn prev" id="vPrev" aria-label="previous capture">&#8249;</button>
<button class="vbtn next" id="vNext" aria-label="next capture">&#8250;</button> <button class="vbtn next" id="vNext" aria-label="next capture">&#8250;</button>
</div> </div>
<div class="vcap"><span id="vCap">Dam &mdash; v0.4.0 intro attract</span></div> <div class="vcap"><span id="vCap">Dam &mdash; v0.4.0 intro attract</span></div>
</div> </div>
<details>
<summary><strong>Full gallery</strong>: 12 in-engine captures from a v0.4.0 intro-attract pass (3072×1728 widescreen, Sep 2026)</summary>
<p align="center">
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-01.jpg" width="100%" alt="In-engine: Dam (v0.4.0 intro attract)">
<div><small>Dam</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-03.jpg" width="100%" alt="In-engine: Runway (v0.4.0 intro attract)">
<div><small>Runway</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-04.jpg" width="100%" alt="In-engine: Surface (v0.4.0 intro attract)">
<div><small>Surface</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-09.jpg" width="100%" alt="In-engine: Frigate (v0.4.0 intro attract)">
<div><small>Frigate</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-11.jpg" width="100%" alt="In-engine: Surface 2 (v0.4.0 intro attract)">
<div><small>Surface 2</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-16.jpg" width="100%" alt="In-engine: Statue (v0.4.0 intro attract)">
<div><small>Statue</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-20.jpg" width="100%" alt="In-engine: Archives (v0.4.0 intro attract)">
<div><small>Archives</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-21.jpg" width="100%" alt="In-engine: Cradle (v0.4.0 intro attract)">
<div><small>Cradle</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-24.jpg" width="100%" alt="In-engine: Aztec (v0.4.0 intro attract)">
<div><small>Aztec</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-27.jpg" width="100%" alt="In-engine: Control (v0.4.0 intro attract)">
<div><small>Control</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-28.jpg" width="100%" alt="In-engine: Streets (v0.4.0 intro attract)">
<div><small>Streets</small></div>
</div>
<div style="width:32%;text-align:center;margin:4px">
<img src="img/shots/shot-29.jpg" width="100%" alt="In-engine: Jungle (v0.4.0 intro attract)">
<div><small>Jungle</small></div>
</div>
</p>
</details>
More captures may land here as playtesting continues.
## Play it, or take it apart ## Play it, or take it apart
- **Try it yourself**: grab a bundle above, bring your own ROM, and play the - **Try it yourself**: grab a bundle above, bring your own ROM, and play the
campaign. It's an early cut for exactly this: if something breaks, an campaign. It's a pre-1.0 build for exactly this: if something breaks, an
[issue](https://github.com/jkdansereau/goldeneye-pc-port/issues) with what [issue](https://github.com/jkdansereau/goldeneye-pc-port/issues) with what
you were doing is genuinely useful. you were doing is genuinely useful.
- **Read the code**: the game logic in `src/` is unmodified decompilation; - **Read the code**: the game logic in `src/` is unmodified decompilation;
@@ -172,80 +155,51 @@ More captures may land here as playtesting continues.
asset sidecar. [CONTRIBUTING](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/CONTRIBUTING.md) asset sidecar. [CONTRIBUTING](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/CONTRIBUTING.md)
has the ground rules that keep it faithful to the original game. has the ground rules that keep it faithful to the original game.
- **AI disclosure**: development here used AI coding agents — Claude Code - **AI disclosure**: development here used AI coding agents — Claude Code
plus a local open-weight model on a single RTX 5090, directed by one person in their plus a local open-weight model on a single RTX 5090, directed by one person
spare time. The project is as much a study of that process as it is a in their spare time. The project is as much a study of that process as it
port, and the write-up is written to let you judge the result for yourself; is a port; the write-up records what happened and takes no position for or
it records what happened and takes no position for or against using LLMs against using LLMs on a project like this. See [the full
on a project like this. See [the full
write-up](dev/agentic-development.md) — the setup, timeline, handoff write-up](dev/agentic-development.md) — the setup, timeline, handoff
workflow, and an honest account of what did and didn't work. workflow, and an honest account of what did and didn't work.
## How it works ## How it works
The R4300 game code's logic and control flow are the decompilation's, and remain the The R4300 game code's logic and control flow are the decompilation's, and
reference we preserve. The port's changes inside `src/` are few in kind (mostly mechanical 32→64-bit pointer fixes, a couple of approved timing fixes, and the opt-in *All unlocked* hook), each gated behind `#ifdef PORT`. The N64's Reality Signal Processor, the graphics remain the reference we preserve. The port's changes inside `src/` are few in
coprocessor that builds and executes each frame's display list, is emulated in kind and each is gated behind `#ifdef PORT`: mechanical 32→64-bit
software: the port interprets the graphics command stream (GBI) the game emits and translates it pointer-width fixes, a couple of approved timing fixes, and the opt-in
to OpenGL, bypassing the RDP entirely. Everything else that would touch N64 *All unlocked* and *Skip intro* hooks. The N64's Reality Signal Processor
hardware (video, audio, input, timers, save storage) is shimmed in a small (RSP), the graphics coprocessor that builds and executes each frame's
dedicated layer, following the architecture of the Perfect Dark PC port from display list, is emulated in software: the port interprets the graphics
the same Rare engine family. Full detail: [Internals](internals.md); the bug command stream (GBI) the game emits and translates it to OpenGL, bypassing
the RDP entirely. Everything else that would touch N64 hardware (video,
audio, input, timers, save storage) is shimmed in a small dedicated layer,
following the architecture of the Perfect Dark PC port from the same Rare
engine family. Full detail: [Internals](internals.md); the bug
catalogue: [Porting notes](porting-notes.md). catalogue: [Porting notes](porting-notes.md).
## Known issues
Known defects and limitations as of v0.5.0, each with its finding-log
reference. The full list, with root causes and fix status: the
[release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases)
and the [finding log](https://github.com/jkdansereau/goldeneye-pc-port/tree/main/docs/dev).
- **Facility — gas leak during Ourumov's monologue (D318).** If gas leaks,
he can pause for up to ~10 s before the scripted shootout resumes. The
race exists in the N64 original too (where it softlocks permanently);
the port detects it and auto-recovers.
- **F10 options overlay under native widescreen (D335b).** The overlay
stretches with the window instead of pillarboxing like the front-end
menus. Legible, cosmetic only; the F10 *Native widescreen* toggle
restores the old stretched frame throughout. The world/HUD widescreen
rendering itself is correct.
- **Front-end Rareware logo (D75).** A subtle texture-filtering artifact;
the Nintendo logo and legal page are clean. Cosmetic only.
- **`All unlocked` is experimental (D387).** The fresh-install corruption
case is fixed, but saves made while it is on are not guaranteed
recoverable by switching it off — complete a level normally first, and
back up `data/ge007.eep` before enabling it.
- **No macOS or ARM builds yet** (both are on the
[roadmap](https://github.com/jkdansereau/goldeneye-pc-port#roadmap));
today the release ships Windows, Linux and Steam Deck. Keyboard, mouse
and controller-button rebinding are all supported (defaults in the
[README's Controls section](https://github.com/jkdansereau/goldeneye-pc-port#controls)).
What the release actually installs, and how faithfully it tracks the N64
game: [Security & fidelity status](security-and-fidelity-status.md).
## Documentation ## Documentation
The technical docs live under [under the The technical docs live on the [Documentation](documentation.md) page — the
hood](under-the-hood.md) — the architecture, the N64→PC bug catalogue, and architecture, the N64→PC bug catalogue, and how the project is developed.
how the project is developed. [Building](building.md) covers building and [Building](building.md) covers building and running from source.
running from source.
<script> <script>
// console-viewer carousel: one media slot, cycle the captures. Vanilla JS. // console-viewer carousel: one media slot, cycle the captures. Vanilla JS.
(function () { (function () {
var slides = [ var slides = [
{ src:"img/shots/shot-01.jpg", cap:"Dam &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-01.jpg", cap:"Dam — v0.4.0 intro attract" },
{ src:"img/shots/shot-03.jpg", cap:"Runway &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-03.jpg", cap:"Runway — v0.4.0 intro attract" },
{ src:"img/shots/shot-04.jpg", cap:"Surface &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-04.jpg", cap:"Surface — v0.4.0 intro attract" },
{ src:"img/shots/shot-09.jpg", cap:"Frigate &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-09.jpg", cap:"Frigate — v0.4.0 intro attract" },
{ src:"img/shots/shot-11.jpg", cap:"Surface 2 &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-11.jpg", cap:"Surface 2 — v0.4.0 intro attract" },
{ src:"img/shots/shot-16.jpg", cap:"Statue &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-16.jpg", cap:"Statue — v0.4.0 intro attract" },
{ src:"img/shots/shot-20.jpg", cap:"Archives &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-20.jpg", cap:"Archives — v0.4.0 intro attract" },
{ src:"img/shots/shot-21.jpg", cap:"Cradle &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-21.jpg", cap:"Cradle — v0.4.0 intro attract" },
{ src:"img/shots/shot-24.jpg", cap:"Aztec &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-24.jpg", cap:"Aztec — v0.4.0 intro attract" },
{ src:"img/shots/shot-27.jpg", cap:"Control &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-27.jpg", cap:"Control — v0.4.0 intro attract" },
{ src:"img/shots/shot-28.jpg", cap:"Streets &mdash; v0.4.0 intro attract" }, { src:"img/shots/shot-28.jpg", cap:"Streets — v0.4.0 intro attract" },
{ src:"img/shots/shot-29.jpg", cap:"Jungle &mdash; v0.4.0 intro attract" } { src:"img/shots/shot-29.jpg", cap:"Jungle — v0.4.0 intro attract" }
]; ];
var img = document.getElementById("vImg"), var img = document.getElementById("vImg"),
cap = document.getElementById("vCap"), cap = document.getElementById("vCap"),
@@ -254,7 +208,9 @@ running from source.
function show(n) { function show(n) {
i = (n + slides.length) % slides.length; i = (n + slides.length) % slides.length;
img.src = slides[i].src; img.src = slides[i].src;
cap.innerHTML = slides[i].cap; img.alt = "GoldenEye 007 PC port — " + slides[i].cap +
", in-engine capture, 3072×1728";
cap.textContent = slides[i].cap;
idx.textContent = (i + 1) + " / " + slides.length; idx.textContent = (i + 1) + " / " + slides.length;
} }
document.getElementById("vPrev").addEventListener("click", function () { show(i - 1); }); document.getElementById("vPrev").addEventListener("click", function () { show(i - 1); });
@@ -266,3 +222,41 @@ running from source.
show(0); show(0);
})(); })();
</script> </script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Software",
"name": "GoldenEye 007 PC Port",
"genericName": "Native PC port of a Nintendo 64 game",
"softwareName": "GoldenEye 007 PC Port",
"category": "GameCategory",
"description": "A native PC build of GoldenEye 007 (Rare, 1997, Nintendo 64), compiled from the n64decomp/007 decompilation with the N64's RSP emulated in software. Ships no ROM and no game assets; you supply your own.",
"softwareVersion": "0.5.0",
"datePublished": "2026-10-05",
"dateModified": "2026-10-05",
"operatingSystem": ["Windows", "Linux", "Steam Deck"],
"downloadUrl": "https://github.com/jkdansereau/goldeneye-pc-port/releases",
"distributionType": "Software-Offline",
"officialDistribution": {
"@type": "SoftwareDistribution",
"downloadUrl": "https://github.com/jkdansereau/goldeneye-pc-port/releases",
"distributionLicense": "MIT"
},
"license": "https://opensource.org/licenses/MIT",
"isFreeApplication": true,
"url": "https://jkdansereau.github.io/goldeneye-pc-port/",
"sameAs": "https://github.com/jkdansereau/goldeneye-pc-port",
"publisher": {
"@type": "Person",
"name": "jkdansereau",
"url": "https://github.com/jkdansereau"
},
"gallery": [
"https://jkdansereau.github.io/goldeneye-pc-port/img/shots/shot-28.jpg",
"https://jkdansereau.github.io/goldeneye-pc-port/img/shots/shot-01.jpg",
"https://jkdansereau.github.io/goldeneye-pc-port/img/shots/shot-24.jpg"
],
"alternateName": "GoldenEye 007 (Nintendo 64, 1997) on the PC"
}
</script>
+2
View File
@@ -1,6 +1,8 @@
--- ---
title: Input and aim title: Input and aim
description: How the GoldenEye 007 PC port maps keyboard, mouse and modern controllers onto the N64's controller, including mouse aim. description: How the GoldenEye 007 PC port maps keyboard, mouse and modern controllers onto the N64's controller, including mouse aim.
date: '2026-10-05'
modified_time: '2026-10-05'
--- ---
## Input and aim ## Input and aim
+1 -1
View File
@@ -3,7 +3,7 @@ title: Internals
description: Architecture behind the PC port; the software RSP-emulation approach, GoldenEye-vs-Perfect-Dark engine differences, and the phased development plan. description: Architecture behind the PC port; the software RSP-emulation approach, GoldenEye-vs-Perfect-Dark engine differences, and the phased development plan.
--- ---
## GoldenEye 007 PC Port: architecture & plan ## Architecture & plan
> This began as the pre-implementation research note and is kept as the > This began as the pre-implementation research note and is kept as the
> architecture reference. Sections 1–9 describe the design; section 10 lists > architecture reference. Sections 1–9 describe the design; section 10 lists
+3 -3
View File
@@ -19,14 +19,14 @@ good that you are looking at one of these.
## Contents ## Contents
- [A. Pointer-width struct growth (32→64); the dominant class](#a-pointer-width-struct-growth-3264--the-dominant-class) - [A. Pointer-width struct growth (32→64); the dominant class](#a-pointer-width-struct-growth-3264-the-dominant-class)
- [B. 16-byte PC `Gfx` / `Vtx` vs 8-byte N64](#b-16-byte-pc-gfx--vtx-vs-8-byte-n64) - [B. 16-byte PC `Gfx` / `Vtx` vs 8-byte N64](#b-16-byte-pc-gfx--vtx-vs-8-byte-n64)
- [C. Big-endian rodata / ROM data read on little-endian PC](#c-big-endian-rodata--rom-data-read-on-little-endian-pc) - [C. Big-endian rodata / ROM data read on little-endian PC](#c-big-endian-rodata--rom-data-read-on-little-endian-pc)
- [C2. Port-layer / SDL shims](#c2-port-layer--sdl-shims) - [C2. Port-layer / SDL shims](#c2-port-layer--sdl-shims)
- [D. N64 hardware idioms fast3d does not emulate](#d-n64-hardware-idioms-fast3d-does-not-emulate) - [D. N64 hardware idioms fast3d does not emulate](#d-n64-hardware-idioms-fast3d-does-not-emulate)
- [D2. The HUD/model "X-mirror"; RESOLVED](#d2-the-hudmodel-x-mirror-d114d116--resolved-it-was-an-upside-down-capture) - [D2. The HUD/model "X-mirror"; RESOLVED](#d2-the-hudmodel-x-mirror-d114d116-resolved-it-was-an-upside-down-capture)
- [D3. GCC/mingw makes an all-non-negative `enum` UNSIGNED](#d3-gccmingw-makes-an-all-non-negative-enum-unsigned) - [D3. GCC/mingw makes an all-non-negative `enum` UNSIGNED](#d3-gccmingw-makes-an-all-non-negative-enum-unsigned)
- [D4. N64 "interrupts off" must be a real lock on PC](#d4-n64-interrupts-off-is-not-free-on-pc--it-must-be-a-real-lock) - [D4. N64 "interrupts off" must be a real lock on PC](#d4-n64-interrupts-off-is-not-free-on-pc-it-must-be-a-real-lock)
- [D5. Loop bounds that assume linker adjacency of two globals](#d5-loop-bounds-that-assume-linker-adjacency-of-two-file-scope-globals) - [D5. Loop bounds that assume linker adjacency of two globals](#d5-loop-bounds-that-assume-linker-adjacency-of-two-file-scope-globals)
- [D12. Collapsing an LOD binding to tile 0 breaks a DETAIL binding](#d12-collapse-an-lod-binding-to-tile-0-is-wrong-for-a-two-texture-detail-binding-d236) - [D12. Collapsing an LOD binding to tile 0 breaks a DETAIL binding](#d12-collapse-an-lod-binding-to-tile-0-is-wrong-for-a-two-texture-detail-binding-d236)
- [D13. Per-render accumulation is not associative (1 vs 2–3 ticks/frame)](#d13-per-render-accumulation-is-not-associative-the-ports-1-tickframe-can-reach-states-the-n64s-23-ticksframe-never-did-d329) - [D13. Per-render accumulation is not associative (1 vs 2–3 ticks/frame)](#d13-per-render-accumulation-is-not-associative-the-ports-1-tickframe-can-reach-states-the-n64s-23-ticksframe-never-did-d329)
+2
View File
@@ -1,6 +1,8 @@
--- ---
title: Saves title: Saves
description: How the GoldenEye 007 PC port backs the N64's EEPROM save with a plain file you can back up. description: How the GoldenEye 007 PC port backs the N64's EEPROM save with a plain file you can back up.
date: '2026-10-05'
modified_time: '2026-10-05'
--- ---
## Saves ## Saves
-115
View File
@@ -1,115 +0,0 @@
---
title: Security & fidelity status
description: What a release actually installs (no networking, no telemetry, no ROM or assets)
and how faithfully the port tracks the original N64 game's logic.
---
## Security & fidelity status
This page answers two questions plainly: *what does installing this put on
your machine*, and *how faithfully does the port actually reproduce the
original N64 game's logic*. Both were reviewed end-to-end on 2026-09-15 and
re-verified for the v0.3.0 release bundles on 2026-09-18 (bundle contents,
no-networking source check, and the asset converter). The no-networking source
check was repeated against the `release/v0.4.1` tree on 2026-09-30 (no socket,
HTTP or name-resolution calls in `src/` or `port/`; neither the engine nor the
bundled `SDL2.dll` imports a networking DLL; no registry calls in the port's
own code); the bundle contents were not re-checked then. The full engineering
record behind each item is in the project's finding log
([`docs/dev/findings.md`](dev/findings.md)).
## What a release actually installs
Each release (`goldeneye-pc-port-*-win64.zip` / `-linux-x86_64.tar.gz`)
contains, and only contains: the game engine executable, a fixed set of
standard runtime libraries (SDL2, zlib, and the MinGW/Linux runtime — no
third-party downloads), the one-time ROM-to-PC asset converter, a README,
and license texts. The build scripts hard-fail if a ROM image or an
oversized blob ends up in the bundle. **No ROM, no game assets (textures,
audio, models, levels, text) are ever shipped** — you supply your own
legally-owned copy.
At runtime, the engine:
- has **no networking of any kind** (no sockets, no HTTP, checked directly
against the source),
- has **no telemetry, crash reporting, or analytics** of any kind,
- **never touches the Windows registry** and **never requests elevated
permissions**,
- writes save data, config, and derived ROM assets only inside its own
folder — never to `%APPDATA%`, `Program Files`, or any system location.
The one-time asset converter (`ge007-convert` / `prepare-assets.py`) — the
part of the bundle most likely to draw suspicion, since it's the thing that
reads your ROM and writes new files — has no network access at all,
verifies your ROM against a fixed table of known retail GoldenEye 007
hashes before touching it (an unrecognized file is rejected outright), and
writes only inside the bundle folder. Its full source ships right next to
the compiled version in every release if you'd like to read it yourself. The
engine starts it automatically on the first run, when the two derived asset
folders (`data/pcmodels-*`, `data/pccg-*`) are missing, passing it the ROM it
found and the output folder; after that first run it is not launched again.
See [`SECURITY.md`](../.github/SECURITY.md) for why the binaries are
unsigned and what that means in practice (a SmartScreen prompt on first
run, and why some antivirus engines flag the converter specifically).
## Building from source
Cloning and building pulls in only standard, well-known packages: MSYS2
`pacman` packages on Windows, `apt` packages on Linux — no `npm`, no
`cargo`, nothing downloaded at CMake configure time, no git submodules, and
no prebuilt binaries checked into the repository. The CI build freezes the release's asset-converter tool with `pyinstaller`,
which is pinned to an exact version, and every third-party GitHub Action the
workflows use is pinned to a full commit SHA (both from the release after
v0.4.0; earlier releases installed an unpinned `pyinstaller`). What
PyInstaller packages is entirely in-repo, stdlib-only Python, so a release is
reproducible from a diff of this repository.
One development-only backdoor exists in source builds: the `GE_DEBUG_UNLOCKALL`
environment variable (`src/game/file2.c`) pre-unlocks all cheat options at boot.
It is off unless explicitly set, changes no shipped behavior, and is documented
here so the env-var surface stays fully accounted for.
## Fidelity to the original N64 game
The port's non-negotiable rule is that decompiled game logic is never
changed — only genuine N64-hardware dependencies get a PC-side
replacement, in the `port/` layer. This was audited directly:
- **Region build macros** exactly mirror the original N64 Makefile's macro
sets for all three regions — verified line-by-line.
- **The audio/library file classification** (which original files compile
vs. get PC-shimmed) exactly matches the project's own ground-truth
manifest — no silent gaps, no silent duplicates.
- **The one shipped game-logic-adjacent change** (a portal-culling
float-precision fix, D271) is `#ifdef PORT`-gated, documented in the
finding log, and moves *toward* matching N64 behavior, not away from it.
Every other deviation from the decompiled source is one of the documented
32→64-bit pointer-width ABI corrections described above.
**One issue, found and fixed before v0.3.0 shipped**: the port's
random-number generator (`port/src/random.c`) was documented as a bit-exact
port of the N64's PRNG, but wasn't — a shift-operation helper didn't match
the real MIPS64 instruction semantics it was meant to mirror. This was
independently confirmed by hand-tracing the assembly against the C port,
tracked as finding D284, and fixed before the release (verified clean
across a full level sweep — all 20 missions plus the ending sequence —
no crashes). It affected loot placement, AI
behavior variance, and replay-state determinism from the very first random
draw, in every release before v0.3.0. Because of the fix, RNG-derived
output — including the save-file CRC — changed, which meant existing save
files and any previously recorded replays no longer validate; v0.3.0's
release notes describe the automatic save migration that handles this. We'd
rather say this plainly than let a "verified bit-exact" claim stand
uncorrected, both when it was wrong and now that it's fixed.
Everything else checked (the documented ABI/pointer-width exceptions used
for the 32-to-64-bit transition, a sample of the finding log's own claimed
fixes against the actual current code) matched what's documented.
---
*This page is kept current alongside future releases. Its source review is a
manual, human-reviewed process today — see the project roadmap for plans to
partially automate the mechanical parts of it.*
+87
View File
@@ -0,0 +1,87 @@
---
title: Security status
description: What a GoldenEye PC port release installs and doesn't: no networking, no telemetry, no ROM, no system writes — re-verified against the v0.5.0 source.
date: '2026-10-05'
modified_time: '2026-10-05'
---
## Security status
This page answers one question plainly: *what does installing this put on
your machine*? The review was done
end-to-end on 2026-09-15 and re-verified for the v0.3.0 release bundles on
2026-09-18 (bundle contents, no-networking source check, and the asset
converter). The no-networking source check was repeated against the
`release/v0.4.1` tree on 2026-09-30 (no socket, HTTP or name-resolution
calls in `src/` or `port/`; neither the engine nor the bundled `SDL2.dll`
imports a networking DLL; no registry calls in the port's own code); the
bundle contents were not re-checked then.
**v0.5.0 update pass, 2026-10-05:** the source checks were re-run against
the current tree — no socket/network includes, no network symbols and no
HTTP string literals in the compiled `src/` and `port/` sets; no registry
or library-loading calls in either; the converter's Python sources
(`prepare-assets.py` and its emit-script imports) import no network
module. The bundle contents were re-checked against the packaging
manifests (`tools_pc/bundle-win.sh` / `bundle-linux.sh` — the scripts CI
runs): an explicit allowlist of engine, runtime DLLs, SDL2, licenses and
converter tools, with a hard-fail guard against a ROM image or oversized
blob sneaking in. The v0.5.0 artifacts themselves were not re-unpacked
locally; they are built by the same scripts. The full engineering record
behind each item is in the project's finding log
([`docs/dev/findings.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/docs/dev/findings.md)).
## What a release actually installs
Each release (`goldeneye-pc-port-*-win64.zip` / `-linux-x86_64.tar.gz`)
contains, and only contains: the game engine executable, a fixed set of
standard runtime libraries (SDL2, zlib, and the MinGW/Linux runtime — no
third-party downloads), the one-time ROM-to-PC asset converter, a README,
and license texts. The build scripts hard-fail if a ROM image or an
oversized blob ends up in the bundle. **No ROM, no game assets (textures,
audio, models, levels, text) are ever shipped** — you supply your own
legally-owned copy.
At runtime, the engine:
- has **no networking of any kind** (no sockets, no HTTP, checked directly
against the source),
- has **no telemetry, crash reporting, or analytics** of any kind,
- **never touches the Windows registry** and **never requests elevated
permissions**,
- writes save data, config, and derived ROM assets only inside its own
folder — never to `%APPDATA%`, `Program Files`, or any system location.
The one-time asset converter (`ge007-convert` / `prepare-assets.py`) — the
part of the bundle most likely to draw suspicion, since it's the thing that
reads your ROM and writes new files — has no network access at all,
verifies your ROM against a fixed table of known retail GoldenEye 007
hashes before touching it (an unrecognized file is rejected outright), and
writes only inside the bundle folder. Its full source ships right next to
the compiled version in every release if you'd like to read it yourself.
The engine starts it automatically on the first run, when the two derived
asset folders (`data/pcmodels-*`, `data/pccg-*`) are missing, passing it
the ROM it found and the output folder; after that first run it is not
launched again.
See [`SECURITY.md`](https://github.com/jkdansereau/goldeneye-pc-port/blob/main/.github/SECURITY.md) for why the binaries are
unsigned and what that means in practice (a SmartScreen prompt on first
run, and why some antivirus engines flag the converter specifically).
## Building from source
Cloning and building pulls in only standard, well-known packages: MSYS2
`pacman` packages on Windows, `apt` packages on Linux — no `npm`, no
`cargo`, nothing downloaded at CMake configure time, no git submodules, and
no prebuilt binaries checked into the repository. The CI build freezes the
release's asset-converter tool with `pyinstaller`, which is pinned to an
exact version, and every third-party GitHub Action the workflows use is
pinned to a full commit SHA (both from the release after v0.4.0; earlier
releases installed an unpinned `pyinstaller`). What PyInstaller packages
is in-repo, stdlib-only Python — a release is reproducible from this
repository alone.
One development-only backdoor exists in source builds: the `GE_DEBUG_UNLOCKALL`
environment variable (`src/game/file2.c`) pre-unlocks all cheat options at boot.
It is off unless explicitly set, changes no shipped behavior, and is documented
here so the env-var surface stays fully accounted for.
+2
View File
@@ -1,6 +1,8 @@
--- ---
title: The asset pipeline title: The asset pipeline
description: How the GoldenEye 007 PC port turns N64 ROM assets into the model and graphics files it loads at runtime. description: How the GoldenEye 007 PC port turns N64 ROM assets into the model and graphics files it loads at runtime.
date: '2026-10-05'
modified_time: '2026-10-05'
--- ---
## The asset pipeline ## The asset pipeline
+2
View File
@@ -1,6 +1,8 @@
--- ---
title: The software RSP title: The software RSP
description: How the GoldenEye 007 PC port emulates the N64's Reality Signal Processor (the graphics coprocessor) in software and bypasses the RDP. description: How the GoldenEye 007 PC port emulates the N64's Reality Signal Processor (the graphics coprocessor) in software and bypasses the RDP.
date: '2026-10-05'
modified_time: '2026-10-05'
--- ---
## The software RSP ## The software RSP
+2 -2
View File
@@ -2057,9 +2057,9 @@ static void d526_note_emit(uint32_t f, struct LoadedVertex* const* v_arr, int us
ok = 1; ok = 1;
} }
if (!ok) return; if (!ok) return;
if (d526_box_on) if (d526_box_on) {
if (mxx < d526_box[0] || mnx > d526_box[2] || mxy < d526_box[1] || mny > d526_box[3]) return; if (mxx < d526_box[0] || mnx > d526_box[2] || mxy < d526_box[1] || mny > d526_box[3]) return;
else if (mxx < -1.05f || mnx > 1.05f || mxy < -1.05f || mny > 1.05f) return; // off-screen } else if (mxx < -1.05f || mnx > 1.05f || mxy < -1.05f || mny > 1.05f) return; // off-screen
d526_sig_total++; d526_sig_total++;
int found = 0; int found = 0;
for (int i = 0; i < d526_nsigs; i++) { for (int i = 0; i < d526_nsigs; i++) {
+1 -1
View File
@@ -48,7 +48,7 @@ param(
[switch]$Dump, # GE_AUDIODUMP=1 -> audiodump.raw [switch]$Dump, # GE_AUDIODUMP=1 -> audiodump.raw
[switch]$VoiceDump, # GE_VOICEDUMP=1 -> voicedump.raw (per-voice, D202/M-67) [switch]$VoiceDump, # GE_VOICEDUMP=1 -> voicedump.raw (per-voice, D202/M-67)
[switch]$MixerTrace, # GE_MIXERTRACE=1 -- SLOW, see warning below [switch]$MixerTrace, # GE_MIXERTRACE=1 -- SLOW, see warning below
# (the -AB/-Old A/B switches were removed 2026-10-07, D532: GE_D204_OLD no # (the -AB/-Old A/B switches were removed 2026-10-05, D532: GE_D204_OLD no
# longer exists in the game, so they were documented no-ops) # longer exists in the game, so they were documented no-ops)
# Plumbing # Plumbing
+5 -1
View File
@@ -54,7 +54,11 @@ cleanup() {
if [ "$EEP_HAD" = 1 ]; then cp "$EEP_ORIG" "$EEP" 2>/dev/null; else rm -f "$EEP" 2>/dev/null; fi if [ "$EEP_HAD" = 1 ]; then cp "$EEP_ORIG" "$EEP" 2>/dev/null; else rm -f "$EEP" 2>/dev/null; fi
rm -f "$INI_ORIG" "$EEP_ORIG" 2>/dev/null rm -f "$INI_ORIG" "$EEP_ORIG" 2>/dev/null
} }
trap cleanup EXIT INT TERM # D534: restore on EXIT only; INT/TERM just exit (which fires EXIT), so an
# interrupted capture cannot continue past the restore with the snapshot gone.
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
# recipe comes from the tracked gate tool, not from this file # recipe comes from the tracked gate tool, not from this file
eval "$(grep -m1 '^GOLDEN_DUMP=' "$VSH")" eval "$(grep -m1 '^GOLDEN_DUMP=' "$VSH")"
+4 -4
View File
@@ -24,13 +24,13 @@ and per platform (`win`, and `linux` — 21 levels x 3 frames on each, captured
D523, **superseded by D529**): the frame depends on the save's **content**, not D523, **superseded by D529**): the frame depends on the save's **content**, not
its presence — D523's "presence, not which save" claim (worst_cell 0.175625 on its presence — D523's "presence, not which save" claim (worst_cell 0.175625 on
each of the four candidate saves, 21.557% with none) was only ever measured on each of the four candidate saves, 21.557% with none) was only ever measured on
Archives, and the 2026-10-07 A/B refutes it (facility 177.47 scene-level on the Archives, and the 2026-10-05 A/B refutes it (facility 177.47 scene-level on the
2026-10-05 playtest save, 0.0-0.25 on every other candidate on disk). `verify.sh` 2026-10-05 playtest save, 0.0-0.25 on every other candidate on disk). `verify.sh`
and `capture_p7.sh` install the canonical eep the same way they pin the ini and `capture_p7.sh` install the canonical eep the same way they pin the ini
(snapshot the local file if any, install the canonical one, restore-or-remove on (snapshot the local file if any, install the canonical one, restore-or-remove on
exit), so the gate is reproducible on a fresh clone and in CI. A local playtest exit), so the gate is reproducible on a fresh clone and in CI. A local playtest
save is **never** the gate's input. The linux 63-frame set was re-captured save is **never** the gate's input. The linux 63-frame set was re-captured
on the box under the canonical eep 2026-10-07 (D531; the 2026-10-05 on the box under the canonical eep 2026-10-05 (D531; the 2026-10-05
re-round, D530, turned out to have run under the box-LOCAL save — the re-round, D530, turned out to have run under the box-LOCAL save — the
`capture_p7.sh` per-level re-pin bug, fixed in D531) and is valid. `capture_p7.sh` per-level re-pin bug, fixed in D531) and is valid.
- Every run ends via `GE_QUITFRAME` (orderly quit; never a hard kill, D344). - Every run ends via `GE_QUITFRAME` (orderly quit; never a hard kill, D344).
@@ -66,7 +66,7 @@ capture with the recipe above and replace `<level>/<platform>/*.png`.
## History ## History
- **D531 (2026-10-07):** `capture_p7.sh`'s D529 adaptation was incomplete — - **D531 (2026-10-05):** `capture_p7.sh`'s D529 adaptation was incomplete —
the per-level re-pin restored the pre-capture LOCAL save (D524-era line), the per-level re-pin restored the pre-capture LOCAL save (D524-era line),
silently overwriting D529's pre-loop canonical install, so the 2026-10-05 silently overwriting D529's pre-loop canonical install, so the 2026-10-05
box re-round (D530) ran under the box-local save, not the canonical one. box re-round (D530) ran under the box-local save, not the canonical one.
@@ -74,7 +74,7 @@ capture with the recipe above and replace `<level>/<platform>/*.png`.
and re-captured: fresh 21/21 box round, 63 frames committed, replacing the and re-captured: fresh 21/21 box round, 63 frames committed, replacing the
D530 set (47/63 frames differ — save content demonstrably moves the frames; D530 set (47/63 frames differ — save content demonstrably moves the frames;
16 byte-identical save-independent scenes). 16 byte-identical save-independent scenes).
- **D530 (2026-10-07, AMENDED BY D531):** the linux set was re-rounded on the - **D530 (2026-10-05, AMENDED BY D531):** the linux set was re-rounded on the
box (X220, tree `442eb2ff`; `~/p7-reround.log` hit `P7 re-round DONE` box (X220, tree `442eb2ff`; `~/p7-reround.log` hit `P7 re-round DONE`
2026-10-05 12:53 EDT, 21/21 rc=0) and committed, replacing the D525 2026-10-05 12:53 EDT, 21/21 rc=0) and committed, replacing the D525
cleared-eep set (51/63 frames differ; 12 save-independent scenes byte- cleared-eep set (51/63 frames differ; 12 save-independent scenes byte-
+15 -7
View File
@@ -112,7 +112,7 @@ while [ $# -gt 0 ]; do
--script) SCRIPT="$2"; USER_SCRIPT=1; shift 2 ;; --script) SCRIPT="$2"; USER_SCRIPT=1; shift 2 ;;
--against) AGAINST="$2"; shift 2 ;; --against) AGAINST="$2"; shift 2 ;;
--json) JSON=1; shift ;; --json) JSON=1; shift ;;
-h|--help) sed -n '2,32p' "$0"; exit 0 ;; -h|--help) sed -n '2,34p' "$0"; exit 0 ;;
*) POSARGS+=("$1"); shift ;; *) POSARGS+=("$1"); shift ;;
esac esac
done done
@@ -121,12 +121,12 @@ set -- "${POSARGS[@]:-}"
case "${1:-}" in case "${1:-}" in
sweep) MODE=sweep; shift; SWEEP_SUBSET="${*:-}" ;; sweep) MODE=sweep; shift; SWEEP_SUBSET="${*:-}" ;;
parity) MODE=parity; LEVEL_ARG="${2:-}"; shift 2 2>/dev/null || true ;; parity) MODE=parity; LEVEL_ARG="${2:-}"; shift 2 2>/dev/null || true ;;
-h) sed -n '2,32p' "$0"; exit 0 ;; -h) sed -n '2,34p' "$0"; exit 0 ;;
"") "")
# D529 never-do 4: a no-arg run must NEVER look like a green verdict. It # D529 never-do 4: a no-arg run must NEVER look like a green verdict. It
# prints the usage and exits NON-zero (2026-10-07: a no-arg pair was # prints the usage and exits NON-zero (2026-10-05: a no-arg pair was
# cited as a "double-green" 21/21 because it exited 0). # cited as a "double-green" 21/21 because it exited 0).
sed -n '2,32p' "$0" sed -n '2,34p' "$0"
echo "error: no mode given -- a sweep is 'verify.sh sweep', one level is 'verify.sh <level>' (never cite a no-arg run as a gate result; D529)" >&2 echo "error: no mode given -- a sweep is 'verify.sh sweep', one level is 'verify.sh <level>' (never cite a no-arg run as a gate result; D529)" >&2
exit 1 ;; exit 1 ;;
*) MODE=single; LEVEL_ARG="$1" ;; *) MODE=single; LEVEL_ARG="$1" ;;
@@ -257,14 +257,21 @@ pin_ini_640x480() {
restore_ini() { restore_ini() {
if [ -n "$INI_BAK" ]; then cp "$INI_BAK" "$INI" && rm -f "$INI_BAK" if [ -n "$INI_BAK" ]; then cp "$INI_BAK" "$INI" && rm -f "$INI_BAK"
elif [ "$INI_CREATED" = 1 ]; then rm -f "$INI"; fi elif [ "$INI_CREATED" = 1 ]; then rm -f "$INI"; fi
INI_BAK=""; INI_CREATED=0
} }
trap 'restore_ini; restore_eep; kill_ours' EXIT INT TERM # D534: restore on EXIT only; INT/TERM just exit (which fires EXIT). A combined
# `EXIT INT TERM` trap restored on Ctrl-C and then let the sweep CONTINUE --
# the next level's pin re-installed the canonical save with the snapshot
# already deleted, so the user's own ge007.eep was left replaced on disk.
trap 'restore_ini; restore_eep; kill_ours' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
# --- save pin (D523, SUPERSEDED by D529): the goldens were captured with a # --- save pin (D523, SUPERSEDED by D529): the goldens were captured with a
# save file PRESENT. D529 (2026-10-07 A/B) proved the frame depends on the # save file PRESENT. D529 (2026-10-05 A/B) proved the frame depends on the
# save's CONTENT, not just its presence -- D523's "presence, not which # save's CONTENT, not just its presence -- D523's "presence, not which
# save" claim had only been measured on Archives (worst_cell 0.175625 on # save" claim had only been measured on Archives (worst_cell 0.175625 on
# each of the four candidate saves, 21.557% with none), and the 2026-10-07 # each of the four candidate saves, 21.557% with none), and the 2026-10-05
# sweep (facility 177.47 scene-level on the local playtest save vs 0.0-0.25 # sweep (facility 177.47 scene-level on the local playtest save vs 0.0-0.25
# on every other candidate on disk) refutes it. The gate now INSTALLS THE # on every other candidate on disk) refutes it. The gate now INSTALLS THE
# CANONICAL SAVE (tools_pc/golden/ge007.eep, 2 KB, in-tree so a fresh # CANONICAL SAVE (tools_pc/golden/ge007.eep, 2 KB, in-tree so a fresh
@@ -291,6 +298,7 @@ restore_eep() {
[ -n "$EEP_PIN_BAK" ] || return 0 [ -n "$EEP_PIN_BAK" ] || return 0
if [ "$EEP_PIN_HAD" = 1 ]; then cp "$EEP_PIN_BAK" "$EEP_PIN"; else rm -f "$EEP_PIN"; fi if [ "$EEP_PIN_HAD" = 1 ]; then cp "$EEP_PIN_BAK" "$EEP_PIN"; else rm -f "$EEP_PIN"; fi
rm -f "$EEP_PIN_BAK" rm -f "$EEP_PIN_BAK"
EEP_PIN_BAK=""; EEP_PIN_HAD=0
} }
# --- run one level -> sets globals: R_STATUS R_FRAMES R_SYM R_BRIEF ------- # --- run one level -> sets globals: R_STATUS R_FRAMES R_SYM R_BRIEF -------