Skip to content
Back to skills

Version Adoption

ASecurity

Scouting a RomM or RetroBat prerelease and adopting a stable, the two tracks that move RomMBat's supported version. Use when an `upstream` tracking issue is open, when running /upstream, or when touching RomMServerVersion, RetroBatVersion, the pinned OpenAPI schema or reference/refresh.sh.

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added October 15, 2026
documentationpythongogitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 15, 2026

npx -y skills add Spinnich/rommbat --skill version-adoption --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Version Adoption?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Version Adoption
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/spinnich-version-adoption/badge)](https://www.skillsdirectory.com/skills/spinnich-version-adoption)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: version-adoption
description: Scouting a RomM or RetroBat prerelease and adopting a stable, the two tracks that move RomMBat's supported version. Use when an `upstream` tracking issue is open, when running /upstream, or when touching RomMServerVersion, RetroBatVersion, the pinned OpenAPI schema or reference/refresh.sh.
---

# Version adoption

RomMBat's floor is the newest **stable** RomM and RetroBat, adopted within one RomMBat release of
upstream shipping it ([version compatibility](../../../docs/design/version-compatibility.md),
[decision](../../../docs/design/decisions/stable-only-floor.md)). An upstream prerelease never
becomes the floor. It gets a scout pass, so that by the time its stable ships the work adoption
owes is already known and mostly landed.

| Upstream ships | Track     | Moves a number | Ends in                                                           |
| -------------- | --------- | -------------- | ----------------------------------------------------------------- |
| A prerelease   | **Scout** | Never          | A findings comment on the tracking issue, and issues for the code |
| A stable       | **Adopt** | The floor      | One PR that moves the floor and closes the tracking issue         |

Both run through `/upstream <romm|retrobat> [tag]`, which picks the track from the tag. How to
read a delta, and the traps in it, is in [delta.md](delta.md).

## The tracking issue

`tools/upstream_watch.py`, run daily by `.github/workflows/upstream-watch.yml`, keeps one issue per
upstream version line above the floor, labeled `upstream` and titled
`<RomM|RetroBat> <major>.<minor>: scout and adopt`. It owns the releases table between its markers
and comments when a tag appears. Everything else in the issue is the pass's:

- **One findings comment per scouted tag**, edited in place when the same tag is scouted again.
  A newer prerelease gets a new comment that says which earlier findings still hold at it.
- The adoption PR says `Fixes #<n>`. A line whose stable ships while a scout is open goes straight
  to adoption, and the scout's findings become its starting list.
- The watch respects a closed issue until upstream ships a tag the issue does not list.

## Scout: a prerelease

Nothing a scout does may move the floor, `LastTested`, the pinned schema, a `Verified:` stamp, the
compatibility table or a certification record. Those describe the builds RomMBat supports, and a
prerelease is not one. A test asserts the floor and the tested row carry no prerelease suffix.

1. **Pick the target**: the newest prerelease of the line when the work starts. Check again
   before posting, because prereleases supersede each other in hours (delta.md).
2. **Read the delta** from the floor tag to the target, from the trees and not the compare
   endpoint (delta.md, "Reading a delta"). Keep the paths RomMBat depends on. Drop the features
   `version-compatibility.md` lists as never reaching a local install.
3. **Refresh into scratch**: `reference/refresh.sh --ref <project>=<tag> --out <scratchpad>/scout`.
   It runs `verify.py` and both generators' `--check` against the scratch copy and leaves
   `reference/` and `data/` alone. Each drift is a finding: name the docs that cite the number,
   and the generator adoption will run.
4. **RomM: diff the schema.** Read `SYSTEM.VERSION` from the disposable instance's
   `/api/heartbeat`. If it is the target, pull `/openapi.json` into scratch and diff it against
   the pin. Name every path and field the generated DTOs or `RomM.Client` use that moved, then
   run the live tests against that instance. If it is not the target, the schema and the live
   behavior are unproven, and the findings say so; the maintainer owns that instance, so never
   upgrade it yourself.
5. **Preview the re-check list**: `python3 tools/docs/check.py --stale --floor <project>=<core>`,
   with the version less its suffix (`5.4.0`), lists the facts adoption will classify, and the
   delta you have just read says which of them it will owe a measurement. Read every entry
   in `docs/upstream/issues.md` against the delta: an upstream fix is noted, never acted on.
6. **RetroBat: smoke the scout tree.** Rebuild `ROMMBAT_SCOUT_ROOT` from
   `./tools/retrobat-install.ps1 -Version <tag>` as `tools/handson/README.md`, "The scout tree",
   says, then `Use-ScoutTree` and run the agent tree's build steps on it with a small set.
   - The startup check warns that the version is newer than tested, and does not refuse.
   - Step 9: a second sync is a no-op, with no gamelist churn and no re-download.
   - Boot each row whose inputs moved (its `es_savestates.cfg` entry, its `<extension>` list, its
     BIOS md5 set, its emulator binary) through `emulatorLauncher` and record what it wrote.
     Nobody plays: a save that needs a pad is a row adoption owes.
   - `Use-AgentTree` when done.
7. **Draft the mapping.** Against each record in `docs/platforms/`, list the nine steps the move
   would touch (`platform-certification`, "When the floor moves"). It goes in the findings, not
   the records, and adoption starts from it.
8. **Post and file.** The findings comment names the target, what was read, measured and left
   unproven, and each finding. A finding that needs code becomes its own issue, citing the
   tracking issue, through `/start-issue`.

### A scout fix

It lands on main and must be **correct on both builds**: the floor's tests stay green, and where
the two behave differently the code branches on `RomMServerVersion` or `RetroBatVersion` read at
runtime, with a test per side. An upstream fact it relies on is stamped with the prerelease it was
measured on, and the adoption re-stamps it on the stable. A change only the prerelease can justify
(a field the floor's server does not send, a folder the floor's tree does not have) waits for
adoption. Gating it is still a branch nobody running the floor can reach.

## Adopt: a stable

A version move is not a find-and-replace: some numbers here are the **current** supported version
and must move, and some are the version a measurement was taken on and must not. Work in order.

1. `reference/refresh.sh --ref <project>=<stable tag>`, into `reference/`. Resolve every drift it
   reports rather than editing the expected number. A drift is a signal to revisit the docs that
   cite it. Run the generator it names and review that diff.
2. Move together, or the startup check disagrees with the README: `RetroBatVersion.Minimum`,
   `RetroBatVersion.LastTested`, `RetroBatRoot.MinimumVersion`, the `README.md` requirements
   table, and the guide's `wiki/getting-started/requirements.md`. A test asserts the first three
   agree. The guide's compatibility table, `wiki/reference/compatibility.md`, is left alone: each
   row records what a release was tested against, and the next release's row is added when it is
   cut (`DEVELOPER_SETUP.md`, "Cutting a release").
3. `python3 tools/docs/check.py --stale` then lists the facts to classify: every fact whose
   `Verified:` stamp names a build below the new floor, and every fact with no stamp. It reads
   the floor from `RetroBatVersion.Minimum` and `RomMServerVersion.Minimum`, so run it once the
   floor being moved is in code: step 2 for RetroBat, step 6 for RomM. **Classify each against the
   delta** (delta.md, "Which facts a delta touches"). A touched fact is re-measured and
   restamped, or deleted with its citations when it stopped being true. An untouched one is
   carried, with a `Carried:` clause giving the reason
   ([decision](../../../docs/design/decisions/delta-directed-recheck.md)). A fact with no stamp
   has no build to carry from and is measured. Read the upstream changelog end to end as well,
   for behavior no fact records yet.
4. Re-check every entry in `docs/upstream/issues.md`. A fix upstream changes what
   RomMBat should do; **no workaround comes out until a hands-on pass has seen the fixed
   behavior.** A changelog line is upstream's belief, not a measurement.
5. Leave provenance alone. `data/retrobat/*.json`'s `_retrobat_version`, and a live capture under
   `tests/.../fixtures/`, record the version something was **measured on**. Rewriting those to
   the new number silently reattributes a measurement to a build nobody ran it against.
6. A RomM move also moves the pinned OpenAPI schema, which is the minimum version on purpose.
   `RomMServerVersion.Minimum`, `RomMServerVersion.LastTested` and the `info.version` inside the
   pinned file move in one commit, and a test reads the pin rather than restating it, so a pin
   that moves without the floor fails there. Capture it as delta.md, "Capturing the schema", says,
   and see `src/RomM.Client/openapi/README.md`.
7. Resolve every scout finding on the tracking issue: done, carried into this PR, or filed with
   its reason. Delete each version gate the new floor makes dead, with its floor-side test.
8. **Map the move onto every record in `docs/platforms/`.** The PR description marks the nine
   steps touched or carried, step 9 always touched, with a one-line reason for each carried
   step. Each record's "Where each row stands" then says which steps were re-run at the new
   floor and which are owed. The rule and what counts as touched are in the
   `platform-certification` skill, "When the floor moves". For RetroBat, rebuild the agent tree
   from a pristine install of the new stable first (`tools/handson/README.md`, "The agent tree").

The PR takes `semver:minor` ([versioning](../../../docs/design/decisions/versioning.md)), closes
the tracking issue, and runs `/drive-pr`.

Files in this skill

  • SKILL.md9.4 KB
  • delta.md4.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.