1. Compatibility and protected-area review prerequisites
1.1 Verify unknown-message tolerance: using the event-graph test
harness (src/event_graph/test_helpers.rs), connect two nodes where
only one registers an EventPutStatus dispatch, send a status from
that node to the unregistered receiver, and confirm the receiving
channel stays up (no stop/strike/
panic). Record the outcome in the change notes; if unknown ids
destabilize channels, stop and re-discuss gating before proceeding.
Verify via a new test in src/event_graph/tests.rs.
1.2 Before implementation changes touching RLN, crypto, circuits,
or canonical serialization, stop for human review of the affected
path, especially reservation/recovery for head materialization and
recreation. Record the review outcome and constraints. Do not treat
planning approval or an agent verdict as crypto sign-off. Flag any
required dependency, build-script, or proc-macro change for human
review rather than silently expanding scope.
2. Event-graph layer (src/event_graph)
2.1 Define EventPutStatus/EventPutResult/NackReason in
proto.rs with explicit u8 discriminants, impl_p2p_message! with
default metering, and register dispatch/subscription in
ProtocolEventGraph::init. Verify wire tags with round-trip and
explicit-byte tests without modifying canonical serialization code;
run make and make clippy.
2.2 Emit statuses from handle_event_put at every outcome per the
design table (NotSynced, Has{false} duplicate, historical-slot check
before TooOld, Invalid, Busy, Has{true} inserted), unicast on the
receiving channel; strike/flood paths unchanged and silent. Verify
each emission point with a two-node test asserting the exact reply
variant, including the retained-slot Has{false} case across a
rotation. Distinguish established invalidity (Invalid) from
transient parent-fetch/processing failure (Busy) in tests.
2.3 Add receipt_pub: Publisher<(EventPutStatus, ChannelPtr)> and
receipt_subscribe() to EventGraph; republish every inbound status
unfiltered from the per-channel handler. Verify with a test that
receives both own-origin and relayed statuses on the subscription.
2.4 Decode hardening: unknown EventPutResult/NackReason
variant or malformed body is dropped with a warning, no panic, no
strike, channel stays connected. Verify with a fuzz-style unit test
feeding truncated/random payloads through the decoder and a channel
test confirming the connection remains usable after malformed input.
3. Durable darkirc FIFO (bin/darkirc)
3.1 Add the darkirc_outbound ordered logical-message records and
durable enqueue/head/dequeue operations, with plaintext rebuild
fields, stable queue position, optional active event/blob, generation
links, and retry/parked state. Verify serialization, concurrent
enqueue ordering, and reopen/restart preservation with local tests.
3.2 Route every accepted outgoing chat message through durable
enqueue, including offline and initial-sync sends. Report enqueue
failure explicitly; do not create events for later entries. Verify
that accepted messages survive restart, failed enqueues do not report
success, and neither direct broadcast nor DAG relay/sync exposes a
later queued message.
3.3 Persist the head's exact event/blob independently of DAG
retention, and commit replacements with the active-generation pointer
and old-to-new superseded_by link before network exposure. Verify
fault-injected persistence failures, restart before/after commit,
unchanged rebroadcast after all local slots prune the event, and one
active generation at the original queue position.
3.4 Enforce a storage bound covering queued plaintext, active
event/blob data, and generation metadata. Explicitly reject new
enqueues at capacity; park recreation if it cannot fit. Verify no
unacknowledged entry or required correlation data is evicted, and
ACK'd entries can be removed to reclaim queue space.
4. ACK-driven head-only worker (bin/darkirc)
4.1 Subscribe to receipts and accepted foreign events; filter to
tracked head generations and use ephemeral connection identity, not
channel addresses, for any aggregation. Verify ACK from both Has
variants and foreign ancestry, and no ACK from locally generated
events or unrelated ids. Do not persist or log peer addresses.
4.2 Serialize ACK/dequeue with head materialization and recreation.
Verify exactly-once durable advancement, ACK processing while sends
are gated, duplicate/late replies after restart, and an old-generation
ACK racing with replacement work without resurrecting the entry or
removing the next head.
4.3 Service only the head when synced and connection count reaches
K. Materialize its initial event only then; otherwise retry its exact
active event with doubling backoff up to R_MAX, then a capped slow
rate indefinitely. Verify with controlled-time tests that negative
replies cannot bypass backoff, no retry/lifetime limit discards the
head, and later entries never create or expose events before ACK.
4.4 Recreate only after local expiry or TooOld and a completed
rebroadcast round without ACK. Keep queue position, use fresh
parents/timestamp/nonce and the reviewed existing RLN path, and retain
old-generation correlation. Verify silent expiry, retained-slot Has
cancellation, multiple rotations without an attempt cap, and no
recreation from silence/Invalid/NotSynced/Busy alone.
4.5 Park the head on budget exhaustion, missing identity, and
processing/storage errors; retry at bounded rate without skipping it.
Verify enabled-RLN budget rollover and identity recovery under the
human-reviewed path, unchanged retries consuming no new slot, and no
unproven enabled-RLN replacement. Verify blocked-send notices do not
imply dequeue or terminal failure, and later messages remain queued.
5. End-to-end FIFO scenarios
5.1 Test offline enqueue of A then B, restart, and reconnect in a
multi-node harness with the configured connectivity threshold met.
Assert only A materializes/sends, B stays unexposed until A's ACK,
and B subsequently becomes the head. Repeat with A parked to confirm
cross-conversation head-of-line blocking rather than implicit skip.
5.2 Test an already-materialized, unacknowledged head spanning
disconnection and rotation: first rebroadcast the original, then
recreate without advancing the queue if no holder ACKs. In a separate
scenario a peer retains the original and replies Has{inserted:false}:
assert dequeue without recreation. Include a late ACK for an older
generation after replacement and verify the next message advances
only once. Do not assume recipient display order or deduplication.
6. Hardening and review gates
6.1 Full workspace gates green: make, make clippy, make test
(proofs + contracts built first per AGENTS.md); confirm no
unwrap/expect/panic! on any new attacker-controlled decode path
and no secrets or peer addresses logged with queue/receipt state.
6.2 Invoke @anon-security-review on the full implementation diff;
treat FAIL as
blocking and address findings before marking the change ready to
apply/archive. Verify the review verdict is recorded in the change
notes; planning-only review does not satisfy this implementation gate.