The node
EachSessionTreeNode carries:
| Field | Meaning |
|---|---|
id | Node id |
root_id | Root of this run |
parent_run_id | Parent node (null for the root) |
envelope | { "limit": <tokens>, "spent": <tokens> } |
terminal_state | Exit reason + outcome once finalized |
scope | Glob scope assigned to this node |
role | Role that owns the node |
rejected_raises | Recorded budget-raise attempts that were denied |
transitions | Board transition deltas |
created_at / ended_at | Lifecycle timestamps |
Budget fan-out
Children are allocated from the parent’s envelope, and the manager enforces the invariant on every allocation:rejected_raises with reason: "cap_raise_rejected" — the attempt itself becomes part of the record.
Budget is treated as a security boundary, not a counter. A child can never overspend its parent, and a rejected raise is auditable.
Terminal states
Every spawned node reaches a terminal state — including failures. The exit reason is one of:Persistence and export
Nodes persist as individual files (mode0o600):
{ "root_id": ..., "nodes": [...] }, which is what the voss board renderer and voss session tree --json consume — and what an ADE audit view renders as a navigable tree.