Graph Identity, Back-Edges, And Scope
ProcessCore is an object graph with convenience indexes maintained by the model. Understanding a few invariants makes traversal behavior much easier to predict.
Every Process is exactly one directed edge. Input and Output are optional singular nodes; fan-in, fan-out, and parallel lanes use multiple process instances, even when those instances share a name and protocol state.
Shared Node Identity
Samples are equal by Name. Data nodes are equal by Path and Selector.
When a process is added to a dataset, its input and output nodes are canonicalized against the root dataset registry. If another process already uses the same logical node, both processes point to the same object instance after canonicalization. Compatible metadata from the later node is merged into that instance: annotations and nested data parts are accumulated, while missing typed and dynamic fields are filled.
Conflicting non-empty metadata raises a canonicalization error rather than selecting a value by load order. The one role-specific exception is Source plus Sample on the same logical sample; these are compatible endpoint roles and normalize to Sample.
This is why a sample produced by one process can be consumed by another process without manually wiring both processes to the same object instance.
Back-Edges
ProcessCore maintains back-edges when you use the public set/clear methods:
Relationship |
Back-edge |
|---|---|
Process has input node |
Node |
Process has output node |
Node |
Dataset has process |
Process |
Dataset has child dataset |
Child |
Use SetInputSample, SetOutputData, ClearInput, ClearOutput, AddProcess, and AddPart so these links stay correct.
Scope
Traversal methods on Sample, Data, and IONode can accept a process scope. Dataset-scoped helpers pass dataset.AllProcesses() for you.
Use a scope when:
- A node is shared across nested datasets.
- You want a query limited to one dataset.
- You want fragment selector providers resolved through the dataset that owns the processes.
Without a scope, node-centered traversal follows the node's back-edges directly.
Nested Datasets
Dataset.AllProcesses() walks the dataset and all nested HasPart children. Adding a child dataset re-canonicalizes the child graph against the parent root, so shared sample/data nodes can connect processes across the hierarchy.
Removing a child detaches it and rebuilds the child's own registry so it can act as a root dataset again.
Fragment Selectors
Data identity includes the selector. Two data nodes with the same path but different selectors are distinct nodes. Traversal can still connect them if their selectors are semantically related and the dataset has a matching fragment selector provider registered.
The fragment selector provider walkthrough demonstrates this with CSV row, column, and cell fragments.
What To Use When
Task |
API |
|---|---|
Add processes safely |
|
Add nested datasets safely |
|
Connect process I/O safely |
|
Stay inside a dataset |
Dataset-scoped helpers such as |
Query from a node with explicit scope |
|
Traverse related fragments |
Register an |
ProcessCore