Local Runner¶
The built-in Runner: it schedules Stages, keeping its state as files on Storage — no database (ADR-0010) — and streams records so memory stays bounded (ADR-0033).
runner ¶
LocalRunner — single-node DAG execution with checkpoint/resume (ADR-0003, 0010).
Run state is files-on-Storage, no database: a run manifest, per-Stage checkpoint
files, and a write-ahead log, all under <storage_uri>/_latence/runs/<run_id>/.
Checkpoints are written batch-granularly and streamed to a temp file that is
atomically published temp-write→rename (WAL discipline, ADR-0033), so the write
transient is O(batch) not O(all-records) and a run killed mid-Stage leaves either
the previous checkpoint or the complete new one — never a torn write. Re-running:
- a Stage whose checkpoint exists is skipped (resume);
- a fully-completed pipeline is a no-op.
Stages execute in topological order over their depends_on edges; for the S1
spine (Source→Parse→Export) the order is linear, but the DAG machinery is real.
RunRecords
dataclass
¶
RunRecords(
runner: LocalRunner,
outputs: dict[str, list[StageOutput]],
storage: Storage,
pipeline: Pipeline,
run_id: str,
)
One run's record substrate for :class:~latence_core.stage_inputs.StageInputs (#69).
The live retained outputs map first, the Stage's on-disk checkpoint as the fallback — the
two-source read that makes doc-level release transparent. Reads go through the engine's public
:meth:LocalRunner.stage_records / :meth:LocalRunner.stage_record_count rather than around
them, so a subclass that intercepts the checkpoint stream (the test seam) still sees every
read, and a second Runner can construct one of these over its own substrate map.
records ¶
One Stage's output — from the live map if retained, else streamed from its checkpoint.
Source code in packages/latence-core/src/latence_core/runner.py
count ¶
How many records one Stage produced — a len or the checkpoint's line count.
Source code in packages/latence-core/src/latence_core/runner.py
carrier ¶
The record type a Stage checkpoints (Record for a mixed-carrier Stage).
LocalRunner ¶
LocalRunner(
registry: ProviderRegistry | None = None,
*,
span_sink: SpanSink | None = None,
lineage: OpenLineageEmitter | None = None
)
Executes a Pipeline on the local node with resumable file-based state.
Source code in packages/latence-core/src/latence_core/runner.py
quality_report_builder
property
¶
The engine's composed :class:~latence_core.quality_report_builder.QualityReportBuilder.
Public so a second Runner reuses the same report seam this engine uses — bound to this
engine's live reader (stage_records / read_findings) and its _fanout_by_stage
tally, so a report built through it is byte-identical to the local Runner's. This is the
interface the Airflow adapter builds its report through, instead of reaching into the
private _build_report / _final_records (the audit's THEME F fix, H-F1).
stage_execution
property
¶
The Stage-execution module every Runner runs its Stages through (C3).
Public because it IS the Runner seam: a second Runner (Airflow, Delta, an adopter's own)
calls stage_execution.execute(stage, ctx) and gets device routing, the skip-with-flag
posture, the Provider tally drains and a fully-populated
:class:~latence_core.quality.StageMetrics — identical to this engine's, because it is
the same code, not a re-implementation. Bound to this engine's registry, its dispatch and
its live fan-out tally, so a Quality Report built off either Runner carries the same
columns (ADR-0003: the identical Stages under a pluggable Runner).
stage_inputs ¶
stage_inputs(
stage: Stage,
outputs: dict[str, list[StageOutput]],
*,
storage: Storage,
pipeline: Pipeline,
run_id: str
) -> StageInputs
This Stage's input, resolved against the Capability's declared plan (Wave 4-I).
The one call a Runner makes to answer "what does this Stage receive, how much of it is
there, and is it wired correctly?" — replacing the executor's four-way shape branch and the
per-shape counting rules. Public because it is the other half of the
:class:~latence_core.stage_execution.StageContext a second Runner builds: an adapter
hands its own substrate map in as outputs and gets the identical input semantics,
rather than re-deriving which Capabilities stream and which gather.
Bound to this run's reuse overlay, so a delta's reused records fold in exactly where ADR-0061 §5 says they do.
Source code in packages/latence-core/src/latence_core/runner.py
dispatch_stage ¶
dispatch_stage(
stage: Stage,
provider: object,
storage: Storage,
pipeline: Pipeline,
run_id: str,
inputs: StageInputs,
) -> Iterator[StageOutput]
The :class:~latence_core.stage_execution.StageDispatch half this engine supplies.
An internal collaborator of :class:~latence_core.stage_execution.StageExecution, not part
of its interface — a Runner adapter never calls this. Public only because the executor is a
separate module and reaching a private name across it is exactly the reach-through this
refactor removes.
Source code in packages/latence-core/src/latence_core/runner.py
run_dir ¶
The run's state/artifact directory on Storage (<uri>/_latence/runs/<run_id>).
Public so a second Runner reusing this engine's report path can land the run's data artifacts where the shared report builder expects them, without reaching a private method (H-F1). The local Runner's own file-state (manifest, checkpoints, WAL) still lives here.
The layout itself is owned by :class:~latence_core.run_store.RunLayout (Wave 2-E) —
every path method below delegates there, so this engine and every other consumer mint
byte-identical locations from one decision.
Source code in packages/latence-core/src/latence_core/runner.py
report_uri ¶
The run's Quality Report location on Storage.
Public so a second Runner persists the report the shared
:class:~latence_core.quality_report_builder.QualityReportBuilder produced to the same
place an adopter reads it regardless of Runner — no private reach-through (H-F1).
Source code in packages/latence-core/src/latence_core/runner.py
read_type_vocabulary ¶
read_type_vocabulary(
storage: Storage,
pipeline: Pipeline,
run_id: str,
stage_name: str,
) -> TypeVocabulary | None
Read back a run's persisted canonical type vocabulary; None when none was written.
The seam an incremental delta run (T4) reads its predecessor's vocabulary through before seeding the next consolidation — so a delta aliases a new type INTO an existing canonical cluster instead of re-electing (and thereby renaming) one.
Source code in packages/latence-core/src/latence_core/runner.py
read_findings ¶
read_findings(
storage: Storage,
pipeline: Pipeline,
run_id: str,
stage_name: str,
) -> list[ScreeningFinding]
Read a Screening Stage's persisted findings sidecar (empty if none written).
Public because it is one half of the
:class:~latence_core.quality_report_builder.StageRecordReader seam the shared
:class:~latence_core.quality_report_builder.QualityReportBuilder reads to build the
Screening rollup — the report builder no longer reaches into a private method for it
(H-F1). The executor's own screening path uses the same reader.
Source code in packages/latence-core/src/latence_core/runner.py
stage_records ¶
stage_records(
stage_name: str,
outputs: Mapping[str, list[StageOutput]],
*,
storage: Storage,
pipeline: Pipeline,
run_id: str
) -> Iterator[StageOutput]
Public reader half of the report-builder seam — delegates to :meth:_stage_records.
The shared :class:~latence_core.quality_report_builder.QualityReportBuilder (and a second
Runner reusing it) reads each Stage's records back through this public method instead of the
private _stage_records — the report concern is a real, relocatable unit that composes
with the engine through its interface, never a # noqa: SLF001 reach-through (H-F1).
Source code in packages/latence-core/src/latence_core/runner.py
stage_record_count ¶
stage_record_count(
stage_name: str,
outputs: Mapping[str, list[StageOutput]],
*,
storage: Storage,
pipeline: Pipeline,
run_id: str
) -> int
How many records one Stage produced — from the live dict, else its checkpoint's lines.
The counting companion to :meth:stage_records, and public for the same reason: the input
resolution (:class:~latence_core.stage_inputs.StageInputs) reads a streamed Stage's
records_in through it rather than around it. A checkpoint is newline-delimited
model_dump_json (one record per non-blank line, blank lines skipped on read), so
counting lines equals counting decoded records — including a fused Stage's mixed-carrier
checkpoint, where each line is still exactly one record. A Stage with no checkpoint (not
run, or genuinely empty) counts 0.
Source code in packages/latence-core/src/latence_core/runner.py
scrub_sensitive ¶
Recursively redact sensitive config keys in a JSON-able manifest structure.
Walks the pipeline.model_dump(mode="json") tree and replaces the value of
any mapping key that looks like a secret (see _SENSITIVE_KEY_TOKENS) with a
fixed placeholder, keeping the key so the manifest still documents that a secret
was configured — just not its value (issue #30). Lists and nested mappings are
scrubbed in place-of-copy; scalars pass through. Env-var references the operator
might legitimately keep (e.g. "$OPENAI_API_KEY") are redacted too — the
manifest never needs the secret's value, referenced or inlined.
Source code in packages/latence-core/src/latence_core/runner.py
topological_order ¶
Kahn's algorithm over depends_on edges. Raises on a cycle.