05 โ State Fork and Lineage
State is immutable: nodes never modify it. They produce new states via
fork(), which carries lineage, confidence, and history forward.
๐ฏ Goal
Walk a branch tree and inspect how states are related, how confidence compounds,
and how history records the exact node path taken.
๐งฑ Setup
Node.fork passes node_id=self.id, so history records the point of
derivation automatically.
๐ Forking
| Field | root |
s1 |
s2 |
|---|---|---|---|
depth |
0 |
1 |
2 |
score |
50 |
60 |
60 |
confidence |
1.0 |
1.1 |
1.1 |
history |
() |
('score.bonus',) |
('score.bonus',) |
parent |
None |
root |
s1 |
๐ Lineage
lineage() walks parents back to the root, root-first:
๐ Immutability guarantees
๐ Metadata & confidence
confidence_deltais added (parent.confidence + delta), so a chain of bonuses compounds: 1.0 โ 1.1 โ 1.2.metadata_updateis shallow-merged intometadataโ untouched states share the same metadata dict (no copy unless a fork changes it).payload_updatekeys are dot-paths; they are validated byvalidate_updateagainst the state'sschemabefore copying.
๐ก Tips
- Use
Node.forkinresolve()โ it recordsnode_idinto history for free. - Fork parameters are keyword-only (
payload_update,confidence_delta,node_id,metadata_update) โ there is no positional API. - A root state built directly (
ScoreState(payload=...)) validates againstschemain__post_init__โ you can't create an invalid root. - Since states are immutable and share structure, forking many branches is
cheap โ copy only the modified branch (see
Payload.update).