Runtime invariants
These are the properties the runtime holds for every node, whether the caller is React, the client, a test, or a script.
| Invariant | What it means |
|---|---|
| Deterministic identity | A node’s id is tag:key, where key is pure and deterministic. The same tag and args always resolve to the same node. See Identity and keys. |
| Static dependency topology | A node’s dependency set is fixed once wired. Args reconciliation cannot change which nodes it depends on. See Dependencies. |
| Dependency-first readiness | A node cannot be ready until every node it depends on is ready. |
| Wiring failure ≠ driver failure | A planning failure (bad key, cycle, duplicate tag) makes the node invalid; it is not a driver/readiness failure. |
| Readiness failure is retryable | A failed acquire leaves the node retryable — calling ensureReady() again starts a fresh attempt. See Errors. |
| Stable pending attempt | Concurrent callers awaiting readiness join the same in-flight attempt; they do not each start their own. |
| Per-node serialized work | Driver work for one node id runs serialized. A stale request cannot commit over a fresh one; two actions cannot interleave. |
| Refresh ≠ retry | Refresh updates a ready node in the background and rolls back on failure; it is distinct from retrying a readiness error. |
| Operation failure ≠ readiness failure | A failed action or refresh leaves the node ready with an operation failure; it does not poison readiness. See Lifecycle. |
| Expired data is hidden | An expired result is not exposed to ordinary reads; active consumers reload it through readiness. See Result validity. |
| Release ≠ eviction | Release clears resources but keeps identity and edges; eviction removes the graph record and edges. See Eviction and release. |
| Liveness ≠ React presence | Driver live work is driven by observation and manual leases, not by a component mounting. See Liveness. |
| Owned cleanup | Node and driver cleanup runs through disposer bags and the driver release hook, on one graph-owned path. |
| Caller-independent | The same contract holds for every caller; it does not depend on the UI disabling a control. |
Underneath all of these: every lifecycle fact has exactly one owner, the runtime.
Next: Testing.