Routing protocols were built for surprise.

A link fails. A neighbor disappears. A timer expires. The protocol detects the change, tells the rest of the network, computes new paths, and installs new forwarding state. Detection first. Reaction second. Every IGP timer you have ever tuned lives inside that bargain.

It is a reasonable bargain on Earth.

A terrestrial router cannot know that a backhoe will find the fiber next Tuesday at 14:03. It cannot know that a card will die, or a span will brown out, or a technician will pull the wrong patch cord. The router is born blind because the world gives it no choice.

Orbit gives it a different world.

A satellite at five hundred kilometers altitude is not guessing where it will be three minutes from now. Its position is a computation. The link it can form with the satellite in the next plane is not a rumor. It has a start time, an end time, a range, an angular rate, and a propagation delay. Those numbers change, but they do not change by surprise.

That changes the question.

If you knew every fiber cut in your terrestrial network weeks in advance, down to the millisecond, would you still build the network around detecting failures after they happened?

Hold onto that question. It is the experiment.

For now, NodalArc does the smaller and more honest thing. It computes the orbital future, turns that future into carrier events, and lets the router react as though a cable was plugged in or pulled out.

The router does not know the future.

NodalArc does.

The sky and the clock

post 002 (Addressing the Geometry Problem) built the pieces: satellite type, constellation, ground station, routing. Those files describe what can exist. They are the bones.

Post 003 starts the clock.

The Orbital Mechanics Engine, or OME, takes those primitives and moves them forward through time. It knows the orbital elements. It knows where the ground stations sit. It knows the terminal limits from the satellite type. It knows that a cross-plane antenna on Iridium NEXT can only track so fast.

From that, it can answer the only question that matters at any instant:

Can these two nodes talk right now?

Not should they talk. Not does the protocol want them to talk. Can they.

Line of sight. Range. Elevation. Terminal capacity. Field of regard. Tracking rate. The OME runs the physical test and produces a fact.

Sometimes the fact is simple: these two satellites can see each other.

Sometimes it is just as simple: they cannot.

Near the pole, the answer changes because the angular rate runs past what the terminal can track. The polar seam from post 002 (Addressing the Geometry Problem) is not a special rule hiding in routing logic. It falls out of the same calculation as every other link.

The antenna cannot keep up. The link goes away.

Nothing failed. The sky moved.

The OME does not publish the sky

There is a tempting bad design here.

Compute every satellite position every tick. Publish all of it. Let every other component drink from the firehose.

That would work for a toy. It is also a very expensive way to say, "the equation still works."

NodalArc does not publish the sky one frame at a time. It publishes the things other parts of the system need to act.

It publishes ephemeris, the orbital elements for the epoch. Anyone who needs a position can do the math where they stand.

It publishes clock ticks, so everyone agrees what moment of simulated time they are in.

It publishes visibility events, the appointments where links become possible or stop being possible.

It publishes link-state snapshots, so a late or restarted component can recover the current truth without replaying the whole world from the beginning.

That distinction matters. The OME owns orbital truth, but it does not become a position server for the universe. It computes the future, publishes facts, and steps aside.

A visibility event looks roughly like this:

event: VisibilityEvent
sim_time: "2026-01-01T00:05:12Z"
node_a: sat-P02S03
node_b: sat-P02S04
visible: true
link_type: isl
terminal_type: optical
range_km: 3200.4
latency_ms: 10.68

That is the concrete floor.

At this instant, these two satellites can see each other. The link is an inter-satellite link. The range is 3200.4 kilometers. One-way propagation delay is 10.68 milliseconds.

That is not a suggestion.

It is an appointment.

From appointment to carrier

A router does not understand orbital mechanics. It understands interfaces.

That is the translation NodalArc has to perform. The OME says a link can exist. The router needs to see carrier.

Between those two facts sits the Scheduler.

The Scheduler reads OME events and keeps a desired picture of the network: this link should be up, that one should be down, this live link needs a new latency value. It compares that desired picture against what is already active and sends only the necessary changes.

The Scheduler is not a little OME. It does not invent geometry. It carries the OME's facts to the place where Linux can be made to believe them.

That place is the Node Agent.

The Node Agent runs on the Kubernetes host with the privilege to touch the kernel. It uses netlink through pyroute2, creates the host-side plumbing, moves interfaces into pod namespaces, drives carrier state, and shapes delay and bandwidth with traffic control.

When the OME says two satellites can talk, and the Scheduler decides that link needs to come up, the Node Agent makes the interface real.

Inside the pod, the router sees an interface come up.

Carrier detect.

IS-IS sends hellos. OSPF sends hellos. The adjacency forms. The link enters the topology database. Routes change if routes need to change.

As far as the protocol is concerned, a cable just got plugged in.

That is the trick. Not a shortcut. Not a model of routing behavior. The actual daemon is reacting to an actual Linux interface.

The cable has weather

A veth pair by itself is a lie.

It is too perfect. Zero useful distance. No orbital delay. No bandwidth constraint. No sense that light had to cross thirty-two hundred kilometers of empty space before the packet arrived.

So the Node Agent shapes the link.

For a 3200 kilometer path, one-way propagation delay is about 10.7 milliseconds. The OME puts that number in the event. The Scheduler preserves it. The Node Agent applies it with tc netem.

Bandwidth comes from the terminal definition. If the satellite type says this optical link carries 100 megabits, the Node Agent applies that with traffic control too.

Now the cable has a length.

A few minutes later, those same satellites may be 4100 kilometers apart. The link is still up, but the delay is no longer 10.7 milliseconds. It is closer to 13.7. Nothing failed. The cable stretched because the endpoints moved.

The OME publishes the new fact. The Scheduler reconciles it. The Node Agent updates tc netem on the live interface.

The cable, while plugged in, has weather.

Terrestrial networks rarely make you care about that. A fiber between New York and Chicago has a delay, and unless someone changes the physical path, that delay mostly sits still. You might put it in a traffic-engineering database. You probably do not update it every few seconds.

Orbit does not sit still.

Two satellites in adjacent planes may move from fifteen hundred kilometers apart to forty-eight hundred kilometers apart inside one pass. That turns a five millisecond path into a sixteen millisecond path without breaking anything.

The protocol did nothing wrong.

The router did nothing wrong.

The shortest path just stopped being shortest because the geometry moved.

Whether IS-IS or OSPF should care about that is not an obvious question. TE extensions can carry delay. The daemon can flood changes. SPF can run again. But how often? At what threshold? Across how many nodes? For what traffic?

The answers are not in a textbook.

They are in the lab.

Facts, not phone calls

The OME does not call the Scheduler directly. The Scheduler does not call VS-API directly. The browser does not ask the OME to please explain the sky.

Facts go on the wire.

NodalArc uses NATS for that wire. Some facts need memory, so they live in JetStream. Visibility events, link snapshots, ephemeris, playback state. A component can restart, subscribe, and recover the current truth.

Commands are different. A command is not history. When the Scheduler tells a Node Agent to bring a link up, that is NATS request-reply. It should succeed with proof, fail loudly, or time out. It should not become a durable museum exhibit.

FIG.01 — Event bus NATS JETSTREAM · nodal.events.>
The OME publishes orbital events on a NATS JetStream subject; router, viz, alert, and archive consumers subscribe. The OME publishes orbital events on a NATS JetStream subject; router, viz, alert, and archive consumers subscribe.
The future, published as it is computed. Anyone can subscribe; the OME does not know or care who is listening.

That split keeps the pieces honest.

The OME owns orbital truth.

The Scheduler owns desired versus actual link state.

The Node Agent owns the kernel.

The router owns routing.

VS-API watches the streams and builds a picture for the browser.

No part needs to know more than its job requires. The OME does not care whether the consumer is the Scheduler, the browser console, a recorder, a measurement tool, or a future path-computation engine. It publishes the fact. The rest of the system can use it or ignore it.

That is not just an implementation detail. It is the same idea as the YAML primitives in post 002 (Addressing the Geometry Problem), moved from files into running processes.

One piece knows the hardware.

One piece knows the geometry.

One piece knows the ground exits.

One piece knows the routing.

At runtime, one piece knows the sky.

One piece decides what links should exist.

One piece makes Linux obey.

The pattern holds.

The router is still blind

There is an odd honesty in this design.

NodalArc knows the future, but the router usually does not.

In an IS-IS or OSPF session, the daemon still learns the old way. Carrier comes up. Carrier goes down. Hellos arrive. Hellos stop. The protocol reacts to the world it is given.

That is intentional.

If you want to know how a real router behaves when orbital geometry is translated into carrier, you must let the router be a router. Do not give it an oracle and then pretend you measured normal routing.

But the oracle exists.

The future is already computed. It is sitting on the bus as ephemeris, visibility, clocks, and link state. Another consumer can read the same future and do something else with it. It can plan paths before the link drops. It can install forwarding before the failure is visible. It can stop discovering the future one failure at a time.

That is a later argument.

For now, this is the important turn:

The sky can be computed.

The computation can become carrier.

The router can live inside that moving world and behave like itself.

What's next

post 004 (Between the Sky and the Kernel) goes into the narrow place between those facts: why the Scheduler reconciles instead of simply reacting, and what the Node Agent has to prove before the kernel is allowed to claim a link is real.