# ECHO Draft Desk 0.1 · local file profile

Status: reference integration, authored by Money Musk. HAP-1 is unchanged.
The application implements a local file effect and a signed snapshot format;
it does not introduce another authority protocol.

## Permission and dispatch

The ticket must verify against a retained issuer key and carry:

- capability `save-draft`;
- resource `draft-outbox`;
- audience equal to the executor key ID;
- unit `utf8-bytes`.

The example owner process uses a 128-byte aggregate allowance, three permitted
uses, a five-second freshness window and a sixty-second grant lifetime. Budget
is consumed when the authority signs the permit, even if execution later fails.

Each payload has exactly `schema: "ECHO/draft/1"`, a 32-character lowercase hex
`operation`, and `contentHex` containing 1–4096 valid UTF-8 bytes. Hex preserves
HAP-1's ASCII canonicalization contract. The SHA-256 of the canonical payload
binds its operation ID and bytes to the HAP-1 executor challenge and permit.

Before requesting a permit, the executor durably claims the operation ID with
an `UNKNOWN / NOT_COMPLETED` result. It then obtains and verifies a fresh HAP-1
permit. Immediately before writing it checks the local revoke flag, closed state
and freshness. There is no asynchronous gap from that check through the bounded
file write. The fixed outbox path and `<operation>.txt` name are not caller-chosen.

Creation uses exclusive, no-follow flags and mode 0600 in a private directory;
existing files are not overwritten. The file and directory are fsynced before a
`SAVED` result is signed and persisted. A failure after entering the write path
is `UNKNOWN`; a failure before it is `REFUSED`. A process exit before persisting
the final result leaves the initial unknown claim. No result is inferred from a
file's mere existence.

Identical operation IDs return the stored record, including `UNKNOWN`; different
content under the same ID is rejected. Claims use SQLite compare-and-swap. The
gate and journal must already exist when reopening; missing state never creates
a new allowance. This model assumes trusted local files, keys, clock and OS.

## Signed records

All signatures are Ed25519 over UTF-8 `domain + "\n" + canonical(unsignedBody)`.
Canonicalization and hashing use the existing HAP-1 rules.

`ECHO/draft-result/1` has exactly:

```text
schema, executor, operation, ticketHash, payloadHash,
status, reason, permitHash, outputHash, dispatchedAt, observedAt, signature
```

`status` is `SAVED`, `REFUSED` or `UNKNOWN`. `reason` is null on success or a
bounded uppercase code. `permitHash` is the HAP-1 permit receipt hash only when
the file-effect callback was entered. `outputHash` is the SHA-256 of the raw file
bytes after successful write and fsync. Timestamps are integer milliseconds.

`ECHO/draft-evidence/1` has exactly:

```text
schema, ticket, history, checkpoint, records, signature
```

The executor signs this envelope. Each of its 1–64 records contains exactly
`payload`, `permit` (the receipt or null), and `receipt` (the signed result).
This profile uses a dedicated single-ticket authority history from sequence zero,
with a signed human checkpoint at its end. It can include permits that never
reached execution; they still consumed allowance. A surviving initial unknown
claim need not contain a permit even if the human history later issued one.

The separately retained `ECHO/draft-pin/1` has exactly `schema`, `humanPublicKey`,
`executorPublicKey`, and `ticketHash`. The checker never takes its trust keys from
the evidence envelope. The sample generates this pin locally; real distribution
requires independent authentication. A pin to the grant alone does not establish
that a later signed snapshot is the latest one.

## Python verification and limits

`verify.py` requires the explicit pin, evidence and outbox. It rejects duplicate
JSON keys, noncanonical numbers, oversized inputs, unrecognized fields, invalid
signatures, incomplete continuity, mismatched checkpoints, duplicate challenges
or operations, permits after revocation, excessive usage and wrong action bindings.

For each saved result it checks the exact permitted amount and payload digest,
dispatch window, signed result hash and actual file bytes. It reads saved files
without following symlinks and rejects unrelated outbox entries. Refused outcomes
are signed attestations with no corresponding file in that supplied directory.
Unknown outcomes are counted separately and never promoted to verified saves.

The JSON report explicitly sets `liveAuthority`, `humanPresence`, and
`independentAdoption` to false. A valid signed snapshot does not authorize another
execution, prove completeness or live revocation status, establish biological
presence, or prove that no action occurred elsewhere. The verifier is a second
language implementation by the same project, not an external audit.
