sandbox §13.1–13.2: what a park retains, and what an interval proves about waiting #582

Merged
dcharlot merged 2 commits from sandbox/transcript-continuation into main 2026-11-02 18:42:36 -05:00
Owner

§13 has always let a run be suspended and resumed, recording what it retained as
a filesystem root and an optional memory image. That shape assumes the resumable
state lives on the host. For a whole class of unit it does not: where the
resumable state is the record of what the unit has already done, that record
is the continuation — restore it and the unit is where it left off, with no
process to revive. Such a run was being made to describe itself in terms of a
filesystem it did not need, and to be priced as though it had parked one.

The two forms

A snapshot reference now carries one of two, and exactly one.

retains resumes on park draws
image fs_root, and memory where resident state is suspended a host able to restore that image a volume, and memory where there is an image
transcript the content address of the run's transcript, and nothing on the host any host satisfying the manifest (§14) the stored bytes

Neither form, both, or a transcript beside a resident memory image is refused
with MalformedSnapshot before anything is hashed, and leaves no segment behind.
The third case is the one worth naming: a park claiming to retain nothing on the
host while holding an image on it. Admitting any of them would put an ambiguity
inside a chain whose whole purpose is to remove one.

The energy claim this makes, and the one it refuses

Nothing runs during a transcript park and nothing is resident, so it is tempting
to call the wait free. What it holds is bytes in storage, and storage draws power
for every hour of the wait. A host therefore MUST NOT record a transcript
park's idle_uj as zero on the grounds that no computation happened; the figure
it owes is the draw of the bytes it kept, under §6.2's provenance discipline.

The claim this form supports is that waiting costs no computation. It does
not support the claim that waiting costs nothing. A run parked for a week on a
transcript is far cheaper than one parked on a volume, and neither is costless;
§13's total — receipts plus idle — stands for both. A record that says zero for a
week of storage is not a cheaper run, only a less honest one.

Backwards compatibility, checked rather than asserted

fs_root became Option with serde(default, skip_serializing_if), so an image
snapshot serializes to the same JSON it always did, and push_snapshot emits
exactly the former byte layout for that form. Two things hold the change to it:

  • a unit test pins the image layout against bytes written out by hand, so it
    is checked without reference to the code that produced it;
  • the committed vector's image-form head is unchanged. durable.json diffs as
    one added line and no changed line — expect_runrecord_head is still
    b3:mk3hGn1kCXPuMQNPGQxHsqu8TxsnGVPBTBcgcxrHYlA, and the transcript form gets
    its own pinned address, b3:XKKBf5hYdrSZoJN-GHLdZ_Bbg7CjN6P4DCRVD17GyUs. The
    two traces are identical but for the form parked, so an implementation that
    confused the forms would produce one address where the other is expected.

Hashing is now total, and one latent bug went with it

Segment::chain_bytes returns Option and fold returns Result, so a
malformed reference cannot be hashed into a chain: suspend refuses it, and one
edited into a record through the wire form makes verify() false rather than
hashing to something. Separately, resume used to add to the run's idle total
before folding the segment, so a refused resume left energy attributed to a
park that was never recorded. It now folds first, and a test holds that.

Conformance

Class C14, and the pack's deliberate class count moves 13 → 14 (the guard
says to bump it only when a class is added, which is the case here).

Evidence

All of it on the build host; nothing was built on the dev Mac.

  • cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo test --workspace: passes.
  • The full pack: all 14 classes passed with no skips, including the
    file-backed durable.json check.
  • check-comparative-prose.sh clean over 4,063 files;
    check-no-vanity-metrics.sh clean over 517 Markdown files.
  • cargo fmt was deliberately not run: these workspaces are not
    rustfmt-clean, and it would bury the change in churn.

🤖 Generated with Claude Code


§13.2 — what an interval proves about waiting (second commit)

§13 prices the wait a run spends parked. It said nothing about the wait a run
spends running, which is usually the larger number: an interval that
dispatches an outward call and then sits until the result arrives holds its
sandbox, and its receipt charges the sitting as computation. Two runs doing
identical work bill hours apart, and the record reported both the same way.

An executed segment may now carry a CallAccount — the calls it dispatched and
the results it resolved, each by call id. A run is non-blocking when every
executed interval accounts, and every interval resolves only calls that were
outstanding before it began. One that resolves its own dispatch did not hand off
and return; it waited, and the wait is inside its receipt.

RunRecord::wait_proof() returns one of four verdicts:

means
NonBlocking no receipt in the run contains a wait for an outward call, so the run's whole cost of waiting is the idle energy §13 records — and §13.1 makes small
Blocked { segment } that interval consumed its own dispatch
Malformed { segment } the account does not add up — a result answering no dispatched call, a call resolved twice, one id dispatched twice
Unproved some interval did not account, or the run has no accounted interval

This is what licenses the energy claim. "Waiting costs no computation" becomes a
statement about this record rather than about the runtime that produced it,
checkable by walking the segments — no trust in the implementation, and no
instrumentation beyond the ids a host already needs to match results to calls.

Two deliberate pieces of honesty:

  • An absent account is not an empty one. Not accounting and accounting for no
    calls are different statements, and they do not fold to the same bytes. A unit
    test and a conformance check both hold that, so the marker is not just a
    comment.
  • A property of no intervals is not a property. A run with nothing accounted
    returns Unproved, never NonBlocking. Without that rule every empty record
    would certify the section's strongest claim.

Backwards compatibility again checked rather than asserted: calls is folded
only when present, so an interval recorded by record_execution hashes exactly
as before (pinned against hand-written bytes), and durable.json diffs as one
added line and no changed line
— both earlier heads unchanged, the accounted
trace pinned at b3:FINebhSRpv_1ncmpE3PaRG85MR8Ri1fDy4lmR1yI2DA. That trace is
the transcript one with the account added and nothing else, so an implementation
that dropped the account would produce the transcript head where this one is
expected. Each id set is length-prefixed, so no id boundary is ambiguous.

Conformance class C15; the pack's deliberate class count moves 13 → 15 across
the two commits.

Evidence for both commits

  • cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo test --workspace: passes.
  • The full pack: all 15 classes passed with no skips, including the
    file-backed durable.json check.
  • Re-verified on Linux x86_64 as well as macOS arm64, so none of this is
    platform-dependent.
  • cargo fmt deliberately not run: these workspaces are not rustfmt-clean.
§13 has always let a run be suspended and resumed, recording what it retained as a filesystem root and an optional memory image. That shape assumes the resumable state lives on the host. For a whole class of unit it does not: where the resumable state is the record of what the unit has already done, that record **is** the continuation — restore it and the unit is where it left off, with no process to revive. Such a run was being made to describe itself in terms of a filesystem it did not need, and to be priced as though it had parked one. ### The two forms A snapshot reference now carries one of two, and exactly one. | | retains | resumes on | park draws | |---|---|---|---| | image | `fs_root`, and `memory` where resident state is suspended | a host able to restore that image | a volume, and memory where there is an image | | transcript | the content address of the run's transcript, and nothing on the host | any host satisfying the manifest (§14) | the stored bytes | Neither form, both, or a transcript beside a resident memory image is refused with `MalformedSnapshot` before anything is hashed, and leaves no segment behind. The third case is the one worth naming: a park claiming to retain nothing on the host while holding an image on it. Admitting any of them would put an ambiguity inside a chain whose whole purpose is to remove one. ### The energy claim this makes, and the one it refuses Nothing runs during a transcript park and nothing is resident, so it is tempting to call the wait free. What it holds is bytes in storage, and storage draws power for every hour of the wait. A host therefore **MUST NOT** record a transcript park's `idle_uj` as zero on the grounds that no computation happened; the figure it owes is the draw of the bytes it kept, under §6.2's provenance discipline. The claim this form supports is that **waiting costs no computation**. It does not support the claim that waiting costs nothing. A run parked for a week on a transcript is far cheaper than one parked on a volume, and neither is costless; §13's total — receipts plus idle — stands for both. A record that says zero for a week of storage is not a cheaper run, only a less honest one. ### Backwards compatibility, checked rather than asserted `fs_root` became `Option` with `serde(default, skip_serializing_if)`, so an image snapshot serializes to the same JSON it always did, and `push_snapshot` emits exactly the former byte layout for that form. Two things hold the change to it: - a unit test pins the image layout against bytes written out **by hand**, so it is checked without reference to the code that produced it; - the committed vector's image-form head is unchanged. `durable.json` diffs as **one added line and no changed line** — `expect_runrecord_head` is still `b3:mk3hGn1kCXPuMQNPGQxHsqu8TxsnGVPBTBcgcxrHYlA`, and the transcript form gets its own pinned address, `b3:XKKBf5hYdrSZoJN-GHLdZ_Bbg7CjN6P4DCRVD17GyUs`. The two traces are identical but for the form parked, so an implementation that confused the forms would produce one address where the other is expected. ### Hashing is now total, and one latent bug went with it `Segment::chain_bytes` returns `Option` and `fold` returns `Result`, so a malformed reference cannot be hashed into a chain: `suspend` refuses it, and one edited into a record through the wire form makes `verify()` false rather than hashing to something. Separately, `resume` used to add to the run's idle total **before** folding the segment, so a refused resume left energy attributed to a park that was never recorded. It now folds first, and a test holds that. ### Conformance Class **C14**, and the pack's deliberate class count moves 13 → 14 (the guard says to bump it only when a class is added, which is the case here). ### Evidence All of it on the build host; nothing was built on the dev Mac. - `cargo clippy --workspace --all-targets -- -D warnings`: clean. - `cargo test --workspace`: passes. - The full pack: **all 14 classes passed with no skips**, including the file-backed `durable.json` check. - `check-comparative-prose.sh` clean over 4,063 files; `check-no-vanity-metrics.sh` clean over 517 Markdown files. - `cargo fmt` was deliberately **not** run: these workspaces are not rustfmt-clean, and it would bury the change in churn. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- ## §13.2 — what an interval proves about waiting (second commit) §13 prices the wait a run spends **parked**. It said nothing about the wait a run spends **running**, which is usually the larger number: an interval that dispatches an outward call and then sits until the result arrives holds its sandbox, and its receipt charges the sitting as computation. Two runs doing identical work bill hours apart, and the record reported both the same way. An executed segment may now carry a `CallAccount` — the calls it dispatched and the results it resolved, each by call id. A run is **non-blocking** when every executed interval accounts, and every interval resolves only calls that were outstanding before it began. One that resolves its own dispatch did not hand off and return; it waited, and the wait is inside its receipt. `RunRecord::wait_proof()` returns one of four verdicts: | | means | |---|---| | `NonBlocking` | no receipt in the run contains a wait for an outward call, so the run's whole cost of waiting is the idle energy §13 records — and §13.1 makes small | | `Blocked { segment }` | that interval consumed its own dispatch | | `Malformed { segment }` | the account does not add up — a result answering no dispatched call, a call resolved twice, one id dispatched twice | | `Unproved` | some interval did not account, or the run has no accounted interval | This is what licenses the energy claim. "Waiting costs no computation" becomes a statement about **this record** rather than about the runtime that produced it, checkable by walking the segments — no trust in the implementation, and no instrumentation beyond the ids a host already needs to match results to calls. Two deliberate pieces of honesty: - **An absent account is not an empty one.** Not accounting and accounting for no calls are different statements, and they do not fold to the same bytes. A unit test and a conformance check both hold that, so the marker is not just a comment. - **A property of no intervals is not a property.** A run with nothing accounted returns `Unproved`, never `NonBlocking`. Without that rule every empty record would certify the section's strongest claim. Backwards compatibility again checked rather than asserted: `calls` is folded only when present, so an interval recorded by `record_execution` hashes exactly as before (pinned against hand-written bytes), and `durable.json` diffs as **one added line and no changed line** — both earlier heads unchanged, the accounted trace pinned at `b3:FINebhSRpv_1ncmpE3PaRG85MR8Ri1fDy4lmR1yI2DA`. That trace is the transcript one with the account added and nothing else, so an implementation that dropped the account would produce the transcript head where this one is expected. Each id set is length-prefixed, so no id boundary is ambiguous. Conformance class **C15**; the pack's deliberate class count moves 13 → 15 across the two commits. ### Evidence for both commits - `cargo clippy --workspace --all-targets -- -D warnings`: clean. - `cargo test --workspace`: passes. - The full pack: **all 15 classes passed with no skips**, including the file-backed `durable.json` check. - Re-verified on **Linux x86_64** as well as macOS arm64, so none of this is platform-dependent. - `cargo fmt` deliberately not run: these workspaces are not rustfmt-clean.
sandbox §13.1: a park retains host state or a transcript, and says which
Some checks failed
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
15b79aba7b
§13 has always let a run be suspended and resumed, recording what it retained
as a filesystem root and an optional memory image. That shape assumes the
resumable state lives on the host. For a whole class of unit it does not: where
the resumable state is the record of what the unit has already done, that record
*is* the continuation — restore it and the unit is where it left off, with no
process to revive. Such a run was being made to describe itself in terms of a
filesystem it did not need.

So a snapshot reference now carries one of two forms, and exactly one.

- **An image park** retains host state: `fs_root`, and `memory` where the
  executor suspends resident state. Unchanged.
- **A transcript park** retains nothing on the host, naming only the content
  address of the run's transcript.

Neither form, both, or a transcript beside a resident memory image is refused
with `MalformedSnapshot` before anything is hashed, and leaves no segment
behind. The third case is the interesting one: a park claiming to retain nothing
on the host while holding an image on it. Admitting any of them would put an
ambiguity inside a chain whose whole purpose is to remove one.

What the second form buys, and what it does not

- **It resumes anywhere.** §13's content-identity precondition is satisfiable by
  any host that can fetch the transcript, so such a park is portable across
  hardware by construction; an image park also needs a host able to restore its
  image. The record now says not merely that a run can resume but where.
- **Its park is small, and still priced.** Nothing runs and nothing is resident,
  and it is tempting to call that free. What it holds is bytes in storage, and
  storage draws power for every hour of the wait, so a host **MUST NOT** record
  its `idle_uj` as zero on the grounds that no computation happened. The claim
  this form supports is that *waiting costs no computation*. It does not support
  the claim that waiting costs nothing, and a record that says zero for a week
  of storage is not a cheaper run, only a less honest one. §13's total stands
  for both forms.

Backwards compatibility, checked rather than asserted

`fs_root` became `Option` with `serde(default, skip_serializing_if)`, so an
image snapshot serializes to the same JSON it always did, and `push_snapshot`
emits exactly the former byte layout for that form — `fs_root ‖ (1 ‖ memory |
0) ‖ manifest`. Two things hold me to it:

- a unit test pins the image layout against bytes written out by hand, so it is
  checked without reference to the code that produced it;
- the committed vector's image-form head is unchanged. `durable.json` diffs as
  one added line and no changed line: `expect_runrecord_head` is still
  `b3:mk3hGn1kCXPuMQNPGQxHsqu8TxsnGVPBTBcgcxrHYlA`, and the transcript form
  gets its own pinned address at `b3:XKKBf5hYdrSZoJN-GHLdZ_Bbg7CjN6P4DCRVD17GyUs`.
  The two traces are identical but for the form parked, so an implementation
  that confused them would produce one address where the other is expected.

Hashing is now total rather than partial: `Segment::chain_bytes` returns
`Option`, `fold` returns `Result`, and a malformed reference edited into a
record through the wire form makes `verify()` false instead of hashing to
something. One latent bug went with it — `resume` used to add to the run's idle
total before folding the segment, so a refused resume left energy attributed to
a park that was never recorded. It now folds first.

Conformance class C14, and the pack's deliberate class count moves 13 → 14.

Evidence, all on the build host (nothing built on the dev Mac): clippy
`-D warnings` clean over the workspace, the workspace's tests pass, and the full
pack reports all 14 classes passed with no skips. `check-comparative-prose.sh`
and `check-no-vanity-metrics.sh` are clean.

Co-Authored-By: Claude Opus 5 <[email protected]>
sandbox §13.2: what an executed interval proves about waiting
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 7s
standards workspaces build + test / proof-rs (proof/conformance/v1/joulespec.toml, proof-conformance, proof/proof-rs, proof-rs, linux, true) (pull_request) Successful in 1m1s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m25s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, -p sandbox-tee --features amd-kds,intel-pcs, sandbox-rs, linux) (pull_request) Successful in 1m37s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m46s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m21s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 7m1s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 12m16s
standards workspaces build + test / joulecontract-rs (joulecontract/joulecontract-rs, joulecontract-rs, linux-arm64, true) (pull_request) Successful in 1m15s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 7m28s
48372367aa
§13 prices the wait a run spends parked. It says nothing about the wait a run
spends *running*, which is usually the larger number. An interval that dispatches
an outward call and then sits until the result arrives holds its sandbox, and its
receipt charges the sitting as computation. A twenty-minute build, a review that
comes back the next morning, an approval that never comes — each is, in a
blocking runtime, an interval whose receipt is mostly waiting. Two runs doing
identical work bill hours apart, and the record reported both the same way.

So an executed segment may now carry a `CallAccount`: the calls it dispatched
and the results it resolved, each by call id.

A run is **non-blocking** when every executed interval accounts, and every
interval resolves only calls that were outstanding before it began. An interval
that resolves a call it dispatched itself did not hand off and return — it
waited, and the wait is inside its receipt. `RunRecord::wait_proof()` walks the
segments in order holding the outstanding set and returns one of:

- `NonBlocking` — no receipt in the run contains a wait for an outward call, so
  the run's whole cost of waiting is the idle energy §13 already records, and
  which §13.1 makes small for a transcript park. This is the condition under
  which "waiting costs no computation" is a statement about the record rather
  than about the runtime that produced it.
- `Blocked { segment }` — that interval consumed its own dispatch.
- `Malformed { segment }` — the account does not add up: a result answering a
  call never dispatched, a call resolved twice, or one id dispatched twice. A
  record that cannot be read is a different problem from a run that waited, and
  is reported separately.
- `Unproved` — some interval did not account, or the run has no accounted
  interval at all.

Two deliberate pieces of honesty

**An absent account is not an empty one.** Not accounting and accounting for no
calls are different statements, and they do not fold to the same bytes — a test
and a conformance check both hold that, so the marker is not merely a comment.

**A property of no intervals is not a property.** A run with nothing accounted
returns `Unproved`, not `NonBlocking`. Without that, every empty record would
certify the strongest claim in the section.

Backwards compatibility, checked rather than asserted

`calls` is `Option`, `serde(default, skip_serializing_if)`, and folded into the
chain only when present, so an interval recorded by `record_execution` hashes
exactly as it did before — pinned by a test against bytes written out by hand.
The committed vector confirms it: `durable.json` diffs as one added line and no
changed line, so `expect_runrecord_head` and `expect_transcript_head` are
unchanged, and the accounted trace gets its own address at
`b3:FINebhSRpv_1ncmpE3PaRG85MR8Ri1fDy4lmR1yI2DA`. That trace is the transcript
one with the account added and nothing else changed, so an implementation that
dropped the account would produce the transcript head where this one is
expected. Each id set is length-prefixed, so no id boundary is ambiguous.

Conformance class C15, and the pack's deliberate class count moves 14 → 15.

Evidence, on the build host: clippy `-D warnings` clean over the workspace, the
workspace's tests pass, and the full pack reports all 15 classes passed with no
skips. `cargo fmt` was not run: these workspaces are not rustfmt-clean.

Co-Authored-By: Claude Opus 5 <[email protected]>
dcharlot changed title from sandbox §13.1: a park retains host state or a transcript, and says which to sandbox §13.1–13.2: what a park retains, and what an interval proves about waiting 2026-11-02 13:39:00 -05:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!582
No description provided.