Skip to content

Test the raid flow for real, and fix what that turned up - #202

Merged
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3
Jul 30, 2026
Merged

Test the raid flow for real, and fix what that turned up#202
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3

Conversation

@0xward

@0xward 0xward commented Jul 30, 2026

Copy link
Copy Markdown
Owner

You asked why I wasn't testing this myself with Playwright. Fair question — the repo already has the pattern (scripts/test-bunker-floor-reset.js boots the app in headless Chromium and reads the saved draft back), and everything I'd verified about raids so far came from reading code and exercising logic in isolation.

So this drives the real map in a real browser.

What the test does

Seeds a player midway through Bunker 3 on floor 3, then:

✓ daily bar renders three chips          ✓ craft chip counts down (⏳2h 15m)
✓ fragment chip shows 7/12 (◈7/12)       ✓ energy chip shows 4 (⚡4)
✓ five bunker nodes on the map           ✓ bunkers 1 and 2 carry a ✓
✓ a cleared bunker offers RAID (RAID ▸)  ✓ and says it costs energy
✓ tapping RAID stashes the campaign position
✓ campaign act is restored, not left at the raided bunker
✓ campaign FLOOR is restored (depth 3)   ✓ maxDepthReached restored
✓ the raid KEEPS what it earned (xp 1400)  ✓ and the loot it picked up
✓ the stash is consumed
✓ high-water mark still 2 after raiding bunker 1

Kept as npm run test:raid.

It earned its keep twice

1. A real leak. takeCampaignResume was called inside the if (raw) guard, so any path where the engine had no snapshot to give — never mounted, already torn down, getSaveSnapshot threw — left the stash on disk. A leaked stash is not inert: the next raid to finish would read it and restore a campaign position from two raids ago.

It is now consumed first and unconditionally, which is also the correct outcome on that path — no snapshot written means the draft still holds the position the stash was insurance for.

2. Its own first run was a false green. With no engine mounted the whole write block was skipped, so three assertions about the campaign being "restored" passed against the untouched seeded draft. A tracer on the resume key showed one write and no removal — which is what exposed both the leak and the vacuous pass.

The engine stub and the raid KEEPS what it earned assertion exist so that cannot repeat: that one can only pass if the raid's own snapshot really was written.

I'm flagging this because I reported those three assertions as passing in a previous message before spotting it. They weren't proving anything then. They are now.

Limits, stated plainly

This drives the shell half. Playing five floors of real-time combat headlessly is not practical, so the engine's snapshot is stubbed — same technique as the existing test-bunker-floor-reset.js, which says the same thing about itself.

That is the right seam here: every one of the four hazards in this flow lives in the shell (GameFlowManager, WorldMapHub, campaignProgress), not the engine.

Still unproven and wanting a human: the engine actually reaching onActBunkerCleared in raid mode, and how the chips look on a real phone with the game's own fonts.

Verification

tsc --noEmit clean · lint 34 errors, unchanged from main · check:copy, audit pass · npm run test:raid 16/16.


Generated by Claude Code

Owner asked why I was not testing this myself with Playwright. Fair
question — the repo already has the pattern (test-bunker-floor-reset.js
boots the app in headless Chromium and reads the saved draft back), and
everything I had verified about raids so far came from reading code and
exercising logic in isolation.

So this drives the real map: seeds a player midway through Bunker 3 on
floor 3, waits for the world map, checks the daily status chips render
with live numbers, checks bunkers 1 and 2 carry a ✓, taps Treeline,
asserts the button reads RAID and the subline names the energy cost, taps
it, and asserts the campaign's act AND floor come back afterwards with
everything the raid earned kept.

It immediately earned its keep twice.

First, it caught a real leak. takeCampaignResume was called INSIDE the
`if (raw)` guard, so any path where the engine had no snapshot to give —
never mounted, already torn down, getSaveSnapshot threw — left the stash
on disk. A leaked stash is not inert: the next raid to finish would read
it and restore a campaign position from two raids ago. The stash is now
consumed first and unconditionally, which is also the right outcome on
that path, since no snapshot written means the draft still holds the
position the stash was insurance for.

Second, and worth writing down: its own first run was a FALSE GREEN. With
no engine mounted the whole write block was skipped, so three assertions
about the campaign being "restored" passed against the untouched seeded
draft. A tracer on the resume key showed one write and no removal, which
is what exposed both the leak and the vacuous pass. The engine stub and
the "raid keeps what it earned" assertion are there so that cannot repeat:
that one can only pass if the raid's own snapshot really was written.

Kept as npm run test:raid rather than thrown away. It does not prove the
engine half — playing five floors of real-time combat headlessly is not
practical — but the shell owns every hazard in this flow, and the shell is
what it drives.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nullstate Ready Ready Preview Jul 30, 2026 5:27pm

@0xward
0xward merged commit 33a2cc9 into main Jul 30, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant