Skip to content

Stage 3: foundation completion + per-instrument config wiring#114

Merged
rfrenchseti merged 6 commits into
rf_core_rewritefrom
core_rewrite_catchup
Apr 29, 2026
Merged

Stage 3: foundation completion + per-instrument config wiring#114
rfrenchseti merged 6 commits into
rf_core_rewritefrom
core_rewrite_catchup

Conversation

@rfrenchseti
Copy link
Copy Markdown
Collaborator

@rfrenchseti rfrenchseti commented Apr 29, 2026

Summary

Closes Stage 3 of the autonomous-navigation overhaul (AUTONAV_PLAN.md): foundational gaps from Stages 0–2 plus per-instrument config wiring so a real image runs through the pipeline without hard-coded defaults misclassifying it. A second pass added INFO+DEBUG logging across every NavModel, NavTechnique, and the orchestrator.

What shipped (Phase 3 specification)

  • Renumbered every shipped config_NN_*.yaml to three-digit prefixes (010/020/.../950); ring catalogues moved to the 3xx band, per-instrument blocks to the 4xx band; bootstrap scalar angle fields converted to degrees.
  • Per-camera data_units / noise: / image_quality_thresholds: / mag_offset: / source_image_filter: / fit_camera_rotation: / max_rotation_deg: blocks added to every config_4N0_inst_*.yaml. A parallel cassini_iss_calib: block was added because the Cassini loader picks the calibrated-IF block when the filename contains _CALIB; raw-DN and CALIB I/F products no longer share the same blank / saturation / noisy thresholds (regression: CALIB images were misclassified as blank against raw-DN thresholds).
  • nav.nav_orchestrator.instrument_config.instrument_settings_from_obs(obs) translates the per-camera YAML block into a frozen InstrumentSettings dataclass; missing data_units, missing noise.saturation_dn (raw_dn), and missing image_quality_thresholds blocks fail fast at navigate time.
  • The orchestrator's hard-coded DEFAULT_FULL_WELL_DN_12_BIT constant is gone; _make_context now reads the per-instrument saturation DN, image-quality thresholds, and source-image filter from obs.inst_config. Calibrated-IF instruments without preserved raw-saturation flags emit a one-line WARNING and an empty saturation mask.
  • nav.nav_orchestrator.provenance.collect_provenance_metadata() returns the runtime-derived git SHA (git rev-parse --short HEAD plus --porcelain dirty-detection), loaded SPICE kernel basenames (via cspyce), and sha256 hex digests of every shipped static-data YAML. The orchestrator's _make_provenance populates Provenance.{rms_nav_git_sha, spice_kernels, static_data_hashes}.
  • STATUS_REASON_INFO_TEMPLATE is wired through every NavResult.failed short-circuit via the new _fail helper.
  • NavModelStars.to_features reads obs.inst_config.mag_offset.{fallback_combo, mag_offset_table} per image and feeds the resolved mag_offset into predicted_snr. The legacy hard-coded mag_offset=0.0 is gone. The PSF-sigma helper handles the actual psfmodel.GaussianPSF interface (sigma_x / sigma_y per-axis attributes); nav.nav_model.stars.predicted_snr.psf_sigma_px is called directly from every site.
  • Every NavTechnique declares confidence_spec: ClassVar[ConfidenceSpec | None] and confidence_attributes: ClassVar[frozenset[str]]. validate_registered_confidence_specs() runs at Config.read_config time. Validation caught a real bug — BodyTerminatorNav referenced mean_phase_angle_factor and mean_albedo_penalty without declaring them.
  • evaluate_sigmoid_combination(..., return_breakdown=True) returns (confidence, ConfidenceBreakdown) carrying per-term raw / normalized / alpha / contribution plus the sigmoid argument and the hard_zero / hard_cap_applied flags. nav.nav_technique.nav_technique.log_confidence_breakdown(logger, breakdown) always logs the breakdown at DEBUG and additionally at INFO when confidence <= 0.1, so calibration bugs surface in the default operator log.
  • Config._load_yaml strips every mapping key starting with _. Documentation-only _sources citation blocks live alongside values in source for human review without bloating the runtime Config object.
  • Initial config_220_body_shape.yaml with 10 bodies. Per Part 0 §74 anti-hallucination rule, every numeric value is null paired with a 'PLACEHOLDER — no source found, calibrate in Phase 10' _sources entry; the runtime fallback (10 % radius default + reliability cap 0.3) handles null values.

Logging additions

  • Per-NavModel and per-NavTechnique section headers via logger.open(...) carry the per-instance context. NavModelBody opens 'CREATE BODY MODEL FOR: <BODY>' / 'EMIT BODY FEATURES: <BODY>'; NavModelRings opens 'CREATE RINGS MODEL' / 'EMIT RINGS FEATURES'; NavModelStars opens 'CREATE STARS MODEL' / 'EMIT STARS FEATURES'; every NavTechnique.navigate body opens with self.logger.open(f'TECHNIQUE: {self.name}'):. Inside a section the per-instance prefix is dropped — the section header already carries that context.
  • INFO covers process narrative + interesting metadata: body subsolar / sub-observer lat-lon / phase / range / km-per-pixel / lit-fraction / silhouette overflow; ring planet / surviving feature count / km/px radial / ring-plane radial range visible in image / edge-vs-annulus / straight-edge counts; star dedup'd count / smear vector / per-star listing via _star_short_info (mirrors the legacy NavModelStars format) / conflict counts; technique features-consumed / converged offset / RMS / inliers / confidence / spurious / at_edge; orchestrator image-classifier verdict / pass-1 prior / pass-2 result counts / final offset+sigma+confidence+rank+per-technique-fusion-count.
  • DEBUG covers internals: bbox / size_ok / shape-class hint / backplane oversample factors / vertex sigma range / coarse-NCC offset / LM iterations / supplementary diagnostics / gated-feature breakdown by feature type / per-technique offset+spurious+at_edge.
  • Ensemble failure paths log the actual measured values, not just the threshold name: combined %.3f < threshold %.3f, gap %.3f < agreement_gap %.3f (best %.3f, runner-up %.3f); conflicted = combined %.3f x multiplier %.3f, combined %.3f, sigma (dv,du) = (%.3f, %.3f) px (max %.3f); tier_thresholds = {...}, all-techniques-spurious technique-name list, unobservable-offset input count.

Plan & docs

  • AUTONAV_PLAN.md Phase 3 section ends with a "What shipped" subsection plus a binding "Logging conventions established in Phase 3" subsection capturing the section-header / INFO / DEBUG / failure-narrative / star-list / confidence-breakdown / pdslogger-only / %-as-format-placeholder rules so future NavModel and NavTechnique additions inherit the conventions automatically. The historical "Pending" snapshot earlier in the file is annotated with "Superseded by core_rewrite_catchup (shipped)" on each affected bullet group.
  • New docs/developer_guide_static_data.rst (citation rules, anti-hallucination procedure, validator tests).
  • New docs/developer_guide_logging.rst (pdslogger conventions, per-status-reason INFO templates, caplog vs capsys).
  • docs/introduction_configuration.rst rewritten for the renumbered set; band notation uses explicit ranges (0xx (000–099) / 1xx (100–199) / 3xx (300–399) / 4xx (400–499) / 9xx (900–999)) to avoid ambiguity with _N0 mid-range values.

Build / CI

  • rms-cloud-tasks>=0.2.0 added as a runtime dependency (the cloud-tasks CLI entry points import cloud_tasks.worker; the package is py.typed, so mypy gets the real types — no override needed).

Review-finding fixes (post-open follow-ups)

  • _resolve_static_data_hashes wraps read_bytes/hashlib.sha256 in try/except OSError and logs a WARNING per skipped file; provenance is best-effort and a transient I/O error must not abort the run.
  • _required_float rejects non-finite (NaN/+-Inf) values with a path-aware ValueError so non-finite YAML values cannot propagate into orchestrator thresholds.
  • instrument_settings_from_obs validates inst_config / iqt_block / noise are mappings via isinstance(Mapping) and data_units is a string before the literal-membership test.
  • BodyLimbNav / BodyTerminatorNav / RingEdgeNav use self.confidence_spec (class attribute) instead of the module-level _*_CONFIDENCE_SPEC constants, eliminating drift risk.
  • log_confidence_breakdown now emits the per-term DEBUG breakdown on every call (including the hard-zero path) and additionally an INFO summary when confidence <= low_threshold, matching the docstring.
  • obs_inst_cassini_iss raises a descriptive ValueError when the config section or detector lookup fails, naming both and listing available detectors, instead of a bare KeyError.
  • config_420_inst_nhlorri.yaml carries a documentation-only _sources block citing every numeric value (Part 0 §74 binding extends to per-camera blocks; stripped at load time by Config._load_yaml).
  • detect_sources PSF docstring updated to reference the psf_sigma_px helper (handles per-axis sigma_x/sigma_y, single sigma, fwhm()).
  • test_config_load adds the newhorizons_lorri instrument check and replaces truthiness assertions on mag_offset.fallback_combo with concrete equality assertions per instrument.
  • test_provenance replaces the tautological isinstance(meta.static_data_hashes, dict | type(meta.static_data_hashes)) assertion with explicit Mapping + MappingProxyType + key/value-type checks.

Test plan

  • ruff check src tests clean
  • ruff format --check src tests clean
  • mypy src tests clean (256 files, 0 issues)
  • pytest -n auto --dist=loadfile — 1044 fast tests pass
  • tests/nav/inst/test_inst_cassini_iss.py::test_cassini_iss_calib_filename_selects_calib_inst_config passes against the real PDS holdings
  • sphinx-build -W -b html docs docs/_build clean
  • pymarkdown scan docs/ .cursor/ README.md CONTRIBUTING.md clean
  • ./scripts/run-all-checks.sh green end-to-end

Calibration items still parked for Stage 10

  • Every # PLACEHOLDER line in config_4N0_inst_*.yaml (read noise, expected noise, mag-offset tables).
  • Every null value in config_220_body_shape.yaml (≤ 10 bodies per PR per the human-review rule).
  • The ring-edge confidence spec consumes per_edge_dt_rms_summed un-divided and saturates to confidence 0 on multi-edge fits even when the underlying RMS is sub-pixel; log_confidence_breakdown surfaces this in the default INFO log when it fires.
  • I/F-domain image-quality thresholds (blank_max_if, saturation_threshold_if, noisy_threshold_if) ship as PLACEHOLDER guesses.

🤖 Generated with Claude Code

Closes the foundational gaps that should have shipped in Stages 0-2 and
wires enough per-instrument config + static data so a real image runs
through the pipeline without hard-coded defaults misclassifying it.
Adds INFO+DEBUG logging across every NavModel, NavTechnique, and the
orchestrator.

Highlights:

- Renumber config_NN_*.yaml -> config_NNN_*.yaml (3-digit prefix bands:
  0NN global, 1NN catalogues, 3N0 ring catalogues, 4N0 per-instrument,
  9NN downstream products).
- Convert bootstrap angle fields to degrees (max_phase_angle_deg, etc).
- Add per-camera data_units / noise / image_quality_thresholds /
  mag_offset / source_image_filter / fit_camera_rotation /
  max_rotation_deg blocks to every config_4N0_inst_*.yaml; add a
  parallel cassini_iss_calib block for I/F products. Cassini loader
  picks the calibrated-IF block when filename contains _CALIB
  (regression: CALIB images were misclassified as 'blank' against
  raw-DN thresholds).
- Add nav.nav_orchestrator.instrument_config.instrument_settings_from_obs
  translating per-camera YAML into a frozen InstrumentSettings.
- Replace hard-coded _instrument_full_well_dn with a config consumer;
  calibrated-IF instruments emit a one-line WARNING + empty saturation
  mask when no preserved raw-saturation flags exist.
- Populate Provenance.{rms_nav_git_sha, spice_kernels,
  static_data_hashes} via the new collect_provenance_metadata helper.
- Wire NavModelStars.to_features through obs.inst_config.mag_offset;
  fix psf_sigma_px to read psfmodel.GaussianPSF per-axis sigma_x/sigma_y
  (regression: every Cassini star extraction raised AttributeError).
- Per-NavTechnique confidence_spec / confidence_attributes declared;
  validate_registered_confidence_specs runs at config-load time.
  evaluate_sigmoid_combination(..., return_breakdown=True) returns a
  per-term breakdown; log_confidence_breakdown logs at DEBUG always
  and at INFO when confidence <= 0.1 (so calibration bugs surface in
  the operator log).
- Wire STATUS_REASON_INFO_TEMPLATE through every NavResult.failed via
  the new _fail / _log_status_reason helpers. Ensemble failure paths
  now log actual measured values (combined-confidence vs threshold,
  best-vs-runner-up gap, sigma vs tier max, etc).
- INFO+DEBUG logging across every NavModel, NavTechnique, and the
  orchestrator, with section headers via logger.open carrying the
  per-instance context. NavModelStars emits the legacy-format per-star
  INFO listing via _star_short_info.
- Initial config_220_body_shape.yaml with 10 bodies. Per Part 0 §74
  anti-hallucination rule: every numeric field is null with a
  PLACEHOLDER citation; runtime fallback handles null values.
  Citations populated in Stage 10.
- Config._load_yaml strips _sources blocks at load time so citations
  live alongside values in source for human review without bloating
  runtime config.

Documentation:

- docs/developer_guide_static_data.rst (citation rules,
  anti-hallucination procedure, validator tests).
- docs/developer_guide_logging.rst (pdslogger conventions, INFO/DEBUG
  split, capsys vs caplog).
- docs/introduction_configuration.rst rewritten for the renumbered
  config_NNN_*.yaml set.
- AUTONAV_PLAN.md updated: Stage 3 marked complete with a "What
  shipped" subsection and a "Logging conventions established in Stage
  3 (binding)" subsection capturing the per-section-header / INFO /
  DEBUG / failure-narrative / confidence-breakdown rules for future
  NavModel and NavTechnique additions.
- phase_03_review/ — seven CRITIQUE_*.md reports per the per-phase
  definition of done.

Verification: ruff check + format clean; mypy --strict clean (256
files); pytest -n auto --dist=loadfile passes 1043 fast tests; sphinx
-W clean; pymarkdown clean; ./scripts/run-all-checks.sh green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

Walkthrough

Phase 3 deliverables update autonomous-navigation with configuration file renumbering (2-digit to 3-digit prefixes), YAML loader key stripping, instrument-specific noise/magnitude/image-quality settings, provenance metadata collection (git SHA, SPICE kernels, static hashes), confidence-spec validation at config load, enhanced confidence breakdown computation/logging, and comprehensive developer documentation.

Changes

Cohort / File(s) Summary
Configuration File Renumbering & YAML Loader
src/nav/config/config.py, src/nav/config_files/config_07_bootstrap.yaml, docs/introduction_configuration.rst
Updated YAML filename convention from 2-digit to 3-digit numeric prefixes (e.g., config_07_bootstrap.yamlconfig_070_bootstrap.yaml). Config loader now recursively strips dict keys starting with _ before returning parsed config, while preserving raw YAML for validation. Adds body_shape property to Config and _validate_registered_techniques() method.
Instrument Configuration Infrastructure
src/nav/nav_orchestrator/instrument_config.py
New module introducing InstrumentSettings frozen dataclass and instrument_settings_from_obs() function to extract per-instrument settings (data units, noise markers, saturation DN, image-quality thresholds, rotation limits) from observation configs, with validation and fallback defaults.
Per-Instrument Configuration Files (Cassini ISS)
src/nav/config_files/config_30_inst_coiss.yaml, src/nav/config_files/config_400_inst_coiss.yaml, src/nav/obs/obs_inst_cassini_iss.py
Cassini ISS config split into raw-DN and calibrated I/F variants under new 3-digit filenames. Config now specifies noise/saturation/missing-pixel markers, image-quality thresholds, rotation parameters, source-image filters, and magnitude-offset tables with placeholders. Observation loader now detects _CALIB filename suffix to select appropriate config block.
Per-Instrument Configuration Files (Other Instruments)
src/nav/config_files/config_31_inst_gossi.yaml, src/nav/config_files/config_32_inst_nhlorri.yaml, src/nav/config_files/config_33_inst_vgiss.yaml, src/nav/config_files/config_40_sim.yaml, src/nav/config_files/config_410_inst_gossi.yaml, src/nav/config_files/config_420_inst_nhlorri.yaml, src/nav/config_files/config_430_inst_vgiss.yaml, src/nav/config_files/config_440_sim.yaml
Moved/replaced Galileo SSI, New Horizons LORRI, Voyager ISS, and simulation configurations from 2-digit to 3-digit filenames with expanded per-instrument settings (noise parameters, image-quality thresholds, rotation fitting, source filters, magnitude offsets) and placeholders for Phase 10 calibration.
Body-Shape Configuration
src/nav/config_files/config_220_body_shape.yaml, tests/nav/config_files/test_body_shape_citations.py
New body-shape catalog with per-body parameters (radii, ellipsoid RMS, crater scale, albedo) set to null placeholders with mandatory _sources citations. Test suite validates citation completeness, forbids TODO/FIXME/XXX tokens, enforces placeholder-only-with-null pairing, and verifies loader strips _sources at runtime.
Provenance Metadata Collection
src/nav/nav_orchestrator/provenance.py, tests/nav/nav_orchestrator/test_provenance.py
New ProvenanceMetadata dataclass and collect_provenance_metadata() function to gather git SHA (with -dirty suffix), loaded SPICE kernel basenames, and static-data YAML SHA-256 hashes. Updated module exports and comprehensive test coverage.
Confidence Specification & Validation
src/nav/nav_technique/confidence.py, src/nav/nav_technique/nav_technique.py, tests/nav/nav_technique/test_nav_technique.py
Enhanced evaluate_sigmoid_combination() with optional return_breakdown parameter returning ConfidenceBreakdown dataclass. New NavTechnique class attributes confidence_spec and confidence_attributes for spec declaration. Added log_confidence_breakdown() helper and validate_registered_confidence_specs() function that validates specs reference only declared attributes (called at config load time).
Per-Technique Confidence Metadata
src/nav/nav_technique/nav_technique_body_limb.py, src/nav/nav_technique/nav_technique_body_terminator.py, src/nav/nav_technique/nav_technique_ring_edge.py
Each technique now declares confidence_spec and confidence_attributes, requests confidence breakdown during evaluation, and logs detailed per-term contributions. Added structured logging of aggregated input statistics, fit diagnostics, and conditional logging of spurious/at-edge flags.
Navigation Model Logging Enhancements
src/nav/nav_model/nav_model_body.py, src/nav/nav_model/nav_model_rings.py, src/nav/nav_model/stars/nav_model_stars.py
Enhanced model creation and feature emission with structured logger contexts, INFO timing summaries, DEBUG geometry/render metadata, and per-feature category counts. Stars model added magnitude-offset resolution from obs.inst_config, conflict detection, and per-star short-info logging.
PSF Sigma Consolidation
src/nav/nav_model/stars/predicted_snr.py, src/nav/nav_model/stars/detection.py, tests/nav/nav_model/stars/test_predicted_snr.py
Unified psf_sigma_px() function now prioritizes anisotropic sigma_x/sigma_y (averaging them), then falls back to single sigma and fwhm(). Removed duplicate PSF-sigma logic from detection.py. Updated test stubs to cover both single-sigma and per-axis forms.
Orchestrator Control Flow & Logging
src/nav/nav_orchestrator/orchestrator.py, src/nav/nav_orchestrator/status_reason_info.py, src/nav/nav_orchestrator/ensemble.py, src/nav/feature/reliability.py
Orchestrator now routes failures through _fail() wrapper emitting STATUS_REASON_INFO_TEMPLATE INFO lines. Removed hardcoded 12-bit saturation DN in favor of instrument-settings-derived saturation mask. Added per-instrument source-image filter application and image-quality-threshold loading. Improved ensemble/gating/classification/technique logging. Updated template wording for IMAGE_OVEREXPOSED and MISSING_DATA_DOMINANT. Minor import restructuring in reliability.py.
Configuration and Instrument Tests
tests/nav/config_files/test_config_load.py, tests/nav/inst/test_inst_cassini_iss.py, tests/nav/nav_orchestrator/test_instrument_config.py
Added config smoke tests (merge completion, bootstrap degrees, per-instrument field presence, body-shape loading). Cassini ISS calibrated-product regression test. Comprehensive instrument_settings_from_obs() tests covering defaults, raw-DN/calibrated-IF parsing, validation, and shipped config blocks.
Developer Documentation
docs/developer_guide.rst, docs/developer_guide_logging.rst, docs/developer_guide_static_data.rst
Two new developer guides added to navigation: "Logging" documents pdslogger routing, technique section framing, status-reason templates, and test patterns (capsys vs. caplog); "Static Data" documents YAML catalog schema, per-instrument parameters, citation requirements, anti-hallucination rules, and placeholder conventions.
Phase 3 Review Documentation
AUTONAV_PLAN.md, phase_03_review/CRITIQUE_SUMMARY.md, phase_03_review/CRITIQUE_CODEBASE.md, phase_03_review/CRITIQUE_DOCS.md, phase_03_review/CRITIQUE_FILECACHE.md, phase_03_review/CRITIQUE_LOGGING.md, phase_03_review/CRITIQUE_PYTHON.md, phase_03_review/CRITIQUE_TESTS.md
Phase 3 marked complete with "What shipped" and binding logging conventions recorded. Eight critique documents provide structured review of codebase changes, documentation updates, filecache best practices, logging conventions, Python patterns, test additions, and summary of findings/verification.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately reflects the main change: completing Stage 3 and wiring per-instrument configuration into the navigation pipeline.
Docstring Coverage ✅ Passed Docstring coverage is 89.26% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering purpose, changes, testing, and potential impacts with clear organization.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 77.63975% with 108 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (rf_core_rewrite@c36ada2). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/nav/nav_orchestrator/orchestrator.py 64.44% 25 Missing and 7 partials ⚠️
src/nav/nav_model/stars/nav_model_stars.py 65.00% 18 Missing and 3 partials ⚠️
src/nav/nav_orchestrator/instrument_config.py 78.46% 7 Missing and 7 partials ⚠️
src/nav/nav_orchestrator/provenance.py 74.50% 11 Missing and 2 partials ⚠️
src/nav/nav_model/nav_model_rings.py 79.54% 6 Missing and 3 partials ⚠️
src/nav/nav_model/nav_model_body.py 86.11% 3 Missing and 2 partials ⚠️
src/nav/nav_technique/nav_technique.py 87.50% 2 Missing and 2 partials ⚠️
src/nav/obs/obs_inst_cassini_iss.py 50.00% 2 Missing and 2 partials ⚠️
src/nav/nav_orchestrator/ensemble.py 66.66% 2 Missing ⚠️
src/nav/nav_technique/nav_technique_ring_edge.py 80.00% 1 Missing and 1 partial ⚠️
... and 2 more
Additional details and impacted files
@@                Coverage Diff                 @@
##             rf_core_rewrite     #114   +/-   ##
==================================================
  Coverage                   ?   49.33%           
==================================================
  Files                      ?      126           
  Lines                      ?    15129           
  Branches                   ?     2069           
==================================================
  Hits                       ?     7464           
  Misses                     ?     7135           
  Partials                   ?      530           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rfrenchseti rfrenchseti changed the base branch from main to rf_core_rewrite April 29, 2026 00:46
@rfrenchseti
Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

rfrenchseti and others added 3 commits April 28, 2026 17:50
CI doesn't install ``rms-cloud-tasks`` (it's not a declared dev dep), so
mypy errors out on every ``from cloud_tasks.worker import Worker`` site.
Add a ``cloud_tasks.*`` override matching the existing pattern for other
optional/external deps.

Also annotate the one site that already carried ``# type: ignore[attr-
defined]`` with ``unused-ignore`` so the ignore is accepted in both
environments — the attribute is real when ``cloud_tasks`` is installed
locally (ignore is needed) and the line type-checks cleanly when the
package is missing on CI (ignore would otherwise be flagged unused).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The cloud-tasks CLI entry points (nav_offset_cloud_tasks,
nav_backplanes_cloud_tasks, nav_create_bundle_cloud_tasks,
nav_mosaic_cloud_tasks) all import ``cloud_tasks.worker`` at module
top — that's a runtime requirement, not an optional extra. The
package is typed (ships ``py.typed``), so mypy gets the real types
once it's installed; no ``ignore_missing_imports`` override is
appropriate.

Reverts the previous commit's ``cloud_tasks.*`` mypy override and the
``unused-ignore`` annotation on
``nav_mosaic_cloud_tasks._data.nav_results_root_path``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@AUTONAV_PLAN.md`:
- Around line 2253-2256: The document shows "Phase 3 — Foundation completion +
per-instrument config wiring (complete)" but later snapshot still lists Phase 3
items as pending; update the snapshot/pending bullets so they no longer conflict
by either marking those specific checklist entries as completed or adding a
clear "historical / superseded" annotation that references the shipped branch
`core_rewrite_catchup` and the "Phase 3 — Foundation completion + per-instrument
config wiring (complete)" heading; locate the pending bullets under the later
snapshot section and either change their status to complete, remove duplicate
pending entries, or prepend "Superseded by core_rewrite_catchup (shipped)" to
each affected bullet so the plan has a single, unambiguous source of truth.

In `@docs/introduction_configuration.rst`:
- Around line 42-45: The phrasing uses ambiguous numeric range notation "3N0"
and "4N0" which can be misread as numbers ending in 0; update the sentence that
currently mentions "3N0" and "4N0" to use explicit range notation such as "3xx
(300–399)" and "4xx (400–499)" or "300–399" and "400–499" so readers clearly
understand these are full 3xx/4xx ranges rather than values ending in 0; keep
the surrounding examples for "0NN", "1NN", and "9NN" consistent with this
clearer format.

In `@src/nav/config_files/config_420_inst_nhlorri.yaml`:
- Around line 15-35: Add a top-level "_sources" metadata block documenting
provenance for the new static calibration keys introduced here (noise and
mag_offset) so reviewers can trace the Phase 10 placeholder values;
specifically, add entries under "_sources" that reference the "noise" and
"mag_offset" keys (and any subkeys like "read_noise_dn" / "saturation_dn" /
"mag_offset_table") with brief provenance notes, since Config._load_yaml()
strips underscore-prefixed keys and this will not affect runtime behavior.

In `@src/nav/config/config.py`:
- Around line 126-129: Replace non-ASCII punctuation in the docstrings/comments
that mention documentation-only ``_sources`` blocks: change the section symbol
and em-dash to ASCII equivalents (e.g., "Part 0 §74" -> "Part 0, Section 74" or
"Part 0 Section 74"; and replace the em-dash "—" with a hyphen "-" or the word
"dash") so all comments/docstrings in src/nav/config/config.py (including the
lines referencing _sources and the nearby comment group) use only ASCII
punctuation per the repository rule; update any similar occurrences around the
same block (the other comment group that spans the next paragraph) to match.

In `@src/nav/nav_model/stars/detection.py`:
- Line 401: The detect_sources docstring is out of date: the code now derives
PSF sigma via psf_sigma_px(psf) instead of only using a numeric sigma or fwhm(),
so update the detect_sources docstring to reflect the shared helper contract;
state that the PSF may be provided as a PSF object and that sigma is obtained by
calling psf_sigma_px(psf) (or accept a numeric sigma), describe expected
types/units returned by psf_sigma_px, and adjust parameter/returns/examples to
reference psf_sigma_px and the PSF input (mention detect_sources as the function
to edit and psf_sigma_px(psf) as the helper).

In `@src/nav/nav_orchestrator/instrument_config.py`:
- Around line 77-88: _required_float currently allows non-finite numeric values
(NaN/Inf) which can corrupt downstream logic; update _required_float to reject
non-finite values by checking math.isfinite(value) (import math) after the
isinstance numeric checks and raise a ValueError with a clear path-aware message
(e.g. "{location}.{key} must be a finite numeric value; got ...") when the value
is not finite so only finite floats are returned.
- Around line 114-139: instrument_settings_from_obs currently dereferences
inst_config, noise and image_quality_thresholds without type checks; update the
function to validate that inst_config is a mapping/dict before using
getattr/get, ensure data_units is a str (and one of 'raw_dn'|'calibrated_if'),
ensure iqt_block (image_quality_thresholds) is a mapping before constructing
ImageQualityThresholds, and when data_units == 'raw_dn' ensure noise is a
mapping/dict (and its expected numeric fields are numbers or raise
TypeError/ValueError). Reference symbols: inst_config,
data_units_raw/data_units, iqt_block, noise, InstrumentSettings and
ImageQualityThresholds; raise clear ValueError/TypeError with descriptive
messages when types or required blocks are invalid.

In `@src/nav/nav_orchestrator/provenance.py`:
- Around line 184-190: The loop in _resolve_static_data_hashes() currently calls
path.read_bytes() and lets any I/O exceptions propagate, which can abort the
whole run; change it to catch exceptions around reading/hashing each file
(inside the for path in sorted(config_dir.glob('*.yaml')) loop), log a warning
including the filename and exception, and skip that file so hashes (the dict
returned as MappingProxyType) only include successfully-read files; keep the
existing prefix filter using _STATIC_DATA_PREFIXES and preserve the return of
MappingProxyType(hashes).

In `@src/nav/nav_technique/nav_technique_body_terminator.py`:
- Around line 330-333: In the navigate method replace the hard-coded use of
_BODY_TERMINATOR_CONFIDENCE_SPEC when calling evaluate_sigmoid_combination with
the instance/class-level confidence_spec so the class-declared configuration is
honored; specifically update the evaluate_sigmoid_combination call (currently
passing _BODY_TERMINATOR_CONFIDENCE_SPEC) to pass self.confidence_spec (and keep
the other args like confidence_context and technique_name=self.name unchanged)
to prevent confidence-spec drift.

In `@src/nav/nav_technique/nav_technique.py`:
- Around line 52-73: The current logic uses a single "log = logger.info if
promote_to_info else logger.debug" which causes DEBUG output to be skipped for
hard_zero and low-confidence cases; change it so the detailed breakdown is
always emitted with logger.debug and, when promote_to_info is true (or hard_zero
path requires an INFO summary), also emit an INFO-level message. Concretely,
replace the use of the single "log" variable: always call logger.debug for the
summary line and for each term in breakdown.terms, and if promote_to_info is
true call logger.info with the same summary (and optionally the same per-term
lines) so INFO is an additional promotion; also in the breakdown.hard_zero
branch, emit the DEBUG summary before returning and then emit the INFO line
stating confidence forced to 0. Use the existing symbols breakdown,
low_threshold, promote_to_info, breakdown.hard_zero, breakdown.hard_cap_applied,
and breakdown.terms to find where to change the logging.

In `@src/nav/obs/obs_inst_cassini_iss.py`:
- Line 71: The current lookup inst_config =
config.category(inst_section)[detector] can raise a bare KeyError; update the
code around that lookup (the inst_config assignment in obs_inst_cassini_iss.py)
to explicitly validate that inst_section exists in config.category(...) and that
detector is a key in that returned mapping, and if either is missing raise a
ValueError containing both inst_section and detector values; e.g., fetch the
category dict into a local (e.g., category_dict =
config.category(inst_section)), check for detector in category_dict (and
wrap/validate config.category call so a missing section produces a clear
ValueError), and then assign inst_config from category_dict[detector] only after
validation so callers get a descriptive ValueError instead of KeyError.

In `@tests/nav/config_files/test_config_load.py`:
- Around line 34-50: The test_per_instrument_required_fields_present smoke test
omits the newhorizons_lorri instrument and uses a lax truthiness check for
mag_offset.fallback_combo; update the test to include
config.category('newhorizons_lorri') and assert exact expected values for all
required keys (data_units, noise.saturation_dn, fit_camera_rotation,
max_rotation_deg, and mag_offset.fallback_combo) rather than truthiness. Locate
the test_per_instrument_required_fields_present function and the
Config().category(...) usages, add a check block for newhorizons_lorri mirroring
the other instruments, and replace the assert
camera['mag_offset']['fallback_combo'] with an equality assertion to the
concrete expected fallback_combo value.

In `@tests/nav/nav_orchestrator/test_provenance.py`:
- Line 63: The assertion using dict | type(meta.static_data_hashes) is
tautological and should be replaced with a concrete check of the expected type
and basic contents; change the assertion to assert
isinstance(meta.static_data_hashes, dict) (or the precise expected type) and
optionally add a sanity check like len(meta.static_data_hashes) >= 0 or that
keys/values match the expected types (e.g., all keys are str and all values are
hashes) to ensure the test actually verifies behavior of
meta.static_data_hashes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 183e5085-7ba5-4e0d-a9a1-a405b18082c2

📥 Commits

Reviewing files that changed from the base of the PR and between c36ada2 and fa323d6.

📒 Files selected for processing (64)
  • AUTONAV_PLAN.md
  • docs/developer_guide.rst
  • docs/developer_guide_logging.rst
  • docs/developer_guide_static_data.rst
  • docs/introduction_configuration.rst
  • phase_03_review/CRITIQUE_CODEBASE.md
  • phase_03_review/CRITIQUE_DOCS.md
  • phase_03_review/CRITIQUE_FILECACHE.md
  • phase_03_review/CRITIQUE_LOGGING.md
  • phase_03_review/CRITIQUE_PYTHON.md
  • phase_03_review/CRITIQUE_SUMMARY.md
  • phase_03_review/CRITIQUE_TESTS.md
  • src/nav/config/config.py
  • src/nav/config_files/config_010_general.yaml
  • src/nav/config_files/config_020_offset.yaml
  • src/nav/config_files/config_030_stars.yaml
  • src/nav/config_files/config_040_bodies.yaml
  • src/nav/config_files/config_050_rings.yaml
  • src/nav/config_files/config_060_titan.yaml
  • src/nav/config_files/config_070_bootstrap.yaml
  • src/nav/config_files/config_07_bootstrap.yaml
  • src/nav/config_files/config_100_satellites.yaml
  • src/nav/config_files/config_220_body_shape.yaml
  • src/nav/config_files/config_300_jupiter_rings.yaml
  • src/nav/config_files/config_30_inst_coiss.yaml
  • src/nav/config_files/config_310_saturn_rings.yaml
  • src/nav/config_files/config_31_inst_gossi.yaml
  • src/nav/config_files/config_320_uranus_rings.yaml
  • src/nav/config_files/config_32_inst_nhlorri.yaml
  • src/nav/config_files/config_330_neptune_rings.yaml
  • src/nav/config_files/config_33_inst_vgiss.yaml
  • src/nav/config_files/config_400_inst_coiss.yaml
  • src/nav/config_files/config_40_sim.yaml
  • src/nav/config_files/config_410_inst_gossi.yaml
  • src/nav/config_files/config_420_inst_nhlorri.yaml
  • src/nav/config_files/config_430_inst_vgiss.yaml
  • src/nav/config_files/config_440_sim.yaml
  • src/nav/config_files/config_900_backplanes.yaml
  • src/nav/config_files/config_950_pds4.yaml
  • src/nav/feature/reliability.py
  • src/nav/nav_model/nav_model_body.py
  • src/nav/nav_model/nav_model_rings.py
  • src/nav/nav_model/stars/detection.py
  • src/nav/nav_model/stars/nav_model_stars.py
  • src/nav/nav_model/stars/predicted_snr.py
  • src/nav/nav_orchestrator/ensemble.py
  • src/nav/nav_orchestrator/instrument_config.py
  • src/nav/nav_orchestrator/orchestrator.py
  • src/nav/nav_orchestrator/provenance.py
  • src/nav/nav_orchestrator/status_reason_info.py
  • src/nav/nav_technique/confidence.py
  • src/nav/nav_technique/nav_technique.py
  • src/nav/nav_technique/nav_technique_body_limb.py
  • src/nav/nav_technique/nav_technique_body_terminator.py
  • src/nav/nav_technique/nav_technique_ring_edge.py
  • src/nav/obs/obs_inst_cassini_iss.py
  • tests/nav/config_files/__init__.py
  • tests/nav/config_files/test_body_shape_citations.py
  • tests/nav/config_files/test_config_load.py
  • tests/nav/inst/test_inst_cassini_iss.py
  • tests/nav/nav_model/stars/test_predicted_snr.py
  • tests/nav/nav_orchestrator/test_instrument_config.py
  • tests/nav/nav_orchestrator/test_provenance.py
  • tests/nav/nav_technique/test_nav_technique.py
💤 Files with no reviewable changes (6)
  • src/nav/config_files/config_40_sim.yaml
  • src/nav/config_files/config_33_inst_vgiss.yaml
  • src/nav/config_files/config_07_bootstrap.yaml
  • src/nav/config_files/config_30_inst_coiss.yaml
  • src/nav/config_files/config_32_inst_nhlorri.yaml
  • src/nav/config_files/config_31_inst_gossi.yaml

Comment thread AUTONAV_PLAN.md
Comment thread docs/introduction_configuration.rst Outdated
Comment thread src/nav/config_files/config_420_inst_nhlorri.yaml
Comment thread src/nav/config/config.py
Comment thread src/nav/nav_model/stars/detection.py
Comment thread src/nav/nav_technique/nav_technique_body_terminator.py
Comment thread src/nav/nav_technique/nav_technique.py Outdated
Comment thread src/nav/obs/obs_inst_cassini_iss.py Outdated
Comment thread tests/nav/config_files/test_config_load.py
Comment thread tests/nav/nav_orchestrator/test_provenance.py Outdated
rfrenchseti and others added 2 commits April 28, 2026 18:10
11 review findings; each verified against current code, fixed when
needed.

- AUTONAV_PLAN.md: snapshot's "Pending" subsection still listed items
  that Phase 3 shipped (per-camera mag-offset wiring, NavContext shared
  derivatives, Provenance population, INFO logging cadence,
  static-data file renumbering + per-camera noise/mag_offset blocks +
  initial config_220_body_shape.yaml, two of the documentation pages).
  Each affected bullet group is now annotated with "Superseded by
  core_rewrite_catchup (shipped)" pointing at the Phase 3 status
  heading; entries that ship in a later phase are kept pending
  inline.
- docs/introduction_configuration.rst: replaced ambiguous "0NN" /
  "1NN" / "3N0" / "4N0" / "9NN" notation with explicit ranges
  (0xx / 1xx / 3xx / 4xx / 9xx with the numeric range in parens).
- config_420_inst_nhlorri.yaml: added a documentation-only ``_sources``
  block citing every numeric value in noise / image_quality_thresholds
  / mag_offset (Part 0 §74 binding extends to per-camera blocks).
  Stripped at load time by Config._load_yaml.
- detection.py detect_sources: PSF docstring updated to reference
  psf_sigma_px helper (handles per-axis sigma_x/sigma_y, single sigma,
  fwhm()) instead of the stale "Only sigma or fwhm() is consulted".
- instrument_config._required_float: rejects non-finite (NaN/+-Inf)
  values with a path-aware ValueError so non-finite YAML values can
  not propagate into orchestrator thresholds.
- instrument_settings_from_obs: added isinstance(Mapping) guards on
  inst_config / iqt_block / noise; data_units narrowed via cast(),
  with isinstance(str) check before the literal-membership test.
- nav_technique_body_limb / body_terminator / ring_edge: switched
  evaluate_sigmoid_combination to use ``self.confidence_spec``
  (class attribute) instead of the module-level
  _BODY_LIMB_CONFIDENCE_SPEC / _BODY_TERMINATOR_CONFIDENCE_SPEC /
  _RING_EDGE_CONFIDENCE_SPEC constants, eliminating the drift risk.
- log_confidence_breakdown: now emits the per-term DEBUG breakdown
  on every call (including the hard_zero path) and additionally an
  INFO summary + per-term INFO when ``confidence <= low_threshold``,
  matching the docstring's promise.
- obs_inst_cassini_iss: replaced the bare KeyError on missing
  config section / detector with an explicit ValueError naming
  both inst_section and detector and listing available detectors.
- test_config_load: added newhorizons_lorri to the per-instrument
  field-presence check; replaced truthiness assertions on
  mag_offset.fallback_combo with concrete equality assertions per
  instrument.
- test_provenance: replaced the tautological
  ``isinstance(meta.static_data_hashes, dict | type(meta.static_data_hashes))``
  assertion with explicit Mapping + MappingProxyType + key/value-type
  checks.

Verification: ruff + format + mypy --strict clean (256 files), pytest
1043 passed, sphinx -W clean, pymarkdown clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Provenance metadata is best-effort — the other resolvers in this module
(_resolve_git_sha, _resolve_spice_kernels) already catch and fall back
on per-source failures, but _resolve_static_data_hashes let
``Path.read_bytes`` and ``hashlib.sha256(...)`` propagate, so a transient
I/O error (file disappearing between glob and read, permission denied,
OS read failure) would abort the whole navigation.

Wrap the read+hash in a try/except OSError; on failure log a WARNING
naming the file and exception and skip it, so successful files still
populate the returned MappingProxyType.

Adds test_static_data_hashes_skips_unreadable_files exercising the
PermissionError path with a monkeypatched Path.read_bytes — asserts
the offending file is dropped, other files still hash, and the
WARNING is on the per-image log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rfrenchseti rfrenchseti merged commit 4846a54 into rf_core_rewrite Apr 29, 2026
2 of 6 checks passed
@rfrenchseti rfrenchseti deleted the core_rewrite_catchup branch April 29, 2026 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant