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
This commit is contained in:
@@ -65,3 +65,23 @@ test("Kits' file is replaced, not deleted, by one holding only the harness's kit
|
||||
assert.equal(kits.rnhrevolver.IsHidden, true)
|
||||
assert.deepEqual(kits.rnhrevolver.BeltItems.map((i) => i.Shortname), ['pistol.revolver'])
|
||||
})
|
||||
|
||||
test('report keeps the state keys it does not own (the cutover, D332) and writes its own', async () => {
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const { report } = require('./drill.js')
|
||||
delete process.env.GITHUB_STEP_SUMMARY
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'drill-report-'))
|
||||
const cutover = { wipe: '2026-11-05', manifest: '1', gates: { public: { at: '2026-11-05T17:11:00.000Z' } }, pr: 7 }
|
||||
fs.writeFileSync(path.join(dir, 'drill.json'), JSON.stringify({ cutover }))
|
||||
const stat = { branch: 'staging', manifest: '42', manifestDate: '10/31/2026 11:48:58', managed: 'ok', oxideBehind: 0, fields: 'same', compile: 'ok' }
|
||||
fs.writeFileSync(path.join(dir, 'static.json'), JSON.stringify(stat))
|
||||
fs.writeFileSync(path.join(dir, 'live.json'), JSON.stringify({ branch: 'staging', ran: true, findings: [], harness: { done: true, pass: 3, fail: 0, failed: [] } }))
|
||||
await report({ state: path.join(dir, 'drill.json'), work: dir })
|
||||
const after = JSON.parse(fs.readFileSync(path.join(dir, 'drill.json'), 'utf8'))
|
||||
assert.deepEqual(after.cutover, cutover)
|
||||
assert.equal(after.checked.manifest, '42')
|
||||
assert.equal(after.lastRun.outcome, 'pass')
|
||||
fs.rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user