diff --git a/docs/agents/review-bots.md b/docs/agents/review-bots.md index 013e4061..54433c34 100644 --- a/docs/agents/review-bots.md +++ b/docs/agents/review-bots.md @@ -32,5 +32,5 @@ - **AGY RE-FILES REFUTED FINDINGS EVERY ROUND, SO THE CEREMONY NEEDS A STOPPING RULE (2026-09-23, #545 / sibling #30 / #31).** Four rounds on three docs PRs. By round 4 the Antigravity reviewer was re-raising, sometimes as **BLOCKING**, claims already refuted with line numbers in rounds 1–3: "`$G` may be undefined" (`tb/regress.sh:28` defines it), "`$VERIFY` is unbound under `set -u`" (`tb/fetch-goldens.sh:123` defaults it, three times), and "TSV `#` lines crash the loop" (`:240` skips them). It re-reviews on every push and does not carry forward the rebuttals, so every fix push buys another round with the same claims in it. **Rule:** fix what is real, reply to everything with evidence, and when a round brings only repeats and nits, reply to them and merge on green rather than pushing again. Every push restarts CI (the `test-roms` job alone is tens of minutes) *and* the reviewer. The rounds still paid: they found an ADR consequence describing a rename that did not happen, a `BLARGG_DIR` default ignoring `GOLDEN_DIR` (and the same bug in `mutate_apu.sh`), and a sentence ("measured on the console") that read as a hardware claim. Declining is only safe after checking each claim, because the first "blocking" finding of a round is not always the repeat it looks like. - **COPILOT REVIEWS ONCE PER PR HERE, AND DOCS7 FLAGS THE PRIVATE SIBLING AS DEAD (2026-09-23).** On all three PRs Copilot posted a single review, on the first push, and never re-reviewed later pushes. So the merge gate can only check that it *has* posted, not that it reviewed the head; agy's comment timestamp is the per-push signal. Context7's **Docs7** bot (a `context7[bot]` issue comment plus a NEUTRAL check) link-checks changed files as an **anonymous** client. Every `https://github.com/doublegate/RustyNES_MiSTer/...` link is therefore reported dead, because that repository is **private** (`gh repo view --json visibility` returns `PRIVATE`). Those are correct links, not findings. Its other catch was real: two pre-existing links into `to-dos/` directories that had moved to `to-dos/archive/`. -- **CODERABBIT SKIPS A PR OVER 100 FILES; REVIEW IT AS SLICES, AND EXPECT CROSS-SLICE FALSE FINDINGS (v2.9.8, v3.0.0).** "Review skipped: 163 files exceed the limit of 100." Both MAJOR release PRs were reviewed as review-only slice PRs (`review/vX-{a,b}` from `main`, one path partition each, built with `git diff --binary -- | git apply --index`, and proved equal to the head on their paths with `git diff --quiet -- `). A slice does not build alone, so it is committed with `--no-verify` and says so. Keep the slices in sync on every release-branch push, and close them unmerged. The trap: a slice lacks the other half's changes. On #587 CodeRabbit rated Major that `rustynes-core` still built the now-`#[non_exhaustive]` `Cartridge` by literal; that change was in the other slice. Shown the release head's lines, it withdrew. It is also rate-limited hourly on this plan, so schedule the re-request rather than re-posting. **A slice is also RED in CI by construction (v3.0.1, #591)**: feature-gated tests that live in one slice and depend on the other (`holy_mapperel.rs`, the provenance audit reading files the other slice changes) fail there and nowhere else. Say so on the slice PR at once, with the named tests, and judge CI on the release PR only. +- **CODERABBIT SKIPS A PR OVER 100 FILES; REVIEW IT AS SLICES, AND EXPECT CROSS-SLICE FALSE FINDINGS (v2.9.8, v3.0.0).** "Review skipped: 163 files exceed the limit of 100." Both MAJOR release PRs were reviewed as review-only slice PRs (`review/vX-{a,b}` from `main`, one path partition each, built with `git diff --binary -- | git apply --index`, and proved equal to the head on their paths with `git diff --quiet -- `). A slice does not build alone, so it is committed with `--no-verify` and says so. Keep the slices in sync on every release-branch push, and close them unmerged. The trap: a slice lacks the other half's changes. On #587 CodeRabbit rated Major that `rustynes-core` still built the now-`#[non_exhaustive]` `Cartridge` by literal; that change was in the other slice. Shown the release head's lines, it withdrew. It is also rate-limited hourly on this plan, so schedule the re-request rather than re-posting. **A slice is also RED in CI by construction (v3.0.1, #591)**: feature-gated tests that live in one slice and depend on the other (`holy_mapperel.rs`, the provenance audit reading files the other slice changes) fail there and nowhere else. Say so on the slice PR at once, with the named tests, and judge CI on the release PR only. **Split CODE from DOCS and the slices pass the hooks (v3.1.0, #595 / #596).** Partitioned by extension (`.rs .toml .lock .wgsl .kts .yml .py` in one slice, everything else in the other), the code slice builds exactly as the release head does and the docs slice touches no Rust, so both were committed with the pre-commit hooks running and no `--no-verify`. Two things to keep: re-derive the partition from `git diff --name-only HEAD` on EVERY sync, because a newly touched path (v3.1.0's `release_notes_render_audit.rs`) is otherwise silently left out of both slices; and prove each slice equal to the head with `git diff --quiet -- ` after applying. CodeRabbit found real defects in both halves (two behaviour bugs in the code slice, a `LADDER-FILL` placeholder in the CHANGELOG in the docs slice). - **AGY'S BLOCKING FINDINGS CAN CITE CODE THAT DOES NOT EXIST (v3.0.0, #586).** One round filed a BLOCKING "state desync in `SpectatorSession::pop_frame`... `push_frame` relies on `relative_idx`"; none of the three exists in the spectator (`git grep` found only the movie attestation builder's `push_frame`). The same round cited `crates/rustynes-core/src/netplay.rs` and `scripts/bump_release.py`, neither of which exists. Another round called `let _ = socket.send_to(..)` a silent failure, against the module's documented contract and four sibling sends. agy edits ONE comment in place, so these sat in the folded "Earlier review rounds" block. `git grep` every cited symbol and `ls` every cited path before acting; refute with the command and the line numbers. diff --git a/docs/agents/tooling-traps.md b/docs/agents/tooling-traps.md index e67cd3a4..e5b44492 100644 --- a/docs/agents/tooling-traps.md +++ b/docs/agents/tooling-traps.md @@ -33,3 +33,5 @@ - **PARALLEL WORKTREE AGENTS NEED THE TIP'S MOVES TOLD TO THEM (v2.9.8).** Five agents worked from one base while their siblings' commits landed. Each time the branch moved (a rename, a removed API), the still-running agents were sent the new tip and the breaking facts and told to rebase before their final commit. Integration then needed only CHANGELOG and ADR conflict resolution. To relieve a loaded host, an agent can be paused at a safe point: let its current cargo job finish, write a status file, end its turn, and resume it later by message. - **`pgrep -f ` IN A WAIT LOOP MATCHES THE LOOP ITSELF (v3.0.1).** `until ! pgrep -f quartus_fit; do sleep 30; done` never ended: the pattern appears in the loop shell's own command line, so `pgrep` always finds one process. Three background loops stayed alive this way after the jobs they waited for had finished, and had to be stopped with TaskStop. Wait on a PID (`while kill -0 $pid`), on a file the job writes last, or use the bracket trick (`pgrep -f '[q]uartus_fit'`). The same mechanism is why `pkill -f` killed the tool shell (memory, and the trap below). - **A WORKTREE-ISOLATED AGENT CANNOT RUN GIT HERE, AND ITS WORKTREE STARTS FROM `main` (v3.0.1).** Two forks were given `isolation: worktree` on 2026-10-07. Both worktrees were created from `main` (`9c23715b`), not from the release branch the session was on. The first agent could still run git and reset its own clean worktree to the right commit. The second could not run git at all: the RTK hook rewrites every `git` into `rtk git`, and the worktree-isolation guard refuses a command that "runs rtk with a git command among its operands" (plain `git`, `git -C`, `command git` and `rtk git` were all refused). It made no change, and the harness removed the unchanged worktree itself. For documents-only work, run the fork in the main tree instead, stage by explicit path, and make no commits from the session until it reports. Otherwise, check the agent's first `git log` before trusting anything it writes. +- **`git show : > FILE` ON AN UNFETCHED TAG WRITES AN EMPTY FILE (v3.1.0).** The shell creates `FILE` before `git show` runs, so when the tag is not in the local repository (a release tag made on GitHub by Auto Release is not fetched by `git fetch origin main`), the command prints `fatal: invalid object name` and leaves a zero-byte file behind. Copied into the libretro-super fork, that was committed and pushed as a 38-line deletion of `rustynes_libretro.info` before the diff was read (caught before the PR, repaired by amend). Fetch the tag first (`git fetch origin tag vX.Y.Z`), and check `[ -s FILE ]` plus the `git diff --stat` before any commit built from a redirect. +- **`workflow_dispatch` RUNS ONLY A WORKFLOW THAT IS ON THE DEFAULT BRANCH (v3.1.0).** `gh workflow run ladder.yml --ref release/v3.1.0` returned HTTP 404 "workflow ladder.yml not found on the default branch" while the file existed on the release branch. A new dispatch-only workflow therefore cannot be exercised before its PR merges; its first run is after the merge, and the PR should say so rather than imply it was tested. diff --git a/docs/libretro/UPSTREAM_SYNC.md b/docs/libretro/UPSTREAM_SYNC.md index 81119718..3fd8fd5d 100644 --- a/docs/libretro/UPSTREAM_SYNC.md +++ b/docs/libretro/UPSTREAM_SYNC.md @@ -182,6 +182,16 @@ local `.info` again (its `display_version` will have moved), and re-check the hand-audited fields of the table above (`savestate`, `cheats`, firmware, the mapper count) against the crate. +## Sync for v3.1.0 (submitted 2026-10-08) + +The only difference between the core's `.info` and +upstream's was `display_version` (`v3.0.0`), measured by `diff` against +`dist/info/rustynes_libretro.info` on upstream `master`. The fork was synced and +[libretro/libretro-super#2134](https://github.com/libretro/libretro-super/pull/2134) +opened with that one line, copied from the `v3.1.0` tag. The docs page names no +version and no libretro-visible feature changed (the CPU overclock and the +sprite-limit option are not core options yet), so `libretro/docs` needs no PR. + ## Sync of 2026-08-20 (done) — measured against upstream `master` > **Done.** This sync merged upstream as libretro-super #2074 (2026-08-28, `display_version` v2.3.9) and docs #1180 (2026-08-22, the license); #2069 (2026-08-16) was the license correction before it. It is kept as the worked example of the procedure. The next sync is prepared at v2.9.9 and submitted at v3.0.0 (ADR 0043); its diff is measured fresh then, not read from here.