The file boundary was the first fix.

post 006 (One Idea Per File) was right: hardware, sky, ground, and routing cannot be allowed to melt into one lab definition. If the second run changes the constellation and the terminal range and the ground exits, the measurement has no clean name. That was true in the first LEO sessions, and it is still true.

post 007 (The YAML Is The Contract) was right about the handoff.

The runtime should not care whether a YAML file came from a text editor, a wizard, or a generator in CI. NodalArc reads YAML, resolves references, and hands the OME, scheduler, node agents, addressing code, and routing setup one object graph.

Those ideas held.

The first object shapes did not.

The early split was shaped by the LEO test stand: satellite type, constellation, ground station, station set, session. That got the lab moving. It gave the first experiments names the reader could understand.

Then the catalog widened.

A ground station stopped being a good enough word once the place might be on Luna. A satellite type stopped being a good enough object once router platform, radios, payload slots, and motion needed to change independently. A constellation stopped being the center of the run once GEO slots, lunar relays, and surface facilities had to sit beside a generated Walker shell.

The old shape does not explode when that happens. That is why the problem is easy to miss. The parser still reads the file. The wizard still has something to show. The run still starts.

Only the measurement gets weaker.

NodalArc was always aimed beyond one LEO constellation. LEO was the proving ground because it is fast, public, and unforgiving. A satellite at 550 kilometers altitude moves around 7.5 kilometers a second. Handover is not an edge case. Motion is the normal case.

That made LEO the right place to prove the first configuration model. Multi-body work exposed what the first model had been allowed to imply.

Where it broke

The first place the old shape broke was the physical frame. In the first LEO runs, Earth was the only body that mattered, so it was easy to treat the planet as background. That stops working as soon as Luna enters the session. Orbits, surface placement, occlusion, and propagation all depend on body facts. Earth and Luna cannot have different body shapes in the catalog, with one carrying equatorial and polar radius and the other carrying only mean radius. The calculation has to receive the same kind of physical fact no matter which body it is working against.

The same problem showed up in terminals. A terminal is not just a label on a link rule. It is the physical communications capability the emulator uses to decide whether a link can close. If one terminal file uses a single bandwidth number, another uses transmit and receive bandwidth, and another hides capability in a free-form string, the runtime no longer has one meaning for "terminal." Range, tracking capacity, field of regard, medium, and directional bandwidth have to live in the terminal object because they are the limits the link rule has to survive.

Placement forced the next split. A router platform is reusable until it is placed. The same node model might be used as a spacecraft router, a GEO relay router, a ground router, or a lunar surface gateway. Those placements are different facts. A node becomes a real runtime node only when a site installs it, a constellation generates it, or a space-node definition places it. If the node already knows where it lives, then changing orbit, facility, or body means editing the platform instead of editing the placement.

That is the reason the grammar became more formal. The first shortcuts were useful while the lab was small. At multi-body scale, those shortcuts become hidden runtime rules.

The objects we needed

A Body owns the physical frame: gravitational parameter and radii. Earth and Luna have the same required body fields because the runtime uses the same kind of fact for both. An orbit needs a body. A surface site needs a body. Occlusion needs a body.

A Terminal owns physical communications capability: medium, signal, directional bandwidth, tracking capacity, maximum range, and angular limits. It does not own role. The same optical terminal class can be mounted for an inter-satellite link in one node and an inter-body relay in another. Role belongs to the mount.

An Orbit owns motion around a body: epoch, shape or elements, orientation, phase, and propagator. It is reusable because the same router platform can fly in different regimes, and the same orbital regime can carry different router platforms.

A Node is the reusable network platform before placement. It may be a ground router, spacecraft router, relay router, or surface gateway router. It owns forwarding class, ethernet ports, terminal mounts, payload mounts, tags, and references. It is not in Denver, GEO, or lunar orbit until a site, constellation, or space node places it.

A Site is a named placed facility. It is not a town. Goldstone is a site. Svalbard means the SvalSat plateau, not Longyearbyen as a convenient dot on the map. A site owns a local LAN and the nodes installed at that facility. An installed terminal can narrow the primitive's capability. It cannot improve it.

A SiteSet is a reusable collection of sites. A Constellation generates space nodes from node, orbit, planes, slots, and phasing. A SpaceNode is an individually placed spacecraft, useful for named GEO slots and relay assets. A Session assembles these parts into the run.

This is why the object split matters. If a constellation contains ground policy, changing ground exits means editing the sky. If a terminal contains role, the same physical device cannot be reused cleanly in a different mount. If a session contains a private terminal shortcut, the runtime has two terminal shapes to reconcile.

LEO proved the pressure

NodalArc did not become cislunar after the first LEO work. That was always the target. LEO was where the cost of being wrong was low enough and the motion was violent enough.

When the grammar only had to describe one LEO shell, shortcuts could hide. When the same model has to describe two Earth LEO shells, a MEO relay layer, GEO gateways, a lunar orbiter, and a named site on the lunar surface, those shortcuts turn into runtime behavior.

That is where the old shape runs out of room.

FIG.01 - Scope map LEO IS THE TEST STAND
EARTH LEO MEO GEO HEO SURFACE SITE LUNA INTER-BODY CANDIDATE LINKS THE SAME SESSION SHAPE HAS TO DESCRIBE ALL OF THIS WITHOUT HIDDEN PER-REGIME RULES
LEO proves fast-moving network behavior. The same object model has to describe the larger target: multiple regimes, multiple bodies, and inter-body paths.

A constellation is one assembly

A constellation combines a Node and an Orbit into many placed space nodes. It says this router platform flies this orbit, in this many planes, with this many slots, with this phasing.

That is one assembly. It is not enough for the session.

A GEO relay may be a small set of named positions, not a generated shell. A lunar relay may be one placed spacecraft before it becomes a constellation. A surface base is not a constellation at all. The session still has to put those objects in the same run and let link rules test whether they can talk.

That is where the first LEO shape ran out. It treated the constellation as the main object and everything else as supporting material. Multi-body sessions reverse the pressure. The session becomes the assembly point, and the constellation becomes one source of nodes among several.

Segments give the session shape

The session uses segments to name the pieces of the world that will become runtime nodes. A segment can come from a constellation, a set of individual space nodes, or a placement of ground sites. The segment id becomes the namespace source. That matters when two different constellations both contain a local node named sat-01. Runtime identity needs an authored boundary.

session:
  name: earth-leo-geo-luna-reachability
  display_name: Earth LEO/GEO to Luna reachability

segments:
  - id: earth_leo
    source: nodalarc:constellations/earth/leo/earth-leo-starlink-36.yaml
    tags: [earth, leo, access]

  - id: earth_geo
    source: nodalarc:space-node-sets/earth/geo/earth-geo-relays.yaml
    tags: [earth, geo, relay]

  - id: luna_llo
    source: user:constellations/luna/llo/luna-llo-relay-8.yaml
    tags: [luna, orbit, relay]

  - id: luna_surface
    placement:
      from_site_set: user:site-sets/luna/artemis-surface-sites.yaml
    tags: [luna, surface]

This is not formatting. It keeps the runtime from guessing. A node in earth_leo and a node in luna_llo may both be routers, but they are not in the same place, not under the same delay, and not in the same routing situation.

Once the session names its segments, link rules can describe candidate relationships between them.

The rule permits. Physics decides.

Link rules are where terrestrial instinct can mislead. A NodalArc link rule does not create a link.

It declares a candidate relationship. It says the emulator is allowed to consider links between two selected endpoint sets, using compatible terminals. The emulator still has to run the physical tests: range, body occlusion, field of regard, tracking capacity, terminal allocation, and elevation masks.

link_rules:
  - id: earth_luna_bridge
    topology:
      mode: nearest_n
      n: 1
    endpoints:
      - select:
          segment: earth_geo
        terminal:
          all:
            - role: crosslink
            - medium: optical
      - select:
          segment: luna_llo
        terminal:
          all:
            - role: crosslink
            - medium: optical
    class: inter_body

That rule does not say an Earth GEO relay is always talking to a lunar orbiter. It says those two sets are allowed to try. At a given simulation time the emulator still has to answer the real question. Is the geometry open? Is the terminal pointed where it can point? Is another link already using the only tracker? Does the declared terminal range cover the path?

Across bodies, that distinction stops the config from claiming a link exists when the physics only allows a candidate.

Cislunar is not long LEO

A LEO access hop is a short argument with geometry. A cislunar path is a different class of thing. The distance can be hundreds of thousands of kilometers. The one-way light time is not a rounding error. Earth and Luna can both occlude paths. The useful relay may not be the nearest node by ordinary graph distance.

That does not make terrestrial routing knowledge useless. It makes the substrate different. The packet still needs an interface, a next hop, a forwarding table, and policy. The trouble is that the physical truth under those things no longer behaves like a fixed network with occasional failures.

Routing is above the world

Routing domains belong in the session, but they do not define the physical world. They consume it.

An Earth domain can run one protocol. A lunar domain can run another. A boundary can export summarized reachability over the Earth-Luna bridge. That boundary references the physical rule by id. It does not turn the inter-body link into an ordinary IGP adjacency by accident.

routing:
  domains:
    - id: earth_domain
      protocol: isis
      selectors:
        - any:
            - segment: earth_leo
            - segment: earth_geo
            - segment: earth_ground

    - id: luna_domain
      protocol: isis
      selectors:
        - any:
            - segment: luna_llo
            - segment: luna_surface

  boundaries:
    - over: earth_luna_bridge
      adapter: static_ip
      export:
        - from: earth_domain
          to: luna_domain
          prefixes:
            aggregate_of: advertised_connected
        - from: luna_domain
          to: earth_domain
          prefixes:
            - 172.24.0.0/22

That split is the difference between emulating a world and drawing a clever topology. The physical layer says what may be reachable and what it costs in latency, bandwidth, loss, and state. The routing layer says what each domain is allowed to learn across that physical possibility.

Mix those two together and the experiment stops having a clean name.

The first model pointed here

The earlier YAML posts were not a detour. They were the first version of the discipline.

One idea per file was right. The session as the runtime boundary was right. The wizard and generator feeding the same artifact was right. The first implementation pressure came from LEO: one constellation, one planet, and a small set of ground exits. The larger target puts the same discipline under more load.

More constellations. More bodies. More orbital regimes. More named facilities. More terminal roles. More routing domains. More chances for a configuration file to say something the emulator cannot truthfully do.

The answer is not to make every new regime a special case. That is how hidden behavior gets into a lab.

The answer is a grammar that makes those boundaries explicit before the run starts.

What's next

post 011 (The Grammar Had To Grow) looks at the mechanism. The session can now describe more than one kind of world, so examples and convention are not enough. The grammar has to keep terminals, nodes, sites, constellations, segments, and routing boundaries from melting into each other.