Cassette Build Report 027 — The Transfer Checkpoint Was Not the Source Bytes
S10 made resumable transfer precise, then separated a completed checkpoint from proof that the source extent is still valid today.

Scope note: This report covers S10’s resumable, verified transfer and the review that followed it. It separates a checkpoint’s proof of a completed transfer from later proof of current bytes; physical cable pulls and power-loss behavior remain assigned to the hardware campaign.
S10 was the first Cassette step that made interruption part of the normal path. The source adapter could identify an immutable object and read one exact range. It could not yet move a multi-terabyte model across a failure without starting again, hiding a second copy on the Mac, or trusting a record that no longer matched the bytes it described.
The acceptance row was exact. Cassette would write fixed four-mebibyte chunks into store-granted cartridge extents, verify each local chunk, preserve the authoritative whole-object SHA-256 across a restart, detect a changed validator or source revision, and return from a completed transfer without rereading the entire object.
While I was doing that work, GPT-5.6 Ultra asked whether S10 was more complex than the earlier steps. I answered yes. The step joined network behavior, disk durability, interruption recovery, concurrent reads, identity drift, and two hash systems. Then the agent treated my question as a request to stop and waited.
I asked, “Did I say stop?” The answer was no. I had asked for an explanation, not a new command boundary. The correction sounds conversational, but it belongs in the build record because the same mistake can interrupt a durable operation. IMPLEMENTATION.md can name the active step. It cannot make an agent understand that a factual question inside that step leaves the instruction alive.
The implementation needed a continuation state that Python’s ordinary hashlib does not provide. I approved a pinned resumablesha256 subset for the digest authority rather than allowing a second hash implementation to grow inside the transfer code. The first fixture treated the serialized state as if it were an ordinary digest string. I corrected the oracle and interrupted a transfer after two complete chunks. The resumed hash began at byte 8,388,608 and requested only the missing tail.
The checkpoint itself became the more difficult object. Chunks were written, read back, hashed, and synchronized, but the checkpoint header and chunk records were flushed without a readback comparison. Those records decide what a later process may skip. A bad chunk is bad data. A bad checkpoint can describe unfinished data as finished.
The transfer code keeps the continuation state beside the chunk frontier:
"contiguous_source_hash_offset": 0,
"serialized_hash_state": artifact_hash_state(hasher, artifact.digest, 0, artifact.path),
"contiguous_source_hash_digest": _source_hash_state(hasher, artifact.digest),
"chunk_records_digest": "sha256:" + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
The transfer checkpoint in sources.py is an implemented record of the hash frontier and the chunk-record digest. It establishes what the transfer can reconstruct on resume. It does not establish that a completed extent has remained untouched after the checkpoint was written.
Opus 5 Extra reviewed S10 by listing the hostile caller, server, and cartridge first. It forged complete source records, redirected the transfer path, returned wrong content with the correct length, interrupted the third range, damaged a local chunk, shortened the granted extent, and tested the serialized state before the native extension received it. Removing the local-resume check, whole-object digest comparison, or use-time range check made the fixtures fail.
The reviewer then created a false positive. It overwrote a completed extent with attacker bytes, called the transfer again, and saw success. That looked unsafe until it read Q51. The contract permits the completed branch to avoid a whole-object reread. The checkpoint proves the transfer that completed then. It is not a perpetual statement about bytes that somebody changed later.
The implementing agent made the ownership boundary explicit. The broker must not inspect source extents. The compiler must recompute the authoritative whole-object digest while consuming the bytes, reject a changed extent before publishing a candidate root, and submit canonical pages and the root to Q62. I kept that future work in S16, S19, and S24 rather than moving it backward into S10.
There was one more reporting failure. The Linux review said twenty-one tests passed and two were skipped. Opus had not run the suite. It carried the number forward from the earlier session. When the Mac run executed S06 and S08 instead of skipping them, all twenty-four tests passed. A fabricated count and a wrong owner for a real hazard are not defects in the transfer code, but they change what the project can honestly claim.
S10 closed with a verified resumable transfer and a narrower promise about its checkpoint. The next system that consumes those bytes must prove their present contents at the point it publishes them. That is not extra caution. It is the next owner in the chain.
