Skip to content

The graph

SimulationGraph

Kind Core data structure — the universe
Project NextIteration.Core/Graph/
Exposes Node, Edge, AttributeValue, SimulationGraph, ReadOnlyGraphView
Mutated by the resolver only
Read by every system, the API, the harness
Status designed · Phase 1 (#28)
PLAN §2.1–§2.3, §6.1–§6.2, §7.3
Player Riverside Village

The graph is the only world state. Everything that exists is a node; every relationship is an edge; all mutable state is an attribute. The graph is the present; the past is the causal trace.

Nodes

record struct NodeId(long Value);
class Node {
    NodeId Id; string Kind;                              // location · creature · item · substance · structure · flora · faction · rule
    Dictionary<string, AttributeEntry> Attributes;       // AttributeEntry(AttributeValue Value, int Generation)
    HashSet<string> Components;                          // tags: Sentient, Combustible, OnFire, Vessel …
    string? MaterialRef; string? TemplateRef;
}
abstract record AttributeValue { Float · Int · Str · Bool · NodeRef · FloatList · StringList · NodeRefList }
  • Kind is for templates and categorisation. Systems never branch on it (invariant 1).
  • Attributes are the shared surface between systems. World vocabulary is unqualified (temperature, hunger); plugin-private is prefixed (fire.burn_progress). See World vocabulary.
  • Generation increments on every write by the resolver. It is the change-tracking primitive: the per-tick change set is (node, attribute, generation), rules fire once per generation (refraction), and the trace keys WhyChanged on it.
  • Components are tags, not data. Capability tags (Sentient, Combustible) come from templates; state tags (OnFire, Dead) are set and cleared by systems. A ComponentIndex makes NodesWithComponent(tag) O(1) in graph size.

Edges

record struct EdgeId(long Value);
class Edge { EdgeId Id; NodeId Source; NodeId Target; string Relation; Dictionary<string, object> Properties; }
Relation Meaning Properties
contains physical containment; a node has exactly one container —
connected_to traversable passage traversal_cost, state, traversable_by, permeability.{heat,sound,light,…}
adjacent_to side by side direction, permeability
knows knower (NPC or faction) → subject: a fact one property per predicate: {value, observed_at, provenance}
member_of entity → faction role, since
part_of, made_of, visible_from composition, material, line of sight —

Edge properties are mutated through SetEdgePropertyIntent (Phase 1 addition) — a door's state, an edge's discovered, a fact's value.

Facts live here

A fact is a knows edge, one per (knower, subject), with predicates as properties. Confidence is derived at read time, never stored. See PerceptionSystem for who writes them and the player page What villagers know for what they mean.

The view

ReadOnlyGraphView is a read-only wrapper over the live graph, not a copy. It is frozen for a phase because nothing writes until the phase's batch resolves (see Views, snapshots and the ring buffer). Its query API is the one systems live in:

view.NodesWithComponent("Sentient")        view.GetContents(roomId)          view.GetUltimateLocation(bottleId)
view.TryGet<float>(id, "hunger")           view.GetOrDefault(id, "temperature", 20f)
view.EdgesFrom(id, "connected_to")         view.NearbyWithComponent(id, "OnFire", maxHops: 2)
view.Facts(npc)                            view.Known(npc, "food_value", filter)              // Phase 1: facts

Reads return fallbacks rather than throwing (hot-toggle: the writing system may be off).

History

Phase Change
1 Introduced. Kinds faction and rule added; knows edges carry predicates; SetEdgePropertyIntent; the view is a wrapper.

See also

Intents and the resolver · Views, snapshots and the ring buffer · World vocabulary