Orchestrator (NavOrchestrator)
Overview
NavOrchestrator is the top-level driver that
turns one observation into one
NavResult. The driver builds the per-image
NavContext, runs every registered
NavModel’s
create_model() and
to_features(), applies the feature-reliability
gate, runs every feasible prior-free
NavTechnique (pass 1), reconciles those results
into a prior via ensemble(), runs every feasible
prior-required technique against that prior (pass 2), and reconciles the union of pass-1
and pass-2 results into the final
NavResult.
Two passes, four short-circuit gates, and an exception-sandbox discipline keep the driver
from raising through to its caller — every failure mode surfaces on the returned
NavResult instead. The four short-circuit gates
are:
_HARD_FAILURE_TO_REASON— theNavImageClassifierreportsblank,fully_overexposed,mostly_missing_data, orcorrupt.NO_FEATURES_EXTRACTED— everyNavModelemitted zero features.ALL_FEATURES_GATED— the reliability gate dropped every emitted feature.NO_FEASIBLE_TECHNIQUES— pass 1 produced zero technique results (no technique was feasible on the gated cohort).
Theory
The orchestrator is a deterministic pipeline. Each per-image run is a sequence of stages:
build context, build models, extract features, gate features, run pass 1, fuse pass 1 into a
prior, run pass 2, fuse the union, return a
NavResult.
Pipeline stages
Provenance and context. Build a reproducibility envelope (git SHA, loaded SPICE kernels, static-data hashes) and a per-image global-state container. The context carries the extfov image, the per-image masks (sensor / saturation / cosmic-ray), the per-image noise sigma, the image-quality classifier verdict, the shared image-side derivatives (gradient magnitude, gradient vector, edge distance transform), and the per-instrument settings (data units, rotation flag, max rotation cap, signal-to-image scale).
Model construction. Iterate the registered
NavModelset, calling each model’screate_model()per the operator’sonly_modelsglob filter. An exception in any model is logged and the model is dropped from the per-image set.Feature extraction. Each surviving model’s
to_features()is invoked; an exception is logged and the model contributes zero features.Reliability gate. The per-feature reliability gate (an instance of
FeatureReliabilityGate) drops features whose per-featurereliabilityscore falls below the per-type floor.Pass 1. Run every registered technique with
requires_priorFalsewhoseaccepts_feature_typesoverlaps the surviving feature set and whoseis_feasiblereports feasible.Pass-1 ensemble. Reconcile the pass-1 results via
ensemble(). When the ensemble produces an offset, that offset and its covariance become the pass-2 prior; when the ensemble fails the technique pipeline returns a failedNavResultimmediately.Pass 2. Run every prior-required technique with the pass-2 context (a copy of the pass-1 context with the prior offset attached via
with_prior()).Final ensemble. Reconcile the union of pass-1 and pass-2 results into the final
NavResult.
Exception-sandbox discipline
Every NavModel callback (create_model,
to_features, to_annotations) and every
NavTechnique callback (navigate)
runs inside a broad except Exception block. An
exception is logged with full traceback and the offending model or technique is treated as
if it produced no output. This is intentional — the orchestrator must never raise through
to its caller; failures land on the
status field instead so the per-image
JSON sidecar always exists.
Glob-pattern model and technique filters
The constructor accepts only_models and only_techniques glob patterns (or pattern
lists) so an operator can restrict which models or techniques run for debugging. The
syntax matches gitignore-style globs with leading ! for exclusion. The model-name
convention is prefix:VALUE (rings:SATURN, body:DIONE, plain stars for the
catalog star model); a pattern missing a colon expands to prefix:* so the common
shorthand (rings) matches every namespaced ring model under that prefix.
Restrictions and assumptions
The orchestrator assumes
NavModelandNavTechniquesubclasses are well-formed and non-malicious — the exception sandbox catches programmer bugs but cannot recover from state-corrupting plugins.The pass-1 → pass-2 hand-off only fires when the pass-1 ensemble produces a non-failed offset. When pass 1 fails, pass 2 does not run.
The image-quality classifier’s hard-failure short-circuit fires before any model is constructed; a
blankorfully_overexposedimage never invokes aNavModel.
Sources of uncertainty
The orchestrator itself reports no uncertainty. Per-technique uncertainty is captured in
each technique’s
covariance_px2; the final
covariance_px2 is the
precision-weighted-merge result from
ensemble().
Configuration
The orchestrator’s runtime knobs come from three places: per-instrument YAML
(config_4N0_inst_*.yaml via
InstrumentSettings), construction-time
overrides on the constructor, and the per-image
NavContext’s default values.
Per-instrument YAML keys (read via
instrument_settings_from_obs()):
data_units—raw_dnorcalibrated_if. Drives the saturation-mask and noise-sigma branches.noise.saturation_dn— saturation DN threshold (raw_dnonly).noise.marker_value— missing-data marker DN.image_quality_thresholds.*— the per-instrumentImageQualityThresholdsvalues.camera_rotation.fit_camera_rotation— bool; turns on 3-DoF technique fits.camera_rotation.max_rotation_deg— float; rotation cap.
Constructor-level overrides:
models— list of constructedNavModelinstances. The caller builds these per-image.config— optionalConfigoverride.only_models— glob pattern or list selecting which models run. Default'*'.only_techniques— glob pattern or list selecting which techniques run. Default'*'.ensemble_config— optionalEnsembleConfigoverride.image_quality_thresholds— optionalImageQualityThresholdsoverride.image_derivatives_config— optionalImageDerivativesConfigoverride.rms_nav_version— string written into provenance.
Implementation
Source files:
src/nav/nav_orchestrator/orchestrator.py—NavOrchestrator, the_HARD_FAILURE_TO_REASONmapping, the_ModelRegistryglob-filter helper, and the per-stage private methods.src/nav/nav_orchestrator/nav_context.py—NavContext; documented at Per-Image State (NavContext).src/nav/nav_orchestrator/nav_result.py—NavResult; documented at Final Output (NavResult).src/nav/nav_orchestrator/ensemble.py—ensemble(); documented at Ensemble Combine (ensemble + EnsembleConfig).src/nav/nav_orchestrator/image_classifier.py—NavImageClassifier; documented at Image Classifier (NavImageClassifier).src/nav/nav_orchestrator/image_derivatives.py—compute_all_image_derivatives(); documented at Image Derivatives (Shared Gradient and Edge DT).src/nav/nav_orchestrator/instrument_config.py—InstrumentSettings; documented at Per-Instrument Settings (InstrumentSettings).src/nav/nav_orchestrator/provenance.py—Provenance; documented at Reproducibility Envelope (Provenance).src/nav/nav_orchestrator/status_reason_info.py—STATUS_REASON_INFO_TEMPLATE, the per-status-reason operator log lines.src/nav/feature/reliability.py—FeatureReliabilityGateandGatedFeatureRecord.
Public class NavOrchestrator, base
NavBase.
Public methods (autodocumented at nav.nav_orchestrator):
prepare()— build per-image state without running any technique. Returns(context, features). Used by the manual-nav dialog.navigate()— run the full pipeline on one observation. Returns oneNavResult.
Call path
Call path traced through
navigate():
Build the
Provenanceenvelope.Build the per-image
NavContextand the image classifier verdict. Log the verdict at INFO.Hard-failure short-circuit. When the classifier’s
image_classis in_HARD_FAILURE_TO_REASON(blank/fully_overexposed/mostly_missing_data/corrupt), return a failedNavResultwith the matchingNavStatusReason.Build every
NavModelby invokingcreate_model()(exception-sandboxed).Extract features from each surviving model (
to_features(), exception-sandboxed) and apply the reliability gate.Build the feature inventory, the model metadata snapshot, and the merged annotations.
Three short-circuit gates on the gated cohort:
NO_FEATURES_EXTRACTEDwhen every model emitted zero features.ALL_FEATURES_GATEDwhen the gate dropped every feature.
Each returns a failed
NavResultvia the_failhelper.Pass 1. Run every prior-free technique whose feature types overlap the gated cohort and whose
is_feasiblereturns feasible. An exception in any technique is logged and the technique contributes no result.NO_FEASIBLE_TECHNIQUES when pass 1 produced zero results — return a failed
NavResult.Reconcile pass-1 results via
ensemble(). When the ensemble’sstatusis'failed'return the failedNavResult.Build the pass-2 context via
with_prior()carrying the pass-1 ensemble’s offset and covariance.Pass 2. Run every prior-required technique against the pass-2 context.
Reconcile the union of pass-1 and pass-2 results via
ensemble()to produce the finalNavResult.Log the final offset / confidence / per-technique summary and the per-status-reason operator INFO lines from
STATUS_REASON_INFO_TEMPLATE.
The _fail helper wraps
failed() and emits the per-status-reason
INFO log lines defined in STATUS_REASON_INFO_TEMPLATE. Every short-circuit gate
listed above invokes _fail to keep the operator log consistent.
Examples
body_partial_overflow(Cassini ISS NAC, imageN1484593951_2)Rhea visible in the upper right with about 22 % of the disc off-frame. The orchestrator builds the body model, extracts LIMB_ARC + BODY_DISC + TERMINATOR_ARC features, runs pass 1 with
BodyLimbNav,BodyDiscCorrelateNav, andBodyTerminatorNav(the latter two flag spurious; only BodyLimb produces a usable result). The pass-1 ensemble selects BodyLimb’s offset of(12.06, 30.53)px, the pass-2 prior is set, and pass 2 runs no prior-required techniques (no STAR features in this scene). The finalNavResultreportsstatus'ok'against the operator-verified offset \((\Delta v, \Delta u) = (11.0, 29.5)\) px.one_bright_star_no_body(Cassini ISS WAC, imageW1449079117_1)Single bright star (Vega) in an otherwise empty FOV. The orchestrator’s pass-1
StarUniqueMatchNavproduces a 1-star prior; pass 2 runsStarRefineNavagainst that prior, polishes the offset, and returns it withconfidencecapped at 0.5 by the single-inlier post-sigmoid cap. The final ensemble fuses both technique results and reportsstatus'ok'against the operator-verified offset \((\Delta v, \Delta u) = (3.06, -0.02)\) px.star_dominated(Cassini ISS WAC, imageW1580760393_1)Dense star field with no body in FOV. Pass 1 runs
StarFieldFromCatalogNav, which produces a multi-star prior via the triplet hash; pass 2 runsStarRefineNav, which polishes the offset using the full predictable cohort. The final ensemble fuses both and reports the operator-verified offset \((\Delta v, \Delta u) = (-2.68, -3.68)\) px.
Hard-failure short-circuit example. An over-exposed Cassini calibration target
returns the classifier’s fully_overexposed class. The orchestrator returns the failed
NavResult with
status_reason
IMAGE_OVEREXPOSED before any NavModel
constructs. The per-image JSON sidecar still
emits with the classifier verdict and the provenance envelope so reviewer tooling can
correlate the failure across an entire campaign.