latent.lint.rules.lt016¶
LT016 — catalog["x"].load()/.save() where input=/output= says the same thing.
Functions¶
lt016¶
catalog["x"].load()/.save() where input=/output= says the same thing.
The two spellings read as equivalent and are not: only the declared one
reaches the cache key. A declared input= is fingerprinted into it by
_CatalogInputCachePolicy; an imperative .load() is invisible to it,
so editing the dataset re-runs the declaring task and leaves the imperative
one serving its cached result. A declared report output= is what makes
_ReportOutputCachePolicy withhold the key so the task re-runs and the
teardown has a fresh report to re-gate; an imperative .save() leaves the
declared outputs tuple empty, the veto never fires, and a cache hit skips
the save the teardown then fails to find — GateFailure on a flow whose code
looks fine.
Task-scoped, like LT001: input=/output= bind a dataset to a task
invocation, so module-scope access is a different defect with a different
fix. A genuinely conditional save fires and needs a waiver, not a
carve-out: output= saves unconditionally, so the two really do differ
and choosing the imperative form is a decision worth writing down.