CRUMB a card from devarno-cloud

Orbital Graph Data Model

meridian intermediate 7 min read

ELI5

The Observatory paints the protocol as a solar system: each council is a star, each agent a planet around it, each capability a moon every planet shares, doctrines are asteroids on weak orbits, and units are debris pulled toward their domain’s star. Bigger things have more connections.

Technical Deep Dive

src/lib/orbital.ts builds a single force-directed dataset by merging councils, agents, capabilities, doctrines, and units.

Class Diagram

classDiagram
class OrbitalNode {
+string id
+string label
+CelestialType celestialType
+EntityType entityType
+number radius
+string color
+string glowColor
+string? orbitParent
+string? domain
+string? council
+boolean? planned
+string? unitType
+string? status
+string? url
+Record meta
}
class OrbitalEdge {
+string source
+string target
+EdgeRelationship relationship
+number strength
+number? forceStrength
}
class OrbitalData {
+OrbitalNode[] nodes
+OrbitalEdge[] edges
+Stats stats
}
OrbitalData "1" *-- "*" OrbitalNode
OrbitalData "1" *-- "*" OrbitalEdge
OrbitalNode <.. OrbitalEdge : source
OrbitalNode <.. OrbitalEdge : target

Type Mapping

SourcecelestialTypeentityTypeid prefix
Council (active or planned)starcouncilcouncil:
Agentplanetagentagent:
Capability (from CAPABILITIES constant)mooncapabilitycap:
Doctrineasteroiddoctrinedoctrine:
Unitdebrisunitunit:

Edge Relationships

RelationshipFrom → TostrengthforceStrength override
rostercouncil → agent0.9
hasagent → capability0.50 (visual-only)
enhancesdoctrine → capability0.4
importsunit → unit0.6
belongs_tounit → council0.30 (visual-only)

forceStrength: 0 is the d3-force escape hatch: the edge renders for hover/click but exerts no physics pull, so capabilities don’t get yanked toward every agent that uses them and units don’t get sucked into their council star.

Radius Formula

radius = BASE_RADII[celestialType] + log2(1 + edgeCount) * 2.5

BASE_RADII = { star: 22, planet: 12, moon: 9, asteroid: 7, debris: 4 }. Edge count is computed during the build pass via countEdge. Visual-only edges (forceStrength: 0) still increment the count, so a high-traffic capability still grows.

Capability Filter

When walking agent.capabilities, any value not in the canonical CAPABILITIES constant is dropped (e.g. free-text strings like "search" or "summarisation"). This is enforced silently — agents may declare capabilities that are aspirational but not yet first-class moons.

Key Terms

  • Celestial type → Visual category (star/planet/moon/asteroid/debris); drives base radius and palette.
  • Entity type → Logical category (council/agent/capability/doctrine/unit); drives URL routing and meta payload.
  • forceStrength → Override for d3-force link strength independent of strength (which governs visual weight).
  • orbitParent → Hint to the renderer that a node should orbit a specific star/planet.

Q&A

Q: Why is the unit→council edge visual-only? A: Units inherit their council via domain → council lookup, and pulling every debris node toward a star would collapse the layout. The edge exists so the UI can highlight membership on hover without distorting the layout.

Q: What happens to a unit whose domain has no matching council? A: councilId is undefined, no belongs_to edge is emitted, and orbitParent is left unset — the debris floats free in the layout.

Q: Why is the radius formula logarithmic in edge count? A: A handful of high-degree nodes (popular capabilities, frequently imported units) would otherwise dominate the canvas. log2(1 + n) keeps growth visible but bounded.

Examples

A new council crucible (planned) is added with one agent and three protected capabilities. After build:

  • 1 star (council:crucible) with planned=true and the burnt-sienna palette entry.
  • 1 planet under it.
  • The three capabilities already exist as moons (added once globally, not per agent).
  • Edges: 1 roster + 3 has (visual-only). Star radius increases by log2(1+1)*2.5 = 2.5 from one outgoing roster edge.

neighbors on the map