Worker w-saveverify-a1; task saveverify; research (read-only RE). Read .agent-cache/WORKER.md. Bus: python "%USERPROFILE%/.claude/skills/agent-cache-orchestrator/scripts/acbus.py" Parallel workers: astra-save-v3 works the STRUCTURAL side of the same problem (save serialization, length prefixes, dictionary checksum) on another host. You work the CRYPTO/CODE side only. Do not touch its files. Its findings and yours must meet in the middle; publish facts rather than duplicating its work.
Objective
These are the user's own single-player save files on their own machine. The
question is a file-format one: how is a .verify sidecar produced, and does it
actually decide whether a save loads?
Measured and unexplained: a candidate save whose three data files were rewritten
consistently (map path in checkpoint.dat incl. its length prefix,
checkpoint_mapstart.dat, game.details, all DAT MD5-fold headers recomputed) is
still rejected at runtime as "File Corrupt", with all six .verify files left
at their retail values. Each .verify is exactly 40 bytes: 8 bytes that look
like a per-write nonce followed by 32 bytes of ciphertext.
Answer, from the code in the runtime image:
- What writes a
.verify, over what input, with which algorithm and key/derivation? - Does the LOAD path verify it? If yes, at which point and what happens on mismatch - is "File Corrupt" that path, or a different one?
- Therefore: is
.verifythe reason the candidate is rejected, or is the structural side (astra-save-v3's lane) the real cause? This is the single most valuable thing you can establish, in either direction.
Sources / starting points
- re_probes/runtime_87400/module.bin - read-only capture of the RUNNING, SteamStub-unpacked NewColossus_x64vk.exe. Layout "virtual RVA": file offset == RVA. Sections and image base in re_probes/runtime_87400/manifest.json. Decisive: the on-disk EXE is packed, this image is not.
- .pdata is a RUNTIME_FUNCTION table - use it for function boundaries instead of sweeping 31 MB of .text.
- Entry points that tend to work: the literal string ".verify" and the save file names ("checkpoint.dat", "game.details", "checkpoint_mapstart.dat") in .rdata, then xrefs into .text. From the writer, the algorithm is usually two or three calls away. Modern x86 AES shows up as AESENC/AESENCLAST/AESKEYGENASSIST instructions - scanning .text for those opcodes localizes the crypto fast, and their call sites lead to the key schedule.
- capstone 5.0.7 vendored: PYTHONPATH=re_probes/python_deps python ...
- Corpus, READ ONLY: re_probes/save_backups/SLOT0_before_c2custom and SLOT2_before_c2custom (14 files each, originals), the quarantined set re_probes/verify_quarantine_SLOT0_FC2, and the live tree under "%USERPROFILE%/Saved Games/MachineGames/Wolfenstein II The New Colossus" - READ ONLY, never write there.
- Prior work, read-only: re_probes/agent_reports/custom_save_registration.md, docs/spielstaende.md, tools/savehash.py (the DAT MD5-fold header).
Ownership
tools/probe_saveverify.py (new), re_probes/saveverify/ (new dir), re_probes/agent_reports/saveverify.md (new).
Forbidden / do not touch
Never write to "%USERPROFILE%/Saved Games" or the Steam install. No game launch, no process attach. Do not touch files owned by others: tools/build_custom_save_candidate.py, tools/probe_details_checksum.py, tools/verify_custom_save_candidate.py, re_probes/custom_save_candidates/, tools/probe_cmdtable.py, re_probes/cmdtable/, tools/probe_idclhash.py, re_probes/idclhash/, tools/vtpixel.py, docs/, wolfsdk/, config.json. No pip install.
Hard constraints
Python 3.11, stdlib plus vendored capstone. Reproducible from the command line. No running game required.
Acceptance criteria
- The writer and, if it exists, the reader identified by function RVA with the xref chain that leads there and the disassembly excerpt that shows the input.
- A clear verdict on question 3 with the evidence behind it.
- If the derivation is recovered: reproduce an EXISTING retail
.verifybyte-exactly from its data file. That is the only acceptable proof. Do it for at least three different files across both backup slots. Anything less is a hypothesis and must be labelled as one. - Negative control: your reproduction must FAIL on a deliberately altered data file. A routine that emits the expected 40 bytes regardless of input proves nothing.
- If the key is not statically recoverable (hardware-bound, Steam-derived, or generated at runtime), say so plainly and name what it depends on.
Verification expectations
Every important assurance needs a check that fails if the assurance is false. "An AES string exists in the binary" is not evidence of anything - the prior report already warns against exactly that inference. Distinguish: crypto code present / called on save write / verified on save load / rejection observable as "File Corrupt".
Failure honesty
A well-evidenced "the load path never reads .verify, so the structural side is the real cause" is an EXCELLENT result - it would redirect the other worker immediately. So is "key is runtime-derived, offline forging is impossible". Report failed hypotheses. Do not pad a negative into a maybe.
Coordination / deliverable
Checkpoint at milestones. Publish a bus fact the moment question 3 has an answer - astra-save-v3 is blocked behind exactly this. Concise German report in re_probes/agent_reports/saveverify.md. Finish the bus task when done.