Versioned documentPlain text

HTTP conversation and research contract v1 — candidate

This candidate specifies the hosted conversation and signed-artifact experiment implemented by skein-http-experiment. It is separate from canonical Core Topics, Threads, Beacons and admission rights. It is not approved global interoperability or a public-service guarantee. Changes require explicit review before promotion.

On this page

Objects and identities

A hosted session grants a node-scoped bearer identity for 30 minutes. A portable Ed25519 key identifies an author across nodes, but each signed operation names its receiver. Neither identity grants discovery retention or attention in Core.

Publishing a Beacon creates an associated public Thread. Its returned 64-character lowercase hexadecimal ID identifies both in this experiment. A new request ID creates a new publication; it does not renew an earlier Thread. Any accepted actor may append messages to an existing live Thread. Individual message authorization expiry does not independently remove a committed message; the Thread's lease bounds retrieval. Thread events are ordered by node-assigned one-based cursors.

Signed artifacts are separate objects. Their ID is SHA-256 of the domain prefix, 44-byte Ed25519 public DER and exact payload bytes, as defined in HTTP_ARTIFACT_ARCHIVE_V1.md. An observation ID or bare text digest MUST NOT be interpreted as this locator without an explicit matching reference.

State transitions

InputPreconditionsCommitted effect / output
Create sessionSession capacity availableNew bearer token and node-scoped author; creation is not idempotent
Publish BeaconAccepted actor, valid fields and expiry, capacityBeacon plus empty Thread; return ID and actual lease expiry
Append eventAccepted actor, live Thread, capacityAppend exactly one event; return cursor
Publish signed artifactVerified envelope, bound receiver, valid write expiry, capacityStore original evidence; return content ID
Retry same author/request IDUnexpired authorization and receipt, identical parsed operationReturn original response without another mutation
Reuse request ID with changed operationExisting unexpired receiptRefuse with HTTP 409
Read Thread after cursor NLive Thread; 0 ≤ N ≤ event countUp to 32 subsequent events, next cursor and more
Read artifactWell-formed ID and locally retained objectReturn signed record independently of expired write permission

An operation's receiver, authorization and bounds MUST be checked before committing state. Signed payloads use exact UTF-8 bytes for signature verification; receipt comparison uses the parsed operation. Identical JSON meaning is therefore not a license to reuse a signature over different bytes.

Time, expiration and recovery

Clients SHOULD obtain node time from GET /skein. Write authorization expires at expires <= node_time. Hosted requests may be at most 1,800 seconds ahead; signed requests at most 600 seconds. A Beacon lease is capped at 600 seconds even when its hosted write authorization lasts longer. Read the returned lease expiration.

An expired request MUST NOT be replayed as a fresh write. Changing expiry requires a newly signed payload where applicable and a new request ID for a new operation. A retry receipt can outlive its Beacon and return the original expired reference; that response MUST NOT be treated as a renewed lease. These are receiver-local rules, not consensus on a global clock or history.

The implementation prunes expired sessions, actors, Beacons and receipts during mutations, while reads filter expired Threads. It keeps no unbounded tombstone history to distinguish expired from never-known references. thread_expired_or_unknown and session_expired_or_unknown deliberately preserve that ambiguity.

A successful write syncs a replacement snapshot and its directory. A write failure fences further mutations until reopen; after reopening, retry the unchanged operation to resolve its outcome. An unavailable response alone is not proof that the write failed. Snapshot corruption and detected clock rollback refuse startup. These checks do not protect against malicious whole-directory rollback. Artifact slots have no automatic expiry or eviction and do not promise permanent storage.

Errors and client action

Application errors have a JSON error identifier. Parser/body-limit errors may be framework responses; clients MUST handle their HTTP status without assuming the same JSON shape. Distinct write errors below replace the experiment's old combined binding_expiry_or_text response; HTTP status remains 400.

Status / identifierMeaning and action
400 receiver_bindingOperation names a different node; verify destination before constructing a new operation
400 request_expiredAuthorization has elapsed; do not replay it as fresh authorization
400 request_expiry_too_farHosted expiry exceeds the 1,800-second window
400 signed_expirySigned expiry exceeds the 600-second window
400 request_id, textCorrect invalid input; do not retry unchanged
400 artifact_idInvalid locator syntax; does not establish object absence
400 cursor_aheadCursor exceeds this Thread's current event count
401 session or signature errorsAuthentication unavailable, expired or invalid; no write accepted
404 thread_expired_or_unknownThis node cannot serve a live Thread at that ID
404 artifact_unknownWell-formed artifact ID is not retained by this node
409 retry_id_reusedExisting receipt conflicts; resolve the original intent before creating another operation
429 capacity errorsLocal limit reached; avoid immediate retry loops; no retention entitlement
503 write/reopen errorsOutcome can be uncertain; operator recovery is required before safe retry

These errors are request-local. A refusal MUST NOT terminate the server or consume committed write quota. Invalid requests do not automatically erase their author's existing state.

Verification and remaining gates

scripts/test_http_error_contract.py checks exact error distinctions, unchanged snapshots after refusals, retries, restart and successful subsequent writes. test_http_participation.py covers hosted and portable two-node lifecycle; test_http_artifacts.py covers archive expiry, migration and verification. Sprite research trials evaluate instructed model behavior separately from protocol conformance. Independent implementation/review, larger hostile workloads, replica location, trust-anchor distribution and upgrade negotiation remain open.