pyssg is pre-1.0 and under active development - APIs, config, and themes may change.
pyssg.core.incremental.invalidation

1 min read

pyssg.core.incremental.invalidation

Dirty propagation with early-cutoff.

The heart of the incremental engine. Three mechanisms combine:

  1. Reverse edges + aspect registration: when an aspect of a node changes, only incoming edges whose sensitive_to includes that aspect propagate dirt, each at its declared restart_phase.
  2. Early-cutoff: after recomputing a node, only aspects that actually changed propagate. An unchanged output stops the cascade right there.
  3. Fixpoint: cutoff guarantees hashes stabilize, so even cyclic graphs converge (the WorkList loop 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).