spec: cultnet write receipt (write_admitted, error id echo, admitted/refused/unconfirmed) #59
Loading…
Reference in a new issue
No description provided.
Delete branch "libby/cultnet-write-receipt-spec"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spec PR for Heimdall's ruling (a write completes on its result frame; admitted and refused never look alike). Files in
contracts/cultnet/interop/:write-receipt.md(rules),cultnet.write-admitted.schema.json,cultnet.error.v1.schema.json,write-receipt-vectors.json. No runtime or server code.Decisions:
cultnet.write_admitted.v0{messageId, operation, schemaId, recordKey}, sent after the commit point; exactly one of it or an error per write.cultnet.error.v1(v0 + requiredmessageId, nil only for an unreadable frame). Not an extra key on v0: the v0 schema is closed and the TS decoder (Ajv) rejects unknown keys and unknownschemaVersions, so "old clients ignore the new frame" is false for today's decoders. Instead the new frames go only to connections whosecultnet.hello.v0lists both insupportedMessageVersions; everyone else gets today's behaviour. Rust/Python/Kotlin unknown-key tolerance is unverified and not assumed.write_admitted. Forwarded writes relay the primary's answer with the original id; no primary answer means silence, not success.admitted | refused | unconfirmed. The 500 ms window (from the send) is the fallback for a pre-receipt server and endsunconfirmed(window_elapsed/session_ended), never success or refusal. An id-less error is attributed only when exactly one write is unanswered.This changes what #55 to #58 shipped: window-with-no-refusal is
unconfirmedunder this spec, not success. Conformance work (all runtimes, hello capability, the forwarder, the Odin catalog) is follow-up.🤖 Generated with Claude Code
Revised per Heimdall: dedupe by (actor, messageId) bound to a content hash (same id, other content = message_invalid, never the old receipt); late answers recorded admitted_late/refused_late; forwarder with no primary answer relays nothing; RECEIPT 5 s / LEGACY 500 ms named constants; capability is framing only; batches can commit partially.