Repository navigation
docs: an edge site is a Thing, not a leaf_nodes record - #6
Merged
Merged
Conversation
Follows the platform change that dropped the `leaf_nodes` collection and the `leaf-sync` binary, and the agent change that absorbed the latter. leaf-nodes.md is rewritten rather than edited. It used to describe a collection, a per-site agent and a config mirror; all three are gone, and what replaces them is one route (GET /api/me/leaf-config) plus the reasons the alternatives were rejected -- no gateway flag because thing_types already says what a device is, no stored `domain` because it was a second copy of the code that could disagree with it, no config mirror because nothing consumed the mirrored rows. Two things worth keeping that were only in the old cmd/leaf-sync README: - The two operator-mode directives a generated nats-leaf.conf must carry (a leaf remote's `account` key, and the $SYS account JWT in resolver_preload, without which the server dies before JetStream starts) -- and the distinction between preloading the $SYS *account* JWT, which grants nothing, and a $SYS *user* credential, which is never served. - One writer per bucket for the digital twin, with the number that made the case: ~170k writes to a single key in 300ms when both ends wrote one bucket. New in §7 of leaf-nodes.md: site connectivity comes from $SYS.REQ.ACCOUNT.PING.CONNZ, asked by the console over its own in-account connection, with the publish-DENY-beats-ALLOW trap written down next to it -- that one surfaces as a bare request timeout, so it is the failure someone re-tightening a NATS Role would otherwise spend a day on. authorization.md §6 is rewritten for the same reason and keeps the point that mattered: the route gates on nothing, because everything it serves is public trust material or the caller's own credential, and the blast radius of a leaked edge credential is a fixed list of named fields rather than a consequence of rules that change for unrelated reasons. agent.md drops the "not to be confused with leaf-sync" note and gains the four edge capabilities; it also corrects two claims that had gone stale before this change -- the Agent does manage Nebula now, in-process. ADR 0002 is annotated rather than edited: it cites leaf_nodes as the precedent for freezing `code`, and an ADR records what was argued at the time. The note points at things.code as today's precedent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Sep 16, 2026
Two errors, both of which would have been read as fact by someone configuring a deployment. **"No listening ports."** agent.md said the Agent initiates all connections outbound and listens on nothing. That was true once. It is not true now: the platform block talks outbound HTTPS, a site gateway hosts a nats-server that local devices connect in to, and /ready + /metrics bind 127.0.0.1:9100 on every agent by default. Replaced with the property that is actually true and is the one a device on a customer network depends on -- nothing can instruct an Agent except over the NATS connection it dialed itself, so no port forward is ever needed to manage one. New §6 carries a direction-and-port table for whoever writes the firewall rules, including the detail that an ordinary Nebula host binds an ephemeral port (pb-nebula writes listen.port: 0 for anything that is not a lighthouse or a relay), so there is nothing to open for the overlay either. **observability.addr defaults to 127.0.0.1:9100, not "".** configuration.md and health-metrics.md both documented the default as empty and the feature as off by default; the agent's defaults.go sets the address, so the listener is up unless you set the key empty. Both corrected, and both now note that 9100 is node_exporter's own port on Linux and FreeBSD -- these same docs offer that exporter as an alternative metrics source, and a bind failure there is logged rather than fatal, so the symptom is a scrape target that quietly never came up. health-metrics.md's scrape example already used 9101 while the prose said 9100; the example was right and now says why. Also: agent.md listed local health as one of four gateway capabilities. There are three. observability is on for every Agent -- the reason to answer locally has nothing to do with running a leaf node -- and nebula.enabled is per-device in the same way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows stone-age-io/platform, which dropped the
leaf_nodescollection and theleaf-syncbinary, and stone-age-io/agent, which absorbed the latter.leaf-nodes.mdis rewritten, not editedIt used to describe a collection, a per-site binary and a config mirror. All three are gone. The filename stays so inbound links survive.
What replaces it is one route —
GET /api/me/leaf-config— plus the reasons the alternatives were rejected, which is the part worth having in docs:thing_typesalready says what a device is and a second marker is a second thing to get wrong;domain, because it was a second copy of the code that could disagree with it, and when it did the site simply stopped appearing;Two things were rescued from the old
cmd/leaf-syncREADME before it was deleted, since they existed nowhere else:nats-leaf.confmust carry — a leaf remote'saccountkey, and the$SYSaccount JWT inresolver_preload, without which the server dies before JetStream starts — and the distinction between preloading the$SYSaccount JWT, which grants nothing, and a$SYSuser credential, which is never served.New in §7: site connectivity comes from
$SYS.REQ.ACCOUNT.PING.CONNZ, asked by the console over its own in-account connection, with the publish-DENY-beats-ALLOW trap written down beside it. That one surfaces as a bare request timeout with the real reason arriving only on the async error handler, so it is the failure someone re-tightening a NATS Role would otherwise spend a day on.The rest of the pass
authorization.md§6 rewritten as "Gateways and the Edge", keeping the point that mattered: the route gates on nothing, because everything it serves is public trust material or the caller's own credential — so the blast radius of a leaked edge credential is a fixed list of named fields rather than a consequence of rules that change for unrelated reasons. Theleaf_nodesrows come out of the role table.agent.mdloses the "not to be confused withleaf-sync" note and gains the four edge capabilities. It also corrects two claims that were already stale before this change: it said the Agent "neither fetches nor manages Nebula" and "does not manage the Nebula interface". Both have been untrue since the overlay feature landed.health-metrics.md§5 rewritten for the agent'sagent_edge_*series and its two checks (not four), with the alert expressions updated to match.configuration.md,connectivity.md,index.md,getting-started.md,operations.md,platform-ui-entities.md,overview.md,platform-layers.mdupdated for theplatform:config block,auth.type: "platform", andplatform.sync_interval.operations.md's failure-mode and upgrade-order tables now say that restarting the agent on a site bounces the leaf server only ifnats.server_configis set.ADR 0002 is annotated, not edited
It cites
leaf_nodesas the precedent for freezingcode. That is what was argued at the time, and an ADR is a record of that argument — rewriting it would erase the decision it exists to document. A status note points atthings.codeas today's precedent instead.Verification
All internal links resolve across 21 files — target file exists, and every
#anchormatches a heading slugified the way mkdocs (python-markdown's toc extension) does. That check caught two broken anchors, one of them written during this pass.Merge with platform: stone-age-io/platform#11 and agent: stone-age-io/agent#4 — the three land together.
🤖 Generated with Claude Code