1 min read
pyssg.core.incremental.invalidation
Dirty propagation with early-cutoff.
The heart of the incremental engine. Three mechanisms combine:
- Reverse edges + aspect registration: when an aspect of a node changes, only
incoming edges whose
sensitive_toincludes that aspect propagate dirt, each at its declaredrestart_phase. - Early-cutoff: after recomputing a node, only aspects that actually changed propagate. An unchanged output stops the cascade right there.
- Fixpoint: cutoff guarantees hashes stabilize, so even cyclic graphs converge
(the
WorkListloop terminates).
Stdlib only.
class WorkList
Pending work, keyed by node, holding the smallest dirty-from phase.
A deeper (smaller) phase subsumes a shallower one for the same node: if a node is dirty from PARSE and also from RENDER, it must restart from PARSE.
WorkList.__init__(self, seeds: Iterable[tuple[NodeId, Phase]] | None = None) -> None
WorkList.add(self, nid: NodeId, from_phase: Phase) -> None
WorkList.drain(self) -> dict[NodeId, Phase]
Return all pending work and clear it (one fixpoint round).
WorkList.get(self, nid: NodeId) -> Phase | None
changed_aspects(build: Build, nid: NodeId) -> set[str]
Aspects whose hash differs from the committed baseline.
propagate_aspect_changes(build: Build, nid: NodeId, work: WorkList) -> None
Spread dirt from a recomputed node to its dependents, with cutoff.
Walks incoming reverse edges; an edge propagates only if it is sensitive to
an aspect that actually changed, restarting the source at the edge's
restart_phase. If nothing changed, the cascade stops (early-cutoff).