Graph
ForgeGraph is the central data model in plant_forge. It describes the
structure of a schema-based simulation object as a directed acyclic graph (DAG)
of typed nodes and edges. The compiler validates it and resolves dependency
ordering before running generators.
Types
ForgeGraph
pub struct ForgeGraph {
pub graph_id: String,
pub nodes: Vec<ForgeNode>,
pub edges: Vec<ForgeEdge>,
}
graph_id is typically the spec identifier for the object being compiled (e.g.
the region id or area id). Node and edge lists may be empty for trivially simple
kinds.
ForgeNode
pub struct ForgeNode {
pub id: String,
pub kind: ForgeNodeKind,
pub properties: serde_json::Value,
}
Each node has a stable string id unique within its graph. properties is an
open JSON object for domain-specific metadata that the compile step preserves
and passes through to the compiled output.
ForgeNodeKind
pub enum ForgeNodeKind {
Anchor,
Generator,
Field,
Institution,
}
| Kind | Meaning |
|---|---|
Anchor |
Fixed reference point; other nodes depend on it |
Generator |
Runs a JTL program to populate dependent nodes |
Field |
A named property or data field produced by generators |
Institution |
A named categorical grouping (e.g. faction, biome class) |
These are the default vocabulary. Future ports may not use all four; the compiler operates on any mix.
ForgeEdge
pub struct ForgeEdge {
pub id: String,
pub kind: ForgeEdgeKind,
pub from: String,
pub to: String,
pub properties: serde_json::Value,
}
from and to are node ids within the same graph. id must be unique within
the graph.
ForgeEdgeKind
pub enum ForgeEdgeKind {
Constraint,
Produces,
Feeds,
Governs,
Interacts,
}
| Kind | Dependency Edge | Meaning |
|---|---|---|
Constraint |
yes | from must be compiled before to |
Produces |
yes | from generates output consumed by to |
Feeds |
no | Data flow hint; does not affect compile ordering |
Governs |
no | Authority / ownership relationship |
Interacts |
no | Bidirectional influence; no ordering implication |
Only Constraint and Produces edges participate in topological ordering.
The others are carried through to compiled output for downstream use.
Validation
ForgeGraph::validate() runs four checks:
- Unique node ids — no two nodes share an
id. - Unique edge ids — no two edges share an
id. - No dangling edges — every
fromandtoreferences an existing node id. - No dependency cycles — the subgraph of
ConstraintandProducesedges is acyclic (verified by Kahn's algorithm).
pub enum GraphValidationError {
DuplicateNodeId(String),
DuplicateEdgeId(String),
DanglingFrom { edge_id: String, node_id: String },
DanglingTo { edge_id: String, node_id: String },
DependencyCycle,
}
compile_forge() calls validate() internally and returns an error on the
first violation. Callers should not pass unvalidated graphs to the compiler.
Building a ForgeGraph
The standard pattern is a to_forge_graph(&self) -> ForgeGraph method on
your spec type:
impl RegionGraphSpec {
pub fn to_forge_graph(&self) -> ForgeGraph {
let nodes = self.nodes.iter().map(|n| ForgeNode {
id: n.node_id.clone(),
kind: ForgeNodeKind::from(&n.kind),
properties: serde_json::to_value(&n.params).unwrap_or_default(),
}).collect();
let edges = self.edges.iter().map(|e| ForgeEdge {
id: e.edge_id.clone(),
kind: ForgeEdgeKind::from(&e.kind),
from: e.from.clone(),
to: e.to.clone(),
properties: serde_json::Value::Null,
}).collect();
ForgeGraph {
graph_id: self.region_id.clone(),
nodes,
edges,
}
}
}
See the Forge Port Guide for the full region reference implementation.