Worker w-savestructure-a1; task savestructure; research/implement.
Read .agent-cache/WORKER.md. Bus: python "%USERPROFILE%/.claude/skills/agent-cache-orchestrator/scripts/acbus.py"
Parallel: w-texdbkey-a1, w-cvartable-a1, w-idclwriter-a1. The other master (codex/Astra) owned the earlier save work and is at its host session limit.
Objective
Find, offline, why an edited Wolfenstein II savegame is rejected as "File Corrupt" - and fix the candidate so it is structurally correct.
These are the user's own single-player saves on their own machine. The task is a file-format one, and the search space is now small.
What is established - this is why the task is tractable now
re_probes/agent_reports/saveverify.md read the load path out of the runtime image and pinned SAVEGAME_E_CORRUPTED (the "File Corrupt" message) to exactly three set sites, all AFTER the .verify check:
(a) 0x8b47c4 Read(body) != Length - 4 (b) 0x8b4831 MD5_BlockChecksum(body) != be32(4-byte head) (c) 0x8b462d only for encrypted *.bin
.verify does NOT block loading: a mismatch only sets a flag that prints "Loading Dev Mode or corrupted save game" and loading continues. So the sidecars can stay untouched.
The master then checked (b) offline over BOTH existing candidates, v2 and v3:
every .dat passes - checkpoint.dat, checkpoint_alt.dat, checkpoint_mapstart.dat, game_duration.dat, level_duration.dat, level_duration_alt.dat, head == fold everywhere. (game.details is plain ASCII with no 4-byte head; (b) does not apply to it, it carries the separate CRC32 over sorted key/value bytes, already solved.)
v2 was rejected at runtime with a clean (b). Therefore the cause is (a): the deserializer consumes a different number of bytes than the file provides.
Concrete lead: checkpoint.dat grew 476224 -> 476231 bytes when the map path went from game/dlc/c02/c2v1 (0x11) to game/dlc/c02/c2v1_custom (0x18). Something else in the stream very likely still carries the OLD total - a section length, a block size, a trailing offset table, or a count of bytes that was written before the rename. Find it.
Sources / starting points
- Originals, READ ONLY:
re_probes/save_backups/SLOT0_before_c2customandSLOT2_before_c2custom(14 files each). - Candidates, READ ONLY:
re_probes/custom_save_candidates/FC2-WOLF0-c2v1_custom(v1),*_v2,*_v3. v3 is the newest and has the details CRC and the length prefixes repaired. - tools/savehash.py (the MD5-fold head), tools/probe_savegame.py, tools/probe_saveverify.py (
struktursubcommand), docs/spielstaende.md. All read-only for you. re_probes/agent_reports/{saveverify,custom_save_registration,save_integrity_v3}.md- The method that works: diff the ORIGINAL against the CANDIDATE byte by byte and account for EVERY difference. There are only a handful. One of them, or one thing that did NOT change and should have, is the bug.
- If you need the serialization grammar,
re_probes/runtime_87400/module.binis the read-only capture of the running, unpacked executable (virtual RVA layout, file offset == RVA, sections in manifest.json); the deserializer around 0x8b3f40-0x8b4900 is mapped in saveverify.md. capstone 5.0.7 is vendored: PYTHONPATH=re_probes/python_deps.
Ownership
tools/probe_save_structure.py (new), re_probes/save_structure/ (new dir, your corrected candidate goes here as a full copy), re_probes/agent_reports/savestructure.md.
Do NOT modify re_probes/custom_save_candidates/ or re_probes/save_backups/ - they belong to the other master and the backups are the user's only copy of their real saves. Read them, write your own copy.
Forbidden / do not touch
Never write to "%USERPROFILE%/Saved Games" or the Steam install. No game
launch, no process attach. Do not touch tools/build_custom_save_candidate.py,
tools/probe_details_checksum.py, tools/verify_custom_save_candidate.py,
tools/probe_saveverify.py, tools/savehash.py, or any other worker's files;
no docs/, no wolfsdk/, no config.json. No pip install.
Do not touch any *.bin in a candidate - profile/progression .bin are
encrypted with a key derived from a runtime user value and must stay as they are.
Hard constraints
Python 3.11, stdlib plus vendored capstone. Reproducible from the command line, no running game required.
Acceptance criteria
- A named, located structural defect: file, byte offset, what it says, what it should say, and why. Not "probably a length field somewhere".
- A corrected candidate under re_probes/save_structure/ where, demonstrably:
every
.datsatisfies branch (b); the map/layer strings are consistent in checkpoint.dat, checkpoint_mapstart.dat and game.details; the.verifyfiles are copied unchanged; and the byte count the deserializer would consume matches Length-4 by your own parse. - A parser that can state, for a given
.dat, how many bytes the deserializer consumes - because that is the only way to check branch (a) offline. - Negative control: your checker must REJECT the v2 candidate (known rejected at runtime) and ACCEPT the untouched original. If it accepts both, it does not measure anything.
Verification expectations
Every important assurance needs a check that fails if it is false. Be careful with one thing in particular: you cannot observe "File Corrupt" offline, so do not claim the candidate is now loadable. The honest claim is "structurally consistent by these checks, runtime unconfirmed". The runtime test needs the user's PC and is not available.
Failure honesty
If the serialization does not yield a definite answer, the valuable deliverable is the offline branch-(a) checker plus the exact list of unaccounted-for differences. A clean negative beats a plausible story. Say which hypotheses died.
Coordination / deliverable
Checkpoint at milestones. Publish a bus fact when the defect is located - the other master's save task is parked on exactly this question. Concise German report in re_probes/agent_reports/savestructure.md. Finish the bus task.