Gives senders of event-graph broadcast messages evidence about whether peers accepted them, and defines the sender-side rebroadcast/recreate policy that prevents messages written while offline from being silently lost to DAG rotation. Covers the reply wire format, delivery-state exposure to applications, darkirc's outbound tracking and recreate flow, and client-side dedup/display of delivery state.
A node that receives an EventPut SHALL send the sender an
EventPutStatus reply on the same channel describing the outcome:
Has { inserted: true } when the event was newly accepted into the
node's DAGHas { inserted: false } when the node already has the eventNack { reason: TooOld } when the event predates the node's current
rotation windowNack { reason: NotSynced } when the node is still performing its
initial DAG sync and skipped the eventNack { reason: Invalid } when the event fails structural or
proof validationNack { reason: Busy } when an internal condition prevented
processingReplies apply to relayed events equally: the receiver cannot and does not distinguish originator from relay.
EventPut for an event it does not have,
which passes all validationHas { inserted: true }EventPut whose event is already in its
DAGHas { inserted: false }EventPut whose event timestamp precedes
its current genesisNack { reason: TooOld }EventPutNack { reason: NotSynced }EventPut that trips existing
strike/flood/parent-depth policingEventPutStatus payloads SHALL carry only the event id and a coarse
outcome. Nack reasons SHALL NOT encode fine-grained validation detail.
All enum variants SHALL use explicit u8 discriminants so the wire
format is stable. Decoding an EventPutStatus with an unknown variant
or malformed body SHALL be rejected without panicking, and the receiving
node SHALL NOT strike or ban the sender solely for an undecodable
status.
EventPutStatus carrying a variant it does
not knowEventPutStatus is serializedThe event graph SHALL expose a subscription that republishes every
inbound EventPutStatus unfiltered, together with the peer channel it
arrived on. The event graph itself SHALL NOT track outbound deliveries
or make retry decisions; that policy belongs to applications.
When darkirc publishes a chat message event, it SHALL first persist an
outbound record containing the event id, the message's uid, the
plaintext message fields needed to rebuild it, a state, and an attempt
counter. Records SHALL survive restart. Records SHALL be closed
(removable) once a positive outcome is observed or the attempt cap is
reached.
For an outbound record with no positive outcome, darkirc SHALL wait
until it is DAG-synced and has at least a configured minimum number of
peer connections, then rebroadcast the original event unchanged. It
SHALL retry with backoff, bounded by a configured maximum number of
rounds. A single Has outcome (either inserted value) SHALL close the
record as delivered.
Has { inserted: false } replies close the record and
no recreation happensdarkirc SHALL create a replacement event from the stored plaintext —
fresh timestamp and DAG parents, fresh encryption nonce, same uid —
when any of:
Nack { reason: TooOld } arrives (the rotation window has passed)Recreation SHALL consume a fresh rate-limit slot when rate limiting is enabled; if the epoch budget is exhausted the attempt SHALL be parked and retried after epoch rollover rather than dropped or sent unproven. Recreation attempts SHALL be capped; once the cap is reached the record SHALL be closed as failed and the failure surfaced to the client.
TooOlduid and fresh
parents/timestamp is publishedThe chat message payload SHALL carry a sender-generated uid that
remains identical across recreations of the same message. Receiving
clients SHALL treat messages with equal uid as one logical message for
display purposes. Payload decoding SHALL be version-aware so peers that
do not understand the new field still decode old payloads.
uid receives a payload without
oneThe app SHALL subscribe to delivery statuses for its own outbound
messages and expose per-message delivery state keyed by uid:
sending (no replies yet), delivered (any Has reply), failed
(record closed at the attempt cap). Delivery state SHALL NOT be
presented as evidence that any particular recipient read the message.
Has for the app's outbound messagedeliveredsending