nav.nav_orchestrator

Orchestrator layer — turns observations into navigation results.

The orchestrator extracts features, gates them by reliability, runs each feasible technique, and reconciles the per-technique results into one NavResult.

Modules:

nav_context

NavContext — per-image global state.

feature_summary

NavFeatureSummary — per-feature post-mortem entry.

image_classifier

NavImageClassifier — quick-fail image-quality classifier.

image_classifier_result

NavImageClassifierResult — output of the classifier.

image_derivatives

build_image_edge_dt, compute_image_gradient_vu, compute_all_image_derivatives, and ImageDerivativesConfig — shared gradient / edge-DT / gradient-vector computation. The combined entry point (compute_all_image_derivatives) shares the heavy gaussian + sobel pass between all three products.

provenance

Provenance — reproducibility metadata.

ensemble

ensemble — free function that reconciles per-technique results.

nav_result

NavResult — final output dataclass.

curator

build_metadata_dict — JSON output curation.

status_reason_info

STATUS_REASON_INFO_TEMPLATE — per-status_reason operator log templates.

NavOrchestrator — top-level driver for autonomous navigation.

The orchestrator turns one observation into one NavResult:

  1. Build a NavContext (image, masks, classifier verdict, provenance).

  2. Iterate registered NavModel instances and gather features and annotations from each.

  3. Apply the FeatureReliabilityGate to drop bad-data features.

  4. Run every feasible prior-free technique on the surviving features.

  5. Combine pass-1 results via the ensemble function to derive a prior.

  6. Run prior-required techniques against the derived prior.

  7. Combine the union of pass-1 and pass-2 results via ensemble.

Glob-pattern filters at construction time let an operator restrict which models or techniques run for debugging (only_models='body:MIMAS', only_techniques='!StarFieldFromCatalogNav').

Bases: NavBase

Top-level driver for autonomous navigation.

Parameters:
  • models – List of constructed NavModel instances for one observation. Caller builds these per-image (since each NavModel binds to an obs).

  • config – Optional Config override.

  • only_models – Glob-pattern string or list selecting which models run. Default '*' runs every supplied model.

  • only_techniques – Glob-pattern string or list selecting which techniques run. Default '*' runs every registered technique.

  • ensemble_config – Optional EnsembleConfig override.

  • image_quality_thresholds – Optional thresholds for the image-quality classifier.

  • rms_nav_version – Version string written into provenance.

Run the full pipeline on one observation.

Parameters:

obs – The observation snapshot to navigate.

Returns:

A single NavResult summarizing the navigation outcome.

Build every per-image artifact a downstream caller might use.

Runs the same pre-technique pipeline as navigate(): builds the provenance envelope and the NavContext, calls every registered NavModel’s create_model, extracts features, builds the feature inventory, snapshots per-model metadata, and merges annotations. Hard-failure image classes are logged but not short-circuited — the caller (manual-nav dialog, debugger) decides what to do on a blank or saturated frame.

Parameters:
  • obs – The observation snapshot to prepare.

  • apply_gate – When True (the default) the reliability gate runs; OrchestratorPrep.features carries only the kept features and feature_inventory records the gate verdict for both kept and gated entries. When False every emitted feature is returned (with feature_inventory marking each as un-gated) — used by the manual-nav dialog, where the operator overrides the autonomous reliability decision.

Bases: object

Per-image artifacts produced by NavOrchestrator.prepare().

Bundles every prep-phase output a downstream caller might want. The autonomous NavOrchestrator.navigate() does not use this struct (it inlines the prep so it can short-circuit on hard-failure images), but the manual-navigation driver does: it wraps the operator’s chosen offset in a full NavResult populated from provenance / image_classifier / feature_inventory / model_metadata / annotations so the manual pipeline writes the same _metadata.json and _summary.png files the autonomous pipeline does.

Parameters:
  • context – NavContext built from the observation.

  • provenance – Reproducibility envelope shared with the autonomous pipeline.

  • image_classifier – Image-quality classifier verdict.

  • features – Either the gated-kept feature list (when prepare(..., apply_gate=True)) or every emitted feature (when apply_gate=False). The manual driver always requests the un-gated list because the operator visually overrides gate decisions.

  • feature_inventory – Per-feature summary entries. When the gate ran, both kept and gated features are included with their gated flag set accordingly; when the gate was skipped, every entry has gated=False.

  • model_metadata – Per-NavModel diagnostic dicts keyed by model name.

  • annotations – Merged annotation collection assembled from every built NavModel’s to_annotations.

NavContext — per-image global state shared across extractors and techniques.

Created once per navigation by the orchestrator. Every member is computed without knowing where any feature lives in the image: global statistics, sensor-vs-extfov masks, shared image-side derivatives, and provenance.

The context is frozen. Pass-2 techniques receive a copy with the pass-1 ensemble’s prior offset and covariance attached via with_prior.

Bases: object

Per-image global state shared across feature extraction and techniques.

The context is frozen; with_prior returns a new instance via dataclasses.replace rather than mutating in place.

Parameters:
  • obs – The observation snapshot under navigation. Typed loosely as object to avoid an import cycle; concrete value is an ObsSnapshotInst subclass.

  • image_ext – The extended-FOV image array (post source-image filter).

  • sensor_mask_extTrue where the pixel is real sensor data, False for extfov padding.

  • image_noise_sigma – Robust MAD-based noise sigma in the image’s native units (DN for raw_dn instruments, I/F for calibrated_if), computed over the entire sensor area. Pixel-threshold consumers (cosmic-ray mask, body-blob noise floor, star detection) use this value directly because they compare against pixel intensities in the same units.

  • saturation_mask_extTrue where pixels at or above the instrument’s full-well DN.

  • cosmic_ray_mask_extTrue where single-pixel cosmic-ray spikes were detected.

  • image_classifier – The image-quality classifier’s verdict.

  • image_gradient_ext – Optional shared Sobel-of-Gaussian magnitude (computed once, reused by every DT-based technique).

  • image_gradient_vu_ext – Optional (H, W, 2) per-pixel gradient-vector image ([..., 0] is g_v, [..., 1] is g_u). Sampled by the polarity filter to compare each model vertex’s outward normal against the image’s edge direction.

  • image_edge_dt_ext – Optional shared signed distance transform of the thresholded gradient image.

  • prior_offset_px – Prior offset from pass 1, None on pass 1.

  • prior_covariance_px2 – Prior offset covariance from pass 1.

  • pre_filter_applied – NavFilterSpec applied to the source image (for diagnostic provenance), None if none.

  • provenance – Provenance metadata; populated at context creation.

  • fit_camera_rotation – Per-instrument flag enabling 3-DoF technique fits. When True every technique adds in-plane camera rotation as a third parameter and reports a 3x3 covariance; when False (the default) techniques produce 2-DoF results.

  • max_rotation_deg – Maximum allowed rotation magnitude (degrees) when fit_camera_rotation is True; rotation outside the bound triggers at_edge=True. Ignored when fit_camera_rotation is False.

Return a new NavContext with pass-1 prior attached.

with_prior is non-mutating; the existing instance is unchanged.

Parameters:
  • offset_px(dv, du) offset to install as the pass-2 prior.

  • covariance_px2 – 2x2 covariance of that offset, or 3x3 when the pass-1 ensemble produced a rotation-aware result; the top-left 2x2 block is consumed.

Returns:

New NavContext with prior_offset_px and prior_covariance_px2 populated. Only the 2x2 translation block is kept; pass-2 techniques re-derive any rotation prior from the per-instrument flag.

Raises:
  • TypeError – if offset_px entries are non-numeric (cannot be coerced to float).

  • ValueError – if offset_px is not a length-2 sequence, contains non-finite entries, or covariance_px2 is not square 2x2 / 3x3 or contains non-finite entries.

NavResult — full in-memory output of a single navigation.

Carries the headline (offset ± uncertainty + simple rank) plus full diagnostic information about every technique that ran, every feature that was extracted, and provenance. Not intended to be JSON-serialized directly; the curator builds a curated JSON-friendly subset.

Bases: object

Full in-memory navigation output for one image.

Constructors NavResult.success, NavResult.failed, and NavResult.conflicted are the canonical entry points; direct instantiation is also supported.

Parameters:
  • status – One of 'success', 'failed', 'conflicted'.

  • offset_px(dv, du) offset; None on failure.

  • sigma_px – Per-axis 1sigma marginal uncertainty; None on failure.

  • sigma_along_unobservable_px – Set when covariance is rank-1 (e.g. flat-ring-only scenes); None for full-rank results.

  • confidence_rank – Five-bucket rank derived from confidence + status.

  • confidence – Underlying calibrated confidence score in [0, 1].

  • status_reason – NavStatusReason value explaining the outcome.

  • covariance_px2 – Full 2x2 covariance (or 3x3 with rotation); None on failure.

  • per_technique – List of every technique’s result (whether kept or dropped by the ensemble).

  • feature_inventory – Per-feature summary entries — what was extracted, what survived the gate, and why.

  • image_classifier – The image-quality classifier’s verdict.

  • model_metadata – Per-NavModel diagnostic dicts keyed by model name.

  • annotations – Composite annotation collection assembled from every registered NavModel’s to_annotations plus orchestrator additions. Empty by default; intended for the summary-PNG renderer.

  • provenance – Reproducibility envelope.

  • rotation_rad – Optional fitted camera rotation (radians); None when fit_camera_rotation is False.

  • sigma_rotation_rad – Optional 1-sigma rotation uncertainty.

__post_init__() None[source]

Validate consistency between status, offset, and reason.

Construct a NavResult for a conflicted (best-group reported) navigation.

confidence_rank is hard-set to 'conflicted'; downstream consumers refuse to use these results without explicit opt-in.

Construct a NavResult for a failed navigation.

Parameters:
  • status_reason – Discrete reason from NavStatusReason.

  • image_classifier – Image-quality classifier verdict.

  • provenance – Reproducibility envelope.

  • per_technique – Optional list of technique results (e.g. when every technique returned spurious).

  • feature_inventory – Optional list of feature summaries.

  • model_metadata – Optional model metadata dict.

  • annotations – Optional pre-built annotation collection (typically empty on failure).

Returns:

NavResult with status='failed', confidence=0.0, confidence_rank='failed', and no offset.

Construct a NavResult for a successful navigation.

Parameters: see dataclass field docs above. sigma_px is derived from the diagonal of covariance_px2.

NavFeatureSummary — one entry per emitted feature in NavResult.feature_inventory.

Carries enough information about each NavFeature for the curator to write a post-mortem entry into the per-image JSON metadata, including the gate decision (kept vs dropped, reason). It does not carry the heavy bits of a full NavFeature (templates, polylines, covariance) because those would bloat the metadata.

Bases: object

Per-feature post-mortem entry consumed by the curator.

Parameters:
  • feature_id – Unique identifier matching NavFeature.feature_id. Must be a non-empty string.

  • feature_type – One of the NavFeatureType values.

  • source_model – Name of the producing NavModel ('stars', 'body:MIMAS', 'rings:SATURN'). Must be non-empty.

  • reliability – Self-assessed reliability score in [0, 1].

  • gated – True if the reliability gate dropped this feature.

  • gate_reason – Human-readable reason when gated is True; None otherwise. When gated is True the reason must be non-empty.

  • bbox_extfov_vu – Half-open (v_min, u_min, v_max, u_max) bounding box in extfov coordinates; a 4-tuple of ints.

Raises:
  • TypeError – if any field has the wrong type.

  • ValueError – if invariants on field values are violated.

__post_init__() None[source]

Validate types and invariants on every field.

NavImageClassifier — quick-fail classifier for incoming images.

Operates on the entire sensor area and assigns an image to one of a small set of classes. Most “bad” classes never invoke an extractor — corrupted images fail in milliseconds with a clear reason.

The classifier is global: no predicted feature positions are used. Three cheap statistics drive the decision:

saturation_frac = fraction of pixels at saturation_threshold_dn or above missing_frac = fraction of pixels equal to missing_data_marker_dn noise_sigma = MAD-based image noise sigma

Per-instrument thresholds live in config_4N0_inst_*.yaml; this module takes them as constructor parameters so it stays pure-Python and unit- testable without loading config.

Bases: object

Per-instrument configuration for the image-quality classifier.

Parameters:
  • saturation_threshold_dn – Pixels at or above this DN are flagged saturated.

  • missing_data_marker_dn – Pixels exactly equal to this value are treated as missing data (instrument-specific dropout marker).

  • max_saturation_frac_clean – Above this fraction of saturated pixels the image is fully_overexposed.

  • max_missing_frac_clean – Above this fraction of missing pixels the image is mostly_missing_data.

  • partial_dropout_min_frac – Below this missing fraction, no partial_dropout flag is raised. At or above this fraction (and below max_missing_frac_clean) the partial_dropout advisory flag is set on the result.

  • blank_max_dn – If the image’s max DN is below this, the image is blank.

  • noisy_threshold – Above this MAD-noise sigma, the noisy flag is raised (image stays clean).

Bases: object

Quick-fail image classifier consumed by the orchestrator.

Parameters:

thresholds – Per-instrument thresholds (see ImageQualityThresholds).

Run the classifier and return its verdict.

Parameters:
  • image – 2-D float image array (sensor + extfov padding).

  • sensor_mask – Optional boolean mask selecting sensor pixels; if None, every pixel is treated as sensor data.

  • missing_frac – Optional pre-computed missing-data fraction over the sensor pixels. The orchestrator supplies this from the true missing mask (which handles the calibrated-IF NaN sentinel before the array is sanitised for the finite-only derivative path); when None the classifier derives the fraction itself from missing_data_marker_dn (using np.isnan when the marker is itself NaN).

Returns:

NavImageClassifierResult.

Raises:

TypeError – if image is not 2-D.

NavImageClassifierResult — output of the image-quality classifier.

Carried on every NavResult (success or failure) so downstream consumers can see at a glance which class the input image fell into and which optional flags were set.

Bases: object

The image-quality classifier’s verdict for one image.

noisy is a flag, not a class — a noisy-but-clean image is image_class='clean', flags=['noisy']. Images whose file fails to read get image_class='corrupt'.

Parameters:
  • image_class – One of the ImageClass literal values.

  • saturation_frac – Fraction of pixels at or above the saturation DN.

  • missing_frac – Fraction of pixels equal to the missing-data marker.

  • noise_sigma – Per-image MAD-based noise sigma (DN units).

  • max_dn – Maximum DN observed in the image.

  • flags – Additional flags caveats (independent of image_class).

Shared image-side derivatives consumed by every DT-based technique.

The orchestrator computes one gradient-magnitude image, one gradient-vector image, and one signed distance-transform image per navigation; every limb / terminator / ring-edge technique then samples those products at its own model polylines. Computing them once keeps the per-image cost bounded regardless of how many DT techniques run.

Three quantities are produced and attached to the per-image NavContext:

image_gradient_ext

Gradient magnitude of the source image after a Gaussian blur at ImageDerivativesConfig.image_gradient_sigma_px. Used by the technique-side polarity / gating logic when only a magnitude readout is needed.

image_gradient_vu_ext

Per-pixel (g_v, g_u) gradient vector after the same Gaussian blur. Sampled by the polarity filter to compare the image’s edge direction with the model’s outward normal at each polyline vertex.

image_edge_dt_ext

Distance transform of the binarised gradient image, with the threshold chosen as edge_threshold_k_sigma * image_noise_sigma. The DT is truncated at DEFAULT_DT_HALF_WIDTH_PX so the per-pixel cost is bounded for the DT-based techniques’ Levenberg-Marquardt step.

The thresholding intentionally treats every edge pixel as a candidate; the per-technique polarity filter rejects matches that disagree on the gradient direction. A non-empty gradient image always produces a fully-defined DT because build_image_edge_dt() falls back to a pure-saturation array when no pixel exceeds the threshold.

Maximum distance returned by the truncated distance transform.

Pixels farther than this from any thresholded gradient pixel saturate at DEFAULT_DT_HALF_WIDTH_PX. The cap bounds the LM cost contribution from vertices that fall in completely-empty regions of the image and bounds the DT array’s working range to a documented maximum.

Default gradient-magnitude threshold expressed as multiples of MAD noise.

Pixels whose smoothed-gradient magnitude exceeds edge_threshold_k_sigma * image_noise_sigma are kept as edge candidates. A 4-sigma threshold keeps single-pixel noise excursions out of the DT input while letting limb / terminator / ring edges through with margin to spare.

Default Gaussian sigma (pixels) used to smooth before the gradient operator.

A 1.2 pixel sigma matches the typical instrument PSF; below that the gradient is dominated by single-pixel noise, above it sharp limbs blur out and the DT loses contrast against the background.

Bases: object

Configuration for the shared gradient + DT computation.

Parameters:
  • image_gradient_sigma_px – Gaussian sigma (pixels) used before the gradient operator. Both axes share the same value; anisotropic blur is intentionally not exposed here because the image-side computation must be feature-agnostic.

  • edge_threshold_k_sigma – Multiples of image_noise_sigma used to threshold the gradient magnitude into a binary edge mask.

  • dt_half_width_px – Cap on the DT distance. Vertices farther than this from any edge pixel see a constant cost.

Raises:

ValueError – if any field is not strictly positive.

__post_init__() None[source]

Validate the three positive-real parameters.

Compute the shared gradient and edge-distance-transform images.

Two independent products are returned, both aligned to image_ext:

  1. The gradient magnitude after a Gaussian smooth at config.image_gradient_sigma_px.

  2. The distance transform of the thresholded gradient image, where the threshold is config.edge_threshold_k_sigma * image_noise_sigma and the result is truncated at config.dt_half_width_px.

For callers (the orchestrator) that need both this product and the gradient-vector product, prefer compute_all_image_derivatives() so the heavy smoothing + Sobel pass runs once instead of twice.

Parameters:
  • image_ext – Extended-FOV image array (post any source-image filter). Must be 2-D.

  • image_noise_sigma – MAD-derived noise sigma (image-native units: DN or I/F) used to scale the gradient threshold. Must be finite and non-negative.

  • config – Optional override; when None the documented defaults apply.

Returns:

Tuple (gradient_ext, edge_dt_ext) of float64 arrays, each shaped like image_ext.

Raises:
  • TypeError – if image_ext is not 2-D.

  • ValueError – if image_ext contains NaN or +/-inf, or if image_noise_sigma is negative or non-finite.

Compute every image-side derivative the orchestrator needs in one pass.

Returns the same products that build_image_edge_dt() and compute_image_gradient_vu() produce separately, but shares the single gaussian + sobel pass between them. The orchestrator’s per-image setup uses this entry point so the heavy smoothing only runs once even though three derivative products end up on the NavContext.

Parameters:
  • image_ext – Extended-FOV image array (post any source-image filter). Must be 2-D.

  • image_noise_sigma – MAD-derived noise sigma (image-native units: DN or I/F) used to scale the gradient threshold. Must be finite and non-negative.

  • config – Optional override; when None the documented defaults apply.

Returns:

  • gradient_ext — gradient magnitude shaped (H, W).

  • edge_dt_ext — truncated distance transform of the thresholded edge mask, shaped (H, W).

  • gradient_vu_ext — signed (g_v, g_u) gradient vector image, shaped (H, W, 2).

Return type:

Tuple (gradient_ext, edge_dt_ext, gradient_vu_ext)

Raises:
  • TypeError – if image_ext is not 2-D.

  • ValueError – if image_ext contains NaN or +/-inf, or if image_noise_sigma is negative or non-finite.

Compute the per-pixel (g_v, g_u) gradient vector image.

The image is first smoothed with an isotropic Gaussian of standard deviation sigma_px; gradients are then computed by Sobel along each axis. The output preserves the sign of the gradient — required by the polarity filter, which compares the image gradient direction to the model’s outward normal.

For callers (the orchestrator) that need this product alongside the gradient magnitude / DT, prefer compute_all_image_derivatives() so the heavy smoothing + Sobel pass runs once instead of twice.

Parameters:
  • image_ext – Extended-FOV image array. Must be 2-D.

  • sigma_px – Gaussian sigma (pixels) used before the Sobel operator. Must be strictly positive.

Returns:

(H, W, 2) float64 array; the last axis stacks the v-component and the u-component of the gradient (out[..., 0] is g_v, out[..., 1] is g_u).

Raises:
  • TypeError – if image_ext is not 2-D.

  • ValueError – if image_ext contains NaN or +/-inf, or if sigma_px is not strictly positive.

Provenance — reproducibility metadata attached to every NavResult.

Two navigations with identical inputs produce byte-identical Provenance except for pipeline_run_iso8601, which is wall-clock by construction; regression-baseline comparison strips that field before comparing.

The collect_provenance_metadata() helper produces the per-image rms_nav_git_sha, loaded-SPICE-kernel list, and the static-data hash dictionary at navigate time so the orchestrator can populate the Provenance envelope without each caller re-implementing the lookups.

Bases: object

Reproducibility envelope written into every NavResult.

Parameters:
  • rms_nav_version__version__ string (e.g. '0.5.2').

  • rms_nav_git_sha – Short git SHA, 'dirty', or None if neither can be determined.

  • spice_kernels – Sorted tuple of SPICE kernel filenames actually loaded (from spice.ktotal / spice.kdata).

  • static_data_hashes – Mapping filename -> sha256(raw bytes) for static-data YAMLs (config_220_body_shape.yaml, every config_3N0_*_rings.yaml, every config_4N0_inst_*.yaml). Comments and whitespace are included in the hashed bytes. Stored as a read-only MappingProxyType after construction.

  • technique_names – Sorted tuple of registered technique class names.

  • extractor_names – Sorted tuple of registered extractor class names.

  • image_et – Observation midtime ET (TDB seconds past J2000).

  • pipeline_run_iso8601 – UTC timestamp when the run began. Excluded from byte-identical regression-baseline comparison because it varies wall-clock-to-wall-clock for identical inputs.

The non-init field spice_kernel_count is derived from len(spice_kernels) in __post_init__.

__post_init__() None[source]

Normalize sequences, derive count, freeze static_data_hashes.

Bases: object

The per-image runtime-derived provenance fields.

Parameters:
  • git_sha – Short git SHA of the repository, 'dirty' if there are uncommitted changes, or None if not available.

  • spice_kernels – Sorted tuple of SPICE kernel filenames actually loaded.

  • static_data_hashes – Mapping of static-data YAML filename to sha256-hex digest of the file’s raw bytes.

Gather process-wide provenance metadata at navigate time.

Returns:

A ProvenanceMetadata instance populated with the current git SHA, loaded SPICE kernel list, and static-data hashes.

Ensemble — reconcile per-technique results into a single NavResult.

The ensemble is the single point in the pipeline where multiple per-technique estimates become one offset. Every step is honest:

  1. Drop spurious=True results.

  2. Drop at_edge=True results unless dropping them would empty the set.

  3. Group remaining results by Mahalanobis-distance agreement (single-link).

  4. Pick the highest summed-confidence group.

  5. Combine offsets within that group via precision-weighted (Kalman-style) merging.

  6. Apply optional disagreement / conflict penalties.

  7. Emit a NavResult.

The ensemble is tested in isolation against synthetic per-technique results; correctness here is what makes the rest of the pipeline trustworthy.

Bases: object

Tunable parameters of the ensemble combine.

Defaults match config_540_orchestrator.yaml.

Parameters:
  • agreement_sigma – Mahalanobis-distance threshold for grouping.

  • agreement_pixel_floor – Translation-distance fallback grouping threshold in pixels. Two results are grouped when either their Mahalanobis distance is at most agreement_sigma or their Euclidean translation distance is at most this many pixels. The pixel floor exists because per-technique covariances are CRLB-tight (FFT subpixel localization for BodyDiscCorrelateNav, M-estimator information for the DT-fit techniques), well below the actual position uncertainty driven by model error and pointing residuals; without the floor, results agreeing visually to a few px register as hundreds of sigmas apart and never group. Set to 0.0 to disable the floor.

  • agreement_gap – Minimum summed-confidence gap between best and runner-up groups before declaring a conflict.

  • disagreement_penalty – Multiplier on combined confidence when more than one group existed.

  • conflicted_confidence_multiplier – Additional multiplier when the conflicted branch fires.

  • min_confidence – Final-result threshold below which the ensemble returns NavResult.failed instead of NavResult.ok.

  • pinvh_rcond – rcond for scipy.linalg.pinvh.

  • max_allowed_rotation_deg – Maximum magnitude (in degrees) a 3-DoF result’s rotation may take before the ensemble rejects it. The rotation parameter is combined as a small angle (circular mean of (dv, du, theta) triples); this bound enforces the small-angle assumption that every contributing technique fits against (every DT/star technique clamps its rotation to +-max_rotation_deg, default 5 deg). A 3-DoF result arriving with abs(rotation_rad) at or above this bound is a programming error upstream and trips an assertion.

  • tier_thresholds – Mapping rank -> {min_confidence, max_sigma_px}; see derive_confidence_rank.

Derive the five-bucket confidence rank from confidence + sigma.

max_sigma_px compares max(sigma_dv, sigma_du) only. high / medium / low tiers require both confidence and sigma constraints; conflicted and failed are status-driven and not chosen here.

Parameters:
  • confidence – Combined confidence in [0, 1].

  • sigma_px – Per-axis 1sigma marginal uncertainty (use None to mean “unknown / not applicable”).

  • tier_thresholds – Mapping rank -> {min_confidence, max_sigma_px} with max_sigma_px allowed to be None.

Returns:

'high', 'medium', or 'low' if any tier matches; else 'failed'.

Reconcile per-technique results into a single NavResult.

Parameters:
  • results – Per-technique results from one or both passes.

  • feature_inventory – Feature inventory (kept + gated entries).

  • image_classifier – Image-quality classifier verdict.

  • provenance – Reproducibility envelope.

  • config – Optional EnsembleConfig overrides.

  • model_metadata – Optional per-NavModel diagnostic dict map.

  • annotations – Optional pre-built annotation collection from the orchestrator’s _collect_annotations pass.

Returns:

A single NavResult — ok / conflicted / failed.

Curator — turn a NavResult into a JSON-friendly metadata dict.

The curator picks JSON-friendly fields from a NavResult, rounds floats to documented precision, replaces inf with the JSON_INF_SENTINEL finite sentinel, and emits the navigation_result block consumed by downstream readers.

Every per-technique diagnostic field that ships in the JSON appears in the technique’s CURATOR_FIELDS allow-list; assert_diagnostic_fields_present fails CI if a new diagnostic field is added without updating the allow-list.

Verify every per-technique diagnostic field has a CURATOR_FIELDS entry.

An unmapped field is a programmer error and raises AssertionError so CI fails the build before a new diagnostic silently disappears from the JSON output.

Parameters:

result – NavResult whose per_technique entries are inspected.

Raises:

AssertionError – if any field on a diagnostic dataclass is missing from its CURATOR_FIELDS allow-list.

Build the additive navigation_result metadata block.

Output is a JSON-serializable dict; the orchestrator merges it into the existing per-image _metadata.json schema as the additive navigation_result key.

Parameters:

result – The full in-memory NavResult.

Returns:

Dict ready for json.dump.

Raises:

AssertionError – if any diagnostic field is missing a CURATOR_FIELDS entry.

Per-NavStatusReason operator-readable INFO log templates.

The orchestrator emits one INFO line per status_reason summarizing the final outcome. Templates here let tests assert the operator-readable narrative for every reason.

Per-instrument configuration consumed by the orchestrator.

Each ObsSnapshotInst carries its already-resolved per-camera config mapping on obs.inst_config (set by ObsInst.from_file). This module reads the data_units, noise, and image_quality_thresholds blocks defined in config_4N0_inst_*.yaml and returns the values the orchestrator needs.

The returned InstrumentSettings is a plain dataclass so the orchestrator can branch on data_units without re-reading raw YAML.

Bases: object

Per-instrument settings the orchestrator needs at navigate time.

Parameters:
  • data_unitsraw_dn or calibrated_if per config_4N0_inst_*.yaml.

  • saturation_dn – Per-instrument saturation DN; None for calibrated-IF instruments.

  • marker_value – Missing-data sentinel value (0 for most raw instruments; NaN for calibrated-IF).

  • thresholds – Image-quality thresholds for the classifier. All values normalised to the appropriate units (DN for raw_dn, I/F for calibrated_if).

  • fit_camera_rotation – Per-camera flag enabling 3-DoF technique fits.

  • max_rotation_deg – Maximum allowed rotation magnitude when fit_camera_rotation is True.

Build the orchestrator’s per-instrument settings from an obs.

Reads obs.inst_config (an AttrDict populated by ObsInst.from_file) and returns a frozen InstrumentSettings instance. When inst_config is None (test fixtures, simulated obs without per-instrument wiring), defaults appropriate for an untyped raw_dn instrument are returned: saturation_dn=None (no saturation mask) and the standard ImageQualityThresholds defaults so the legacy code path stays unchanged.

Parameters:

obs – An ObsSnapshotInst (or a stand-in carrying the inst_config attribute).

Returns:

An InstrumentSettings instance.

Raises:

ValueError – If inst_config is supplied but missing required fields, or carries an unrecognised data_units value.