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. Generationincrements 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 keysWhyChangedon it.- Components are tags, not data. Capability tags (
Sentient,Combustible) come from templates; state tags (OnFire,Dead) are set and cleared by systems. AComponentIndexmakesNodesWithComponent(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