# Local-First Behavior

NDK treats app writes and reads as local-first when the relevant data is stored in the configured cache backend.

## Publish behavior

When an event is created through NDK broadcast flows:

- the event can be written to the cache before every relay acknowledges it
- the event can become visible to app reads from that cached state
- relay delivery can continue after the initial publish call finishes

This applies to normal events as well as targeted relay delivery used for replies, reactions, and other gossip-aware publish paths.

## Delivery state

NDK keeps delivery state in the configured cache backend.

That state includes:

- aggregate event delivery status
- per-relay delivery targets
- retry timing and retry outcome

Behavior depends on the backend:

- with `MemCacheManager`, delivery state exists while the process is alive
- with a persistent backend, delivery state also survives restart

## Retry behavior

NDK retries pending delivery in the background while the app is running.

Retry behavior includes:

- retry on reconnect when a relay becomes reachable
- periodic retry for targets that are due even if connectivity state does not change
- per-event-kind retry policy differences
- permanent failure detection for relay responses that should not be retried forever

## Replaceable events

For replaceable and addressable events:

- app reads return the latest visible winner
- background delivery follows that same visible winner
- older superseded offline versions are not kept in active retry once a newer visible version exists

## Reads after write

After a local publish, app-facing reads may show the event before every relay confirms it.

This means:

- your UI can update from NDK state immediately
- relay acknowledgement is a separate concern from local visibility
- delivery progress should be treated as asynchronous

## What this means for apps

- use a persistent cache backend if you want local-first behavior to survive restart
- treat locally visible publish as durable in the cache, not necessarily fully delivered to every relay yet
- do not assume one failed relay means the publish is globally failed
- for replaceable data, assume the newest visible version is the authoritative one
