Skip to content

latent.gates.publish

Publish a statistical report: gate-fill, sampled stamp, renderings, payload.

The engine behind the stats.Report / agent_studio.Report dataset types (which own the file IO) and the public escape for non-catalog contexts — scripts, notebooks, orchestrators. Catalog-declared flows never call it: they return the report and let the catalog publish it.

One call produces the artifact contract the rest of the machinery reads: a gates array, a sampled stamp, a run_id stamp when a flow is active, and a mode="json" payload (latent.gates.thresholds.discover_reports, flow-teardown enforcement, LT013). analyze's analysis knobs (rubrics, comparison_scores, n_resamples, confidence_level, seed, …) stay on analyze — call it yourself and pass report=.

Publishing records verdicts; it never raises on a failed gate. latent.gates.gating.enforce_gates owns the raise.

Classes

PublishedReport

PublishedReport()

A published report: the gated, stamped model plus its renderings.

Frozen — post-hoc payload surgery is what extra= replaces. The freeze is shallow: report and payload are themselves mutable objects, so treat them as read-only.

Functions

publish_report

publish_report(scores: dict[str, np.ndarray] | None = None, report: StatisticalReport | None = None, score_types: str | dict[str, str] | None = None, gates: dict[str, float | GateSpec] | None = None, extra: dict[str, Any] | None = None, sampled: bool | None = None) -> PublishedReport

Analyze or adopt a report, gate it, stamp it, render it, log it.

Args: scores: Metric name -> 1D score array. Mutually exclusive with report; this branch calls :func:~latent.stats.report.analyze. report: An already-analyzed report (from analyze, build_gated_report, or a pre-built flow's result["report"]). Published on a deep copy — the caller's object is never mutated. score_types: "binary"/"ordinal"/"continuous" broadcast to every metric, or a per-metric dict. Scores mode only. gates: Explicit thresholds; they win over thresholds.yaml verbatim. None resolves the active flow's lockfile section (:func:~latent.gates.thresholds.resolve_gates). {} publishes ungated and records gates_disabled on the artifact. Direction comes from an explicit GateSpec.lower_is_better only — this function forwards no metric_directions, so bare-float thresholds gate as floors. extra: Extra top-level payload keys (offender lists, dataset ids, ...), JSON-normalized before merging. A key colliding with a StatisticalReport field raises — set it on the report instead. run_id is reserved inside a flow: the active run's id is stamped over it (see below). sampled: Override the smoke-run stamp. None (default) reads latent.prefect.sampling.effective_truncation() — True only when apply_sampling actually truncated this run — and ORs it with an incoming report's own stamp, so the flag only ever goes on by default: republishing a sampled report cannot launder it into an enforceable one. sampled=False is the explicit escape hatch.

Returns: A frozen :class:PublishedReport.

Raises: ValueError: Neither or both of scores/report; score_types in report mode; gates against a report that already carries gates; a gated metric name appearing more than once in the report; an extra key colliding with a report field or not JSON-serializable.

Methods

PublishedReport.all_passed

True when every recorded gate passed.

Vacuously True when the report carries no gates (never gated, or gates={}): it means "nothing failed", not "everything was checked". Coverage is latent thresholds check's question; enforcement is :func:~latent.gates.gating.enforce_gates'.