Planning and Cache State¶
Hosts that want to render “this node is cached / prior selection miss / not
yet run / skipped” without executing anything use
Workflow.plan. Hosts that want to
clear selected cache records explicitly use
Workflow.invalidate.
The deeper cache model — result keys, selected records, and current pointers — lives in Caching and Provenance.
Workflow.plan()¶
plan() returns dict[str, NodePlan], one entry per node:
plan = wf.plan()
for name, entry in plan.items():
print(name, entry.status, entry.final_result_key, entry.selected_record_id)
It uses the direct planning path — no Wetlands worker pools are launched and no tool code runs.
NodePlan¶
Each NodePlan carries:
Field |
Description |
|---|---|
|
Scoped name ( |
|
V1 result key when it can be computed from known selected upstream
records. |
|
Selected record ID for |
|
One of the |
|
Tuple of scoped names of this node’s direct upstreams. |
|
Tuple of scoped upstream names whose selected records are not known yet. |
|
Diagnostic logical signature. It is not the public cache identity; use
|
|
Read-only bool; |
|
Read-only bool; |
NodePlanStatus → UI mapping¶
Status |
Meaning |
Suggested affordance |
|---|---|---|
|
The planned result key has a selected current record; |
Green / “up to date” |
|
The planned result key has no selected record, but the same node has
another selected current record. |
Yellow / “needs rebuild” |
|
No known cache record exists for this node yet. |
Grey / “not yet run” |
|
The node is disabled, or has a disabled upstream that prevents
execution. |
Struck-through / muted |
|
At least one consumed upstream selected record is not known until that upstream executes, so the final result key cannot be determined yet. |
Grey / “pending upstream” |
Workflow-node aggregation¶
A workflow node aggregates its internals: it reports SKIPPED when disabled, CACHED only when every executable internal entry is cached, PENDING_UPSTREAM when an internal final selection still depends on an unresolved upstream, and UNEXECUTED otherwise.
Internal entries are still present in the
plan dict under their scoped names, so a host can show drill-down
(“3/5 internals cached”) on a “needs rebuild” parent.
Workflow.invalidate()¶
When a long-lived host changes a parameter and wants to clear cached
results explicitly, Workflow.invalidate removes cache selections for
the named nodes:
cleared = wf.invalidate(["segment"]) # cascade=True default
cleared_nodes = {selection.node_name for selection in cleared}
wf.invalidate(["segment"], cascade=False) # just "segment"
Returns InvalidatedSelection entries for actual current.json pointers that were removed.
Each entry includes the node name, result key, selected record ID when readable, and a removal status.
Entries that had no selected cache record are silently skipped.
KeyError is raised when any name is unknown.
Warning
invalidate() is not safe to call concurrently with
compute(). The library does not currently expose a public lock
primitive; coordinate externally (cancel + join + invalidate).
Cycle handling¶
The two methods diverge on cycles:
Workflow.validate()reports a cycle as aValidationErrorwithkind="cycle". Non-raising.Workflow.plan()raisesCycleInWorkflowError— it cannot topologically order a cyclic graph and refuses to fabricate a plan.
The recommended pattern: call validate() first, gate plan() on
“no cycle errors”:
errs = wf.validate()
if any(e.kind == "cycle" for e in errs):
render_cycle(errs)
else:
render_plan(wf.plan())
Specs.md §6.5 covers the contract end-to-end.