> Source: https://nexusatlas.dev/docs/3.0.0/concepts/identity — Nexus Atlas developer documentation (Concepts). Converted from the HTML page; the page is canonical.

# Identity and authorisation shipped

Without a fleet list, an Atlas node is its transport key: the key is the node's id in the routing database, in the mesh roster and in every snapshot, and any admitted node may do anything. With `[auth] provider = "fleet"`, a node is a **record**: a stable id and a name that hold keys for a while and carry the node's permissions. This page covers the record, how its keys rotate, the capability flags it carries, how a new node is admitted, how a node is removed — by name, by area or by a signed wipe — and how routing messages are authenticated.

## The node record

Every record in the fleet list has the same fields:

| Field | What it holds |
|-------|---------------|
| node_id | A UUID minted once by atlasd keygen --identity. On the wire the node id is BLAKE2s-256 of it; snapshots and the dashboard show the short form, e191..81b6. |
| name, roles | A DNS-safe name, unique in the fleet, and free-form roles (operator, uav, sensor). |
| allowed_ips | The tunnel addresses the node may use. |
| [node.capabilities] | The four capability flags. |
| [[node.keys.transport]] | X25519 public keys, each with valid_from and valid_to in Unix seconds (0 = open-ended). At most two may be valid at any instant. |
| [node.ext] | Optional record extensions under short keys, signed with the rest of the record — the first is interconnect. |
| [[node.keys.signing]] | Ed25519 public keys, same windows: they sign the node's dashboard token and, with config_author, configuration. |

The records of a fleet travel together as one **fleet list**. `atlasd fleet sign` stamps it with a sequence number, a timestamp, the author's key and an Ed25519 signature over canonical bytes (sorted-key JSON of the parsed list, so the TOML and JSON forms sign identically). A node accepts a list signed by an anchor in `config-authors.toml`, the same anchors that sign config epochs, or by a `config_author` record of the list it already holds, and only when its sequence number is above the node's high-water mark for that fleet. The bootstrap copy and the cached copy are verified again on every load; a node that cannot verify its list, or whose own key has no record, refuses to start.

**/etc/atlas/config.toml — a record-fleet member**

```
[interface]
node_id     = "af2e580d-5365-4b5f-acfa-9a9da1f69e73"   # the record UUID
private_key = "…"                                      # current X25519 key
signing_key = "…"                                      # Ed25519 seed
# next_private_key = "…"                               # during a rotation

[auth]
provider   = "fleet"
fleet_list = "/etc/atlas/fleet-list.toml"              # bootstrap copy
```

**The list travels over sessions.** The file at `fleet_list` only seeds a node at start. After that, every session that comes up is offered the list its peer holds, and a node that adopts a newer list offers it to every other live peer, hop by hop. A list is read only from a live, admitted session, and adopted only when it verifies and is newer; the journal records `identity.fleet_list_adopted` or `identity.fleet_list_rejected`. To publish a new list, place it at the `fleet_list` path of any one node and restart that daemon; the rest of the fleet receives it from there.

**No record, no entry.** A key without a valid record gets no session, whether it came from a `[[peer]]` block, mesh discovery or nowhere. The handshake is refused, counted in `identity.refused_no_record` and journalled as `identity.no_record_refused` once a minute per key; its adverts are not accepted and nothing it sends is forwarded. A mesh member is accepted only as the record its key belongs to. Two rules protect routing in every fleet, with or without records: a link-state advert is processed only when it arrives on a live, admitted session (anything else counts `lsa_no_session`), and a link between two nodes is used only when both nodes' adverts list it (one-sided claims count `lsa_one_sided_links`).

The routing database, the mesh roster, epoch targeting, routes (`routes[].next_hop`) and every snapshot key on the record's node id. A peer is looked up by node id; its key is just what it proves in the handshake.

## Rotation with overlap

The fleet-wide schedule — publish, activate, retire, with the retire step gated on the required nodes and a lifeline for stragglers — is under [Fleet configuration: rotation](https://nexusatlas.dev/docs/3.0.0/concepts/fleet-config#rotation); this section is the per-node mechanism it rests on.

A node holds two transport keys during a rotation: `private_key`, which it initiates handshakes with, and `next_private_key`. It answers a handshake addressed to either. Its record lists both public halves, and validation refuses a record with three valid at once:

```
$ atlasd fleet check --file fleet-list.toml
  error: node `drone`: 3 transport keys are valid at once around 0 — a node holds at most 2 (current and next)
fleet `field-1` seq 2: 4 records, 1 error(s), 0 warning(s), signature does not verify against the anchors
```

When the node starts initiating with its next key, the peer that receives the handshake finds the key in the same record and **rebinds the existing peer entry** to it rather than creating a new one: the same node id, endpoints and link-monitor history, journalled as `identity.peer_key_changed`. Routes and topology do not move. End-to-end sealing resolves the destination's node id to its record's transport key (the valid key with the earliest `valid_from`), and the node opens sealed traffic on either of its two keys through the overlap, so sealed traffic keeps flowing. In a record fleet only a key on the record can open traffic sealed to that node.

Signing keys rotate the same way on the record side: list the new key beside the old one, switch the node's `signing_key`, then drop the old entry. The node holds one signing key at a time.

The whole procedure, with commands, is in [Rotate a node's key without a flag day](https://nexusatlas.dev/guides/key-rotation).

## Capability flags

Each record carries four flags. They belong to the record, not to a key, so a rotation keeps them. Every flag the record leaves out takes its least-privilege default, which is also what `atlasd fleet add-node` writes unless told otherwise.

| Flag | Default | Enforced where |
|------|---------|----------------|
| relay | false | Routing on every node, the node's own forwarding, and its neighbours' forwarding · counter caps.relay_refused |
| classes | Telemetry, Position, Bulk | QoS ingress on the sending node and on its first neighbour · counter caps.class_clamped; and at every forwarding hop after them, against the origin in the 12-byte relay header · caps.class_clamped_transit, caps.origin_unrecorded for an origin no record covers; under [crypto] e2e the destination refuses an upgraded class or a changed origin · e2e.class_tampered |
| config_author | false | Signature checks on config epochs and fleet lists |
| dashboard | own | The web API's node-token check (none, own or fleet) |

**`relay = false`.** Shortest-path routing reaches the node but never expands it, except as the origin of its own traffic (it still roots its own multicast trees), and top-K multipath never uses it as a first hop toward anyone else. Every node computes this from the same fleet list, so the whole mesh routes around it consistently. A node whose own record forbids relaying refuses to forward. A neighbour drops a relay-framed packet that a non-relay node forwarded — one whose hop count shows it was already relayed, or whose source is not that node (the sealed sender key, or the clear source address) — and counts it. Traffic the node itself originates is never affected and travels any number of hops.

**`classes`.** Any of `Control`, `Voice`, `Position`, `Telemetry`, `Video`, `Bulk`, highest priority first. At QoS ingress — the node's own classification, and the class byte of traffic a neighbour originated when the receiving node runs QoS — a class the record does not list is clamped to the highest-priority listed class below it, or to the lowest listed class when every listed class ranks above it. A sensor with the default classes that marks a packet `Control` sends it as `Position`; an observer allowed `Voice` and `Position` that sends `Bulk` sends it as `Position`. The check runs at the origin and at the first hop; nodes further along carry the class those two settled.

**`config_author`.** The record's valid signing keys are accepted as authors of config epochs and fleet lists, beside the anchors in `config-authors.toml`. `atlasd fleet check` refuses the flag on a record without a signing key and warns when the record's roles do not include `operator`.

**`dashboard`.** In a record fleet the node token is node-bound: `n1.` followed by base64url of the node id, the five-minute window and an Ed25519 signature by the node's `signing_key`, verified against the record's signing keys. The *reading* node's flag decides: `fleet` reads any member, `own` only the node that minted the token, `none` nothing. Mesh-secret tokens are not accepted in a record fleet. `atlasd config node-token`, the fleet proxy, fleet health and the crash pull mint the node-bound form automatically. The token matters where reads are gated, on a node running `[web] protect = "all"`; dashboard accounts and passkeys are a separate gate and are unchanged.

A fleet without a fleet list has no records: every node holds `relay`, every class and `dashboard = "fleet"`, and configuration authors come from `config-authors.toml` alone, as before. Worked records for a ground station, a sensor and a partner are in [A least-privilege fleet](https://nexusatlas.dev/guides/least-privilege).

A worked deployment with records and with the command hook — two hubs, one network per customer, aircraft admitted from a ground station's own database and removed for good — is in [A cellular fleet behind a web ground station](https://nexusatlas.dev/guides/web-gcs-fleet).

## Record extensions shipped

A record grows through its extension area, `ext`: short string keys mapped to values, covered by the list signature like every other field. A node keeps every key it receives, known or not, and the list verifies with them as they are, so a record can carry a key an older build of the same line does not read. A record holds at most 32 keys of at most 32 characters each. In the authoring TOML a key is a table under its `[[node]]`; in the JSON form of the list (the wire and the cache) it sits under `"ext"`.

The first key, `interconnect`, says what the node may import and export as an [Atlas Interconnect seam host](https://nexusatlas.dev/docs/3.0.0/concepts/interconnect#record): `may_import` lists the routes and mapped `local` addresses it may announce from another network, `may_export` this network's hosts it may expose. Deny by default — a record without the section may import and export nothing, and anything is written `0.0.0.0/0`. An entry is allowed only when it lies entirely inside one listed prefix; a wider one is refused whole, not narrowed.

**fleet-list.toml — a seam host's record**

```
[[node]]
name = "op-a"
node_id = "…"
allowed_ips = ["10.0.101.1/32"]

[node.ext.interconnect]
may_import = ["10.0.9.0/25", "10.0.101.130/32"]
may_export = ["10.0.101.0/24"]
```

**the same record in the list's JSON form**

```
"ext": {
  "interconnect": {
    "may_import": ["10.0.9.0/25", "10.0.101.130/32"],
    "may_export": ["10.0.101.0/24"]
  }
}
```

[atlasd fleet set-interconnect op-a --may-import 10.0.9.0/25,10.0.101.130/32 --may-export 10.0.101.0/24](https://nexusatlas.dev/docs/3.0.0/cli#cmd-fleet-set-interconnect) writes the section, `--clear` removes it, and `atlasd fleet sign` then `atlasd fleet push` publish the list. `atlasd fleet check` refuses more than 32 keys, a key over 32 characters and a section that does not parse, and warns when either interconnect list is empty ("this node may not act as a seam host"). Every member checks a seam host's adverts against this section, the seam host applies it in its own data path, and `atlasd config check` refuses a route, map or export outside it.

> **Publishing the first record with an extension.** A list without any extension is written exactly as before. A list in which any record carries one cannot be verified by nodes on release 3.0.0 or older: they keep the list they hold and count a signature refusal. Publish the first such list once every node runs a build with record extensions.

## Admission modes shipped

A record normally reaches the list from the operator host. Four admission modes let a node in without that step, each with its own trust root; they are configured in `[auth]` and worked through in [Admit nodes by pairing code, certificate or approval](https://nexusatlas.dev/guides/admission-modes).

| Mode | What admits the key | What the node gets |
|------|---------------------|--------------------|
| Invitation — fleet invite, [auth] invite_token | A 40-byte token in the v=3 pairing code: id ‖ expiry ‖ BLAKE2s-MAC(invite secret, id ‖ expiry ‖ capabilities ‖ binding), the binding a digest of the hub's key, the fleet's anchors, the config authors and both tunnel addresses the code carries; verified and spent by the node that minted it, which then confirms the code over the session so the carried anchors count | A record minted for the key its handshake proved, with its own UUID and signing key and the invitation's flags — least privilege unless raised |
| Certificate — fleet cert, [auth] cert_file | A record signed by an anchor or a config_author record, at most 940 bytes, optional expiry | The certificate's flags on every node that trusts the authority, with no list entry; never config_author |
| Key + PSK — [auth] psk, psk_file, a record's psk_id | A psk_tag = BLAKE2s-MAC(psk, every init byte before it) ahead of mac2, and Noise IKpsk2 | Nothing on its own: it is a second factor in front of whatever else admits the key |
| Pending — [auth] pending = true | An operator's approval of a parked knock (any provider) | A record with the operator's flags and address |

**The hello.** Every HandshakeInit carries a hello inside its encrypted payload — flags, the name the node calls itself, its record UUID, signing key and a signature proving it holds both, and the invitation token or certificate when it has one. A node that mints a record mints it with the key the handshake proved, the UUID and signing key the hello proved, and never anything the hello merely asserts.

**Minting.** Minting is serialised, so a single-use token presented from two keys, or on two links, at the same instant admits one node. A spent, expired or withdrawn token admits nothing (`admission.expired`), and a UUID or key the list holds or has revoked is refused without spending a use. A node that can sign the list — its own record is a `config_author`, or it holds the trusted config-author key — signs the next list with the new record and floods it; any other node keeps a local record that admits the node there and [forwards it to an author](https://nexusatlas.dev/docs/3.0.0/concepts/identity#forwarding).

**Joining.** A record-fleet node started with an invitation or a certificate but no `fleet_list` runs `joining`: it knows itself by its record id, signs what it floods, admits its configured peers until a list arrives, and adopts the first list signed by an anchor or by the `config_author` record whose transport key is the pairing code's `k=`. From then on it enforces records like every other member (`identity.mode` goes `joining` → `fleet`). A record-fleet node with neither a list nor an invitation or certificate refuses to start.

**Certificates travel.** The admitting node offers an accepted certificate on over its sessions (the fleet-list message carries `{"cert": …}`), so every member learns the record and verifies the certified node's signed adverts. Revocation is the list: a certificate whose id or keys the list revokes is refused (`admission.cert_refused`); `fleet revoke --cert` revokes one that has no list entry.

**The PSK check.** With only a fleet-wide PSK the tag is checked before any Diffie-Hellman; with named keys, right after the initiator — or the record its certificate carries — is known. A missing or wrong tag is dropped without any answer, not even a cookie, and counted in `admission.counters.psk_dropped`. A pair whose records name a `psk_id` uses the lower node id's key.

**The queue.** With `pending = true`, a key that fails every other check is parked with its source, claimed name, proved UUID, first and last seen and a count — rate-limited per source and capped at `pending_max` (`admission.knock`). Approve mints its record and the node's next retry gets a session without a restart; deny blocks the key for `block_secs`, dropped unanswered. Every decision is journalled with its operator: `web:<user>`, `token:<name>` or `cli:<user>`. The daemon is the only writer of the admission store; it and the invite secret are data-at-rest stores, encrypted under `[storage] at_rest`, and `atlasd zeroize` wipes `psk` and `invite_token` and shreds the invite secret.

**Forwarded to an author.** A node that cannot sign hands its queued records to a node whose record carries `config_author`, once a second and up to four per message: to a neighbouring author over the session on the fleet-list channel as `{"admit": …}`; to an author further away the same body goes end to end on the control channel (control type 0x10), routed and sealed like data, which needs `[crypto] e2e` on the forwarding node because an author takes a relayed forward only sealed. The author checks each record under its own policy: the sender holds a record in the signed list; the record has the shape a node mints (one transport key, at most one signing key, no lifeline, no `psk_id`); never `config_author`; no flag the sender lacks itself — relay, a wider dashboard role, a class, the `operator` role (`exceeds_forwarder`); no id, name or key already held by another record (`collides`); nothing the list revokes (`revoked`); and the next list must validate. Accepted records go into one next list, signed and flooded, about a second after the admission; the author answers `{"admit_ack": …}` per record — `accepted` with the sequence, `held`, `refused` with its reason, or `retry` — and the forwarding node drops its local copy once a list carrying the record is adopted. With no author reachable it retries with backoff, 5 s doubling to 5 minutes; a refused record stays local, still admitting its node there, and is not forwarded again. With `[auth] accept_forwarded = false` (default `true`) an author holds forwarded records for an operator: `atlasd fleet pending list` shows them as `forwarded … awaiting approval`, `approve` signs one exactly as minted, `deny` refuses it. The journal records `admission.forwarded`, `forward_waiting`, `forward_accepted`, `forward_held`, `forward_refused` and `forward_listed` on the forwarding node, `admission.intake_accepted`, `intake_held`, `intake_refused` and `intake_rejected` on the author, with matching counters in `admission.counters`; each local record carries its `forward` state.

## Revocation shipped

[atlasd fleet revoke](https://nexusatlas.dev/docs/3.0.0/cli#cmd-fleet-revoke) on the operator host, or the dashboard's **Remove nodes…**, takes a record (or one key of it) out of the list and lists its node id and every key it held under `revoked = [{ node_id | transport_key | signing_key, since, reason }]`. It is for good: no later list may carry a revoked id or key; re-enrolment is a new UUID with new keys. The list is signed at the next sequence number and handed to one daemon, which floods it. Every node that adopts it does four things in the same intake:

1. **Re-offers the list** to every peer, the removed node included, so it learns it is out.

2. **Evicts now** every peer whose key now resolves to no record: sessions retired, link state cleared, its adverts and roster entry purged. A discovered peer is removed outright; a configured `[[peer]]` keeps its entry but stays unadmitted. Counted `security.evicted_total`, journalled `security.peer_evicted` and `security.revoked`.

3. **Switches to a rotated mesh secret.** The list carries a fresh 32-byte secret sealed to each remaining record's transport key (X25519, HKDF-SHA256, ChaCha20-Poly1305, bound to the rotation id and the recipient). Gossip moves to it at once; the old one is still opened for 10 minutes so a node a hop behind is heard. The operator host keeps the newest secret beside its list (`<file>.mesh-secret`, mode 0600) so a later record gets its copy.

4. **Refuses the node** from then on: no record, no handshake. With `--push-relays` or `fleet push --relays` the revoked transport keys also go to the relay registry; each relay polls it and drops the key's sessions within one poll.

The removed node shows `identity.revoked_by = { seq, reason }`, and `atlasd status` prints *revoked by fleet seq N — no peer will accept this node; re-enrol with a new identity*. A peer whose record simply disappears from a newer list is evicted the same way. Within a second of the push no node holds a session with the removed node. What it already received it keeps; nothing new reaches it, and traffic captured earlier stays unreadable because session keys are ephemeral. [atlasd peer evict](https://nexusatlas.dev/docs/3.0.0/cli#cmd-peer-evict) resets one peer's sessions on demand; a still-recorded peer reconnects. The full procedure is in [Remove a compromised node](https://nexusatlas.dev/guides/remove-node).

## Removal by area, geofences and remote zeroize shipped

Three tools built on the record and the revocation above. The procedures are in [Remove nodes by area, set geofences, wipe a node remotely](https://nexusatlas.dev/guides/area-zeroize).

**Last-known positions.** Every node of a record fleet keeps the last position each node advertised, and keeps it after the advert ages out, so a node that went silent inside an area is still found there (up to 4096 entries, in memory; snapshot `area.positions`).

**Removal by area.** A polygon — `[lat, lon]` corners, or GeoJSON's `[lon, lat]` converted at the edge, 3 to 256 corners, crossing the antimeridian if it must, never winding around a pole — is resolved against those positions into a reviewable list: the records inside, each with `fix_age_secs` and whether its advert is still `live`, a count of those outside, and the records with no position, listed apart because a polygon cannot place them. The selection removes nothing. `atlasd fleet select-area --revoke`, or the dashboard's **Revoke selected**, then removes exactly the listed records through the revocation — never the node doing the selecting.

**Geofence.** A record may carry `[node.geofence] polygon = [[lat, lon], …], grace_secs, action = "isolate" | "zeroize"` (default `isolate`), signed in the list like every other record field. The node checks its *own* fix against its fence every 10 s. The first fix outside starts a grace timer (`security.geofence_outside`); back inside cancels it (`security.geofence_inside`); outside for `grace_secs` fires the action once:

- **`isolate`** — the node refuses first, announces `isolated` in its own signed status entry and flushes that gossip to every peer, then tears every session down (`security.geofence_isolated`). While it holds, every handshake either way is refused (`area.isolation_refused`) and gossip stops; peers that hear the announcement drop their side at once. Back inside, the isolation lifts (`security.geofence_released`) and the sessions return.

- **`zeroize`** — the zeroize routine below, cause `geofence`.

A node with no fix never fires its action and is flagged `no_fix`; a lost fix keeps the timer's start. The timer is persisted sealed at rest, so a restart outside the fence restores the state instead of handing out a fresh grace period; a changed fence re-arms the action but keeps the timer. Snapshot: `area.geofence {state, action, grace_secs, outside_for_secs, grace_left_secs, fired}`, `area.isolated`, and `area.fences[]` — every record's fence as this node sees it from that record's advertised position.

**Remote zeroize.** The fleet list carries `commands = [{ node_id, cmd = "zeroize", not_before, issued_at, author, sig }]`. Each command is signed on its own by a fleet author — an anchor or a `config_author` record — over the fleet id and its fields, so it cannot be lifted into another fleet's list or re-aimed, inside a list that is signed as a whole; one command per node, kept in later lists until cancelled. By default the same list also revokes the node — its id and keys, with a mesh-secret rotation, as `fleet revoke` does — so a wiped identity can never rejoin; `--no-revoke` (API: `"revoke": false`) keeps the record. The addressed node checks every second: an unknown signer is refused (`security.command_rejected`), a command not yet due is held (`security.command_pending`), a verified, due one runs — the node sets `zeroized` in its own signed status entry, flushes that gossip, destroys its store key, private and signing keys, mesh secret and web secrets, truncates every store (the geofence timer included) and exits, leaving one clear journal line, `security.zeroized`, with the cause, the signer, the fleet sequence and the times. A replayed older list never gets a command read: the high-water mark refuses the list first. Every node that hears a peer's verified `zeroized` announcement evicts it and purges its adverts and roster entry at once (`security.peer_zeroized`), and `area.commands[]` marks the command acknowledged.

## The signed control plane shipped

Hop messages are authenticated by the session; what floods is signed by its originator. Every node on the current wire, protocol 5, works this way: a fleet upgrades together, and a node speaking wire 1, 2, 3 or 4 gets no session (counted `protocol_refused`). Wire 5 adverts carry an extension area inside the signed body — a map of short keys to values, the first of them the node's [bearer kinds](https://nexusatlas.dev/docs/3.0.0/concepts/architecture#wire-versions) — which a wire-4 node could not verify. A node keeps every entry it receives, known or not, so an unknown key still verifies at the next hop, and reads only the keys it knows; an advert with more than 32 keys, or a key longer than 32 characters, is refused like an oversized one.

- **Probes, acks and keepalives** are sealed under the session's transport keys with the same nonce counter as data, with version, type and session id as associated data, and checked against the anti-replay window. One that does not authenticate moves no RTT, revives no link and points no endpoint anywhere. The 24 bytes of nonce and tag add about 6 ms to a probe round trip on a 64 kbit/s link.

- **Link-state adverts** carry `node_id`, `key_id` and an Ed25519 `sig` over canonical bytes, checked against the originator's record before the routing database sees them. Unsigned, unknown key, bad signature or no record: dropped, counted `security.lsa_sig_rejected`.

- **Gossip** carries its sender's key id and signature, and every config-status entry is signed by the node it describes, so holding the mesh secret does not let one member speak as another (`security.gossip_sig_rejected`).

- **Keys change only through the signed list.** No message from a node can add, rotate or retire its own keys. A record fleet therefore needs `[interface] signing_key` on every node, listed in its record; the daemon refuses to start without it.

- **Handshakes are rate-limited before any Diffie-Hellman:** per source (burst 32, 8/s; IPv6 by /64) and node-wide (burst 200, 100/s). Past the budget a node answers with an address-bound cookie and processes only inits that echo it, so a flood of forged handshakes cannot push out a recorded node.

## Seeing it

- `atlasd identity show` — this node's identity as the daemon resolves it at start: node id and UUID, record name, flags, each key with its validity and whether it is held here, and the fleet list's sequence number. `atlasd fleet show -c <config>` summarises the list the node runs with, with each record's `interconnect` line and any extension keys this build does not know.

- `GET /api/identity` and `GET /api/fleet` — the same over the [REST API](https://nexusatlas.dev/docs/3.0.0/api#identity), with the refusal counters.

- `GET /api/admission` — pending knocks, blocked keys, invitations without their tokens, records held outside the signed list, certified records and the `admission.counters`; `atlasd fleet pending list` and `fleet invite --list` on the command line; the dashboard's Peers tab opens with an **Admission · Pending** card.

- The dashboard: Settings shows a **Node record** card (mode, node id, keys with validity and rotation state, flags, fleet list, refusals); Peers names each peer after its record, shows its flags, and marks an unadmitted key "No record — refused"; the Fleet tab opens with the fleet list joined to the live view by node id, so a node mid-rotation stays one row.

- The Fleet tab marks removed nodes **revoked** (name struck through, reason, date) in the records table and both matrices; a revoked node shows a red banner; a strip under the list shows the control-plane counters.

- The Topology map has an **area** tool and draws every record's geofence by state; the Fleet tab shows each record's fence with a state chip and grace countdown, pending zeroize commands, a red banner while this node is isolated, and **Zeroize…** beside Remove nodes. `atlasd status` prints the geofence state and any isolation.

- Snapshot fields: `identity.{mode, node_id, node_uuid, keys, capabilities, fleet, refused_no_record, revoked_by}`, `security.{protocol, lsa_sig_rejected, gossip_sig_rejected, evicted_total, handshake_rate_limited, handshake_cookie_sent, mesh_secret}`, `peers[].{node_id_short, record_name, capabilities, admitted}`, `routes[].next_hop`, `caps.{relay_refused, class_clamped, class_clamped_transit, origin_unrecorded}`, `e2e.class_tampered`, `lsa_no_session`, `lsa_one_sided_links`.

## Boundaries

- A node's own node id is fixed when the daemon starts; a list that moves the node's key to a different record takes effect for it at the next restart.

- A key whose record is removed or revoked is [evicted](https://nexusatlas.dev/docs/3.0.0/concepts/identity#revocation) when the list arrives: its sessions end and its handshakes are refused.

- A dashboard removal signs on the node it runs on, so the operator host's authoring copy falls behind until it is pulled back with `atlasd fleet show -c <config> --json`.

- Relays take revocations from the registry, polled every 30 s by default, or from `[relay] revoked_keys_file`.

- A fleet without a fleet list has no keys to verify against: its adverts and gossip stay unsigned, and the underlay remains its trust boundary.

- A few outer-header fields used for loss accounting sit outside the data packet's associated data, so an on-path attacker can disturb loss figures; nothing can be injected.

- Signed config-status entries add about 120 bytes each, so a gossip round that carries every node's status can exceed one datagram and cross as IP fragments.

- A fleet list travels as one datagram, about 600 bytes per record, which holds a fleet of about a hundred records.

- The other network's daemon on an interconnect seam is admitted by the seam host without a record in this list — it is configured as that host's interconnect peer, and members never peer with it — while the seam host's own record bounds what it may import and export. A seam node that re-originates mapped traffic needs `relay = true` or its mapped prefixes in `allowed_ips`.

- Records, the dashboard token form and the `fleet` provider are one mode per fleet: every node in a fleet runs with the list, or none does.

- Invitations and certificates admit into a record fleet. A node that cannot sign forwards the records it mints to an author; to an author that is not a neighbour only with `[crypto] e2e`. The node it admitted adopts the author's list as its first list only when an anchor of its `config-authors.toml` (or its inviter) signed it; until then it stays `joining` — known to every other node from the list, reaching its configured peers directly. A refused record stays on the node that minted it until an operator removes it or signs it by hand (`atlasd fleet pull --with-queued`).

- Area selection and every fence state seen from another node use self-reported positions; a geofence is enforced by the node itself, so a device whose GPS is spoofed or whose software is altered does not enforce it — revoke it. Last-known positions live in memory; polygon edges are straight in latitude and longitude.

- A joining node learns the mesh secret only from a rotation sealed to its record. A certificate carries no geofence.

- The HandshakeInit is 162 bytes bare, 319 with an invitation and about 850 with a typical certificate and a token; the daemon checks at start that it stays within 1,200.
