82 lines
3.4 KiB
Markdown
82 lines
3.4 KiB
Markdown
# Phase 0.9D off-device backup contract
|
|
|
|
Date: 2026-07-18
|
|
Status: `DESIGN_ONLY`; no readback route currently satisfies this contract.
|
|
|
|
## Invariants
|
|
|
|
A future host workflow shall process one component per separately authorized
|
|
session. It shall contain no upload, create-on-device, rename, unlink, delete,
|
|
chmod, chown, launch, process/service action, mount action, configuration
|
|
change, `/autoload_status`, automatic resume, or automatic retry.
|
|
|
|
The host must:
|
|
|
|
1. record an approved literal source path without inference;
|
|
2. record non-secret device identity, session identity, route, raw
|
|
request/response metadata, and exact client source commit;
|
|
3. create a new local temporary output exclusively and refuse overwrite;
|
|
4. receive in binary mode while counting every byte;
|
|
5. reject timeout, protocol error, unexpected EOF, short transfer, surplus
|
|
bytes, missing expected length, or any partial output as
|
|
`TRANSFER_INCOMPLETE` then `INVALID`;
|
|
6. close the file, reopen it, record its exact size, and compute SHA-256;
|
|
7. start a new connection and session for a second new exclusive local
|
|
temporary file, with no reused partial bytes;
|
|
8. close, reopen, size, and hash the second file;
|
|
9. compare exact sizes, SHA-256 values, and every byte;
|
|
10. make no automatic third attempt when the copies differ.
|
|
|
|
If a transport cannot provide a trustworthy expected byte count, the host may
|
|
save an exploratory copy only as `SOURCE_MAPPING_PARTIAL`; it cannot classify
|
|
the transfer as byte-exact source attestation. The current stack has the
|
|
stronger blocker that it does not return arbitrary file bytes at all.
|
|
|
|
## State machine
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> TRANSFER_NOT_STARTED
|
|
TRANSFER_NOT_STARTED --> TRANSFER_INCOMPLETE: first byte accepted
|
|
TRANSFER_INCOMPLETE --> INVALID: timeout / short read / framing error
|
|
TRANSFER_INCOMPLETE --> HOST_COPY_RECEIVED: exact complete response
|
|
HOST_COPY_RECEIVED --> HOST_COPY_REOPENED: close + reopen
|
|
HOST_COPY_REOPENED --> HOST_COPY_HASHED: size + SHA-256
|
|
HOST_COPY_HASHED --> SECOND_COPY_CREATED: new session/output
|
|
SECOND_COPY_CREATED --> SECOND_COPY_REOPENED: exact receive + close/reopen
|
|
SECOND_COPY_REOPENED --> SECOND_COPY_HASHED: size + SHA-256
|
|
SECOND_COPY_HASHED --> INVALID: size/hash/byte mismatch
|
|
SECOND_COPY_HASHED --> COPIES_MATCH: size/hash/all bytes equal
|
|
COPIES_MATCH --> SOURCE_MAPPING_PARTIAL: path/object identity incomplete
|
|
COPIES_MATCH --> SOURCE_MAPPING_VERIFIED: independent source mapping proven
|
|
```
|
|
|
|
Required status vocabulary:
|
|
|
|
- `TRANSFER_NOT_STARTED`
|
|
- `TRANSFER_INCOMPLETE`
|
|
- `HOST_COPY_RECEIVED`
|
|
- `HOST_COPY_REOPENED`
|
|
- `HOST_COPY_HASHED`
|
|
- `SECOND_COPY_CREATED`
|
|
- `SECOND_COPY_REOPENED`
|
|
- `SECOND_COPY_HASHED`
|
|
- `COPIES_MATCH`
|
|
- `SOURCE_MAPPING_PARTIAL`
|
|
- `SOURCE_MAPPING_VERIFIED`
|
|
- `INVALID`
|
|
|
|
## Classification boundaries
|
|
|
|
`OFF_DEVICE_BACKUP_VALID` is allowed only after the two closed-and-reopened
|
|
local copies have identical sizes, SHA-256 values, and bytes. It says nothing
|
|
about the current live source path unless source mapping was independently
|
|
proven.
|
|
|
|
`RECOVERY_PROVEN` is forbidden in this phase. A matching host backup is not
|
|
proof that any actor can safely restore it, survive power loss, retain the old
|
|
live file, or recover without the component being replaced.
|
|
|
|
The contract is intentionally descriptive. Phase 0.9D creates no client,
|
|
script, device command, backup, or transfer package.
|