chore(release): RunicNPC cutover for the 2026-11-05 wipe, Rust 547616323393184824 #29

Merged
whitlocktech merged 13 commits from edge into main 2026-11-06 08:13:38 -06:00

13 Commits

Author SHA1 Message Date
761a9b6733 Merge pull request 'fix(cutover): gate 1 asks Steam when public was set (D397)' (#28) from fix/cutover-public-gate into edge
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 41s
Reviewed-on: #28
2026-11-06 10:44:09 +00:00
e5548472da fix(cutover): gate 1 asks Steam when public was set, not the manifest's date or staging (D332)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 29s
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
2026-11-06 04:37:50 -06:00
fa606e5a01 Merge pull request 'ci(cutover): the wipe-day edge → main cutover, once five gates pass (D332)' (#25) from feat/auto-cutover into edge
Reviewed-on: #25
2026-11-02 15:38:25 +00:00
29226ab450 ci(cutover): no Closes listed twice, room for the worst case, the checkout pinned (D332)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 14s
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
2026-11-02 07:08:47 -06:00
512efa77cb ci(cutover): the wipe-day edge → main cutover, once five gates pass (D332)
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
2026-11-02 06:15:16 -06:00
1374891251 Merge pull request 'fix(kit): kit extras found by item definition; stage 5 pairs in sight (#20, #22)' (#24) from fix/kit-extras-belt-only into edge
Reviewed-on: #24
2026-11-02 11:46:19 +00:00
df2a258f64 fix(drill): stage 5's pairs stand in each other's sight; say how the leashed NPC came to fight (#20, #22)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 31s
s5.fight.shootBack failed on every staging drill run because, on the drill's
3500 map (seed 1234), a cliff rock (cliff_hills_large_e_arid) stands between
the fifth fight's victim and the bully 15 m north of it: the bully never saw
the victim, so never shot it. In the open the victim answers within a second.
Each fight's second NPC now stands where each one's eyes see the other's
centre, both ways, as RunicNPC's own line of sight runs: north first, then the
other seven ways round, with a note when it moves.

s5.fight.leash failed once (run 49) and did not come back in three tries. The
first moment the leashed NPC has a target, the harness now notes the target,
its health, and how far it and the scientist are from its home, so the next
failing run says whether it sensed, was shot, or heard an alarm.

Harness 0.7.5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-11-02 04:24:15 -06:00
5c3a360b70 fix(kit): find a kit's extra by its item definition when it has no held entity (#20)
Rust's November 2026 build (staging 26344826) adds the server variable
ItemModEntity.playerOnlyEntityBeltOnly, on by default: an item Rust marks
player-only, the medical syringe among them, has a held entity only while it
is in the belt. A kit puts its syringes in the main inventory, so the heal
(D260) found no item whose held entity is a MedicalTool and never healed
(s5.kit.heal on the staging drill: heals 0, health 75).

FindHeld now asks the item definition's entity prefab when an item has no
held entity, for every extra (heal, melee, flamethrower, grenade, rocket),
and HasFuel reads the flamethrower's fuel type the same way. Holding the item
moves it to the belt, where Rust makes its entity. A heal that cannot hold the
item (a full belt) is now no heal, not a heal of an item never held (D331).

On rust-staging: s5.kit.heal PASS, heals 2, syringes left 0, health 145.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-11-02 04:24:14 -06:00
a43e5c299f Merge pull request 'fix(drill): staging 26341433's swap fields, a harness that finishes, a drill rig that starts fresh (#20, #22)' (#23) from fix/staging-drill-20 into edge
Reviewed-on: #23
2026-11-01 08:18:20 +00:00
cf3997bbce fix(drill): place spots found up to 15 m from the navmesh; count only this run's Oxide errors (#22)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in 1m28s
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
2026-11-01 02:15:18 -06:00
4fb935d9dd fix(drill): lay the harness's kit down before boot instead of reloading Kits (#22)
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
2026-11-01 01:50:19 -06:00
54fb1ece67 ci(pr-checks): run the staging drill's tests (#20)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-11-01 01:35:45 -06:00
bad19a668d fix(drill): staging 26341433's swap fields; a failed group no longer ends the harness (#20)
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
2026-11-01 01:30:10 -06:00