somatize.foreseen
What a graph’s nodes will be called before anything runs, and what an edit did:
from somatize import foreseen
foreseen.names(g) # what each answer will be calledforeseen.unneeded(g, x, store=store) # what would not have to run at allforeseen.changes(before, after) # what the edit didforeseen.snapshot(g) # the same, kept for laterA name is a hash of the recipe and not of the data, so only the graph’s input is hashed by content and from there down they are hashes of hashes. The engine already makes this pass before its first node; asking for it on its own turns is my cache still good? into a millisecond instead of a run.
changes answers {node: [finding, ...]} — the shape somatize.health uses,
and for the same reason: what happens to a node is more than one fact.
| finding | what it says |
|---|---|
CHANGED | its shape moved: another class, other arguments, or who feeds it |
RESETTLED | it is frozen at another state — other weights, another version |
SALTED | its salt moved |
DOWNSTREAM | none of those moved and its name moved anyway |
STALE | its name did not move and its code did |
SUSPECT | something above it is STALE |
ADDED / GONE | it is in one graph and not the other |
UNVERSIONED | its answer is kept and nobody can say whether its code moved |
UNKNOWN | it cannot be named on one side or the other |
The first three are one question split three ways, because two questions get
asked of one answer: does my cache still hold is all three, did the code
change is CHANGED alone — weights belong to a version, they are not one.
STALE exists because the fingerprint of the code is deliberately not in the
key: editing a forward renames nothing, so a diff that only looked at names
would answer nothing changed to the very edit being asked about. Here it is an
opinion and not an invalidation, and it reaches down as SUSPECT.
UNKNOWN must never be read as unchanged: a .mapped() node is named by items
nobody has yet.
Each side is a Graph or a snapshot of one, because two versions of a module
do not coexist in an interpreter. Nothing here reads or writes a store.
Functions
Section titled “Functions”changes
Section titled “changes”changes(before: Graph | Snapshot, after: Graph | Snapshot, input: Any | None = None, *, store: Store | str | None = None) -> dict[str, list[str]]What an edit did, as {node: [finding, ...]}. A node with nothing said
about it is not in it. input and store are only used for a side that is
still a graph, since a snapshot has been named already.
names(graph: Graph, input: Any | None = None, *, store: Store | str | None = None) -> dict[str, str]What each node’s answer will be called — {node: name} — with nothing run.
A node missing from it cannot be named in advance, which is what a
.mapped() node and anything under it are.
snapshot
Section titled “snapshot”snapshot(graph: Graph, input: Any | None = None, *, store: Store | str | None = None) -> SnapshotEverything changes reads about a graph, as plain JSON, so a version can
be compared against one that no longer exists in this process. Two are
comparable when taken with the same input, which the default always is.
unneeded
Section titled “unneeded”unneeded(graph: Graph, input: Any | None = None, *, store: Store | str) -> list[str]The nodes that would not have to run at all, because something below them
is already kept. A store and not a temporary one: this is the only question
here whose answer depends on what is in it.
Constants
Section titled “Constants”FINDINGS—STALE,SUSPECT,CHANGED,RESETTLED,SALTED,DOWNSTREAM,ADDED,GONE,UNVERSIONED,UNKNOWN