Per-Image State (NavContext)
Overview
NavContext is the frozen dataclass that carries
per-image global state shared across feature extraction and technique navigation. The
orchestrator’s
navigate() builds one instance per
image; pass-2 techniques receive a copy with the pass-1 ensemble’s prior offset and
covariance attached via
with_prior(). 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.
Theory
The context is the single source of truth for per-image state. Three invariants apply:
The context is frozen.
with_priorreturns a new instance viadataclasses.replace(); mutation is not supported.Every image-shaped field is extfov-shaped — zero-padded around the original sensor rectangle.
image_extis the canonical post-source-filter extfov image; the matching sensor / saturation / cosmic-ray masks share its shape.The pass-1 → pass-2 hand-off carries only the 2x2 translation block of the prior covariance. Any rotation prior is re-derived per technique from the per-instrument flag, not propagated through the context.
The default values on the dataclass cover the autonomous-pipeline path; the manual-nav dialog and tests construct contexts with relaxed defaults (e.g. no provenance, no classifier).
Restrictions and assumptions
Construction is via direct dataclass instantiation. Validation happens in
with_prior()(the only mutator surface): the prior offset must be finite, the prior covariance must be 2x2 or 3x3 and finite.The frozen-array discipline is enforced via
__post_init__on the prior covariance copy:with_priormakes a writable independent copy and marks it read-only so the caller cannot mutate the prior after the new context is built.The shared image-side derivatives (
image_gradient_ext,image_gradient_vu_ext,image_edge_dt_ext) are optional in the dataclass signature so test contexts that do not need them can omit them; the orchestrator always populates all three for autonomous runs.
Sources of uncertainty
The context dataclass itself reports no uncertainty. Per-image quantities surfaced in the context (the noise sigma, the classifier’s confidence) are reported by the sub-systems that produced them.
Configuration
The dataclass carries no YAML configuration of its own. Field defaults are Python
constants with the documented per-instrument-aware values populated by the orchestrator’s
_make_context.
Implementation
Source file: src/nav/nav_orchestrator/nav_context.py —
NavContext.
Public class NavContext, frozen dataclass.
Public fields (autodocumented at nav.nav_orchestrator):
obs— the observation snapshot under navigation. Typed loosely asobjectto avoid an import cycle.image_ext— extended-FOV image array post any source-image filter.sensor_mask_ext— boolean mask;Truewhere the pixel is real sensor data,Falsefor extfov padding.image_noise_sigma— robust MAD-based noise sigma in the image’s native units (DN forraw_dn, I/F forcalibrated_if).saturation_mask_ext— boolean maskTruewhere pixels are at or above the per-instrument full-well DN.cosmic_ray_mask_ext— boolean maskTruewhere single-pixel cosmic-ray spikes were detected.image_classifier— theNavImageClassifierResultverdict.provenance— per-image reproducibility envelope (Provenance).image_gradient_ext— Optional shared Sobel-of-Gaussian magnitude (computed once, reused by every DT technique).image_gradient_vu_ext— Optional(H, W, 2)per-pixel gradient-vector image;[..., 0]isg_v,[..., 1]isg_u.image_edge_dt_ext— Optional shared signed distance transform of the thresholded gradient image.prior_offset_px— pass-2 prior offset;Noneon pass 1.prior_covariance_px2— pass-2 prior covariance;Noneon pass 1.pre_filter_applied— theNavFilterSpecapplied to the source image,Noneif none.fit_camera_rotation— bool; turns on 3-DoF technique fits. DefaultFalse.max_rotation_deg— float; rotation cap whenfit_camera_rotationisTrue. Default5.0deg.
Public methods:
with_prior()— return a newNavContextwith the pass-1 prior attached. Validates the offset (finite, length-2) and the covariance (2x2 or 3x3, finite); the rotation block is dropped.
The dataclass declares eq=False on @dataclass(frozen=True, eq=False);
NavContext instances are compared by identity
because the numpy-array fields prevent the default dataclass equality.
Examples
Pass 1 context. The orchestrator’s _make_context builds a
NavContext with the per-instrument settings
populated and the prior fields None:
context = NavContext(
obs=obs,
image_ext=image,
sensor_mask_ext=sensor_mask,
image_noise_sigma=4.7,
saturation_mask_ext=sat_mask,
cosmic_ray_mask_ext=cr_mask,
image_classifier=classifier_result,
provenance=prov,
image_gradient_ext=grad,
image_gradient_vu_ext=grad_vu,
image_edge_dt_ext=edge_dt,
pre_filter_applied=None,
fit_camera_rotation=False,
max_rotation_deg=5.0,
)
Pass 2 hand-off. After the pass-1 ensemble produces an offset, the orchestrator
calls
with_prior() with the pass-1 offset
and covariance. The returned context carries the prior on
prior_offset_px and
prior_covariance_px2; pass-2
techniques like
StarRefineNav consume those.
Field-by-field illustration on ``body_partial_overflow``. After the orchestrator’s
_make_context builds the per-image state for the Rhea-overflow scene, the context
fields might be:
NavContext(
image_classifier.image_class = 'clean',
image_noise_sigma = 4.7, # DN
saturation_mask_ext.sum() = 0, # no saturated pixels
cosmic_ray_mask_ext.sum() = 12, # 12 cosmic-ray hits
fit_camera_rotation = False, # Cassini default
prior_offset_px = None, # pass 1
)
The pass-2 hand-off attaches
prior_offset_px
= (12.06, 30.53) once BodyLimbNav
reports its result.