The 2026-11-05 weekend never cut over: gate 1 blocked every hourly run. Both of
its checks rested on assumptions the wipe disproved:
- The wipe build went live Thursday evening, but its depot manifest is dated
11-04: the date DepotDownloader prints is when Facepunch built it.
- Public never names staging's manifest. Facepunch promotes a hidden `release`
branch ("Release, before public"), and staging had moved on before the wipe.
Gate 1 now reads Steam's app info (steamcmd +app_info_print 258550, kept by
static.sh as appinfo.txt with BRANCH=public): branches.public.timeupdated must be
on the wipe day or later, and the Linux depot manifest Steam names for public
must be the one the static half downloaded. The staging static half is gone from
edge's cutover.yml; --staging-work is still accepted, since main's copy passes it
until the cutover merge carries the new wiring over.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014HJEmgsXtLR5kLfh7f9y8P
From the second review:
- A PR whose merge commit main already has is not listed again. edge's tip at
a cutover is often that PR's merge commit, and its merged_at can be a moment
after the cut-off's committer date, so its issues would have had the next
release's comment too.
- timeout-minutes 240: the worst case is about 200, and a timeout must never
cut off the step that starts rust-carbon again.
- A test pins the checkout: edge, except on a dry dispatch that names code_ref.
Dry run (CI run 54, before these): every gate refused for the right reason.
Public Rust is still the 22 October build, which lacks the three fields edge
carries for November, and gates 1 to 4 each saw it; the panel key wrote to,
restarted and read rust-carbon; the live half ran 266 pass, 0 fail; nothing
was opened, edited, commented or merged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
A workflow that merges edge into main on the forced-wipe weekend with no
approval: hourly from Thursday 17:00 UTC to Sunday 23:00 UTC, through five
gates in order, then a merge commit made with RUNICNPC_TOKEN (that step only)
so release.yml cuts the release.
1. Rust's public build changed: dated the wipe day and naming the same depot
manifest as staging (the staging build was promoted to live).
2. Oxide's public release caught up, RunicNPC compiles, the swap's fields match.
3. A Carbon boot on public Rust: rust-carbon proves the public manifest is
installed, and rnpc.status says framework carbon, navmesh ready,
missing=- added=-.
4. The drill's live half on public Rust with edge's plugin and harness.
5. PR checks, run fresh on the cutover PR's head just before the merge.
Gates are kept in drill.json for one (wipe, public manifest, edge commit);
any change runs them again. A failed Carbon or live attempt cools down for
3 hours. The merge is pinned to the commit the gates ran on. The cutover PR
lists every `Closes #N` from the PRs merged into edge since the last cutover,
so those issues close on the merge; afterwards each gets the release version.
One comment a day while a gate blocks; at the deadline it hands back.
The copy on main is only the trigger and step wiring; every step runs edge's
code (a dry dispatch may name another branch, code_ref). Dispatches are dry
unless dry_run is exactly false. rust-carbon is started again if the job left
it stopped. drill.js only gains exports; its report already kept other keys,
now tested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Run 49: place.set.each was refused "4.4 m from the navmesh", because
OnMesh searched 3 m and returned the unsnapped point; Place now searches
15 m. The drill reported run 48's four error lines again: oxideErrors
read the whole day's Oxide log, and now reads only what was added after
the drill started the rig.
Refs #20, #22
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Run 48 deleted Kits' file for a fresh start, and the harness's
rnhrevolver kit, added after boot with `oxide.reload Kits` through the
panel's command endpoint, never reached Kits: no reload or compile job
followed, and every test profile was refused for want of the kit.
The drill now replaces kits_data.json with one holding only that kit.
Kits reads it at boot; RunicNPC's first load adds its example kits
beside it (it skips kits already there) and settles its own Kits
reload (D329). The add-after-boot stays as a fallback, now through the
console's websocket, and is a finding when Kits does not load again.
Refs #20, #22
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
The staging drill's run 47 failed on Rust staging 26341433:
- Rust added BasePlayer.timeSinceAiming, BaseEntity.ServerPreProcessed and
BaseNetworkable.ignoreNetworkLod to the swap's field list (D232): 55 -> 58.
On edge now; main at the forced wipe of 2026-11-05.
- Harness 0.7.4: place.set.each was refused and the refusal was thrown
away; place.spawned failed; reading each[0] of an empty list then killed
the coroutine, so the drill waited 45 minutes for a run that had stopped
after 10. Place puts its spots on the navmesh, the set checks carry the
refusal, a failed place.spawned ends the group, and any group that throws
is a <group>.exception FAIL line and the run goes on.
- drill.js: rust-staging boots from empty Kits and RunicNPC data, so the
write-once example kits match this Rust (s6.examples.fullCondition); the
wait ends after 5 minutes without a new harness line; latest.log's tail
goes into the issue when the harness did not finish. drill.test.js
covers the stall logic.
Refs #20, #21
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
A Gitea job that checks each new Rust staging build in the seven days before the
monthly forced wipe:
- tools/drill/static.sh: staging's managed assemblies (DepotDownloader) and
Oxide's staging build; whether Oxide has caught up (fieldlist --oxide-behind),
the swap's field list compared, and the plugin compiled.
- tools/drill/drill.js: window (D318), gate (one check per depot manifest),
live (rust-staging runs rnt.run all; rust-carbon is stopped and restarted when
both 6000-map rigs run, D309) and report (one issue per build, state on the
drill branch; a build waits up to three days for Oxide, D317).
- tools/drill/rig-start.sh: the rig's startup; installs the branch and Oxide's
build for it, and refuses to start a mismatched pair.
- RunicNpcTest 0.7.2: stage 5's five fights look for a field with room for their
280 m line (D319), and the spawn check names what did not spawn.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY