Skip to content

Conversation

@rfrenchseti
Copy link
Collaborator

@rfrenchseti rfrenchseti commented Dec 23, 2025

This is the initial pass at PDS4 bundle generation.

  • New CLI programs nav_create_bundle and nav_create_bundle_cloud_tasks.
  • Add pds4 section to config.
  • New module pds4 with modules to create data and browse product labels and collections and global indexes.
  • Break Cassini ISS into two sections to correspond to PDS4 bundles - cruise and saturn. Original joint dataset is also available.
  • Add new pds4 helper methods to DataSet.
  • Initial PDS4 support available for Cassini ISS. All other DataSets are not implemented.
  • Add helper routines to deduce nav, backplane, and bundle results roots.
  • General code cleanup.
  • Fixes Implement backplane aggregator and label generator #58
  • Fixes Write summary image label generator #59
  • Partially addresses Design the PDS4 labels for the backplane files #30

Summary by CodeRabbit

  • New Features

    • PDS4 bundle generation added with two CLI entry points for labels (single-image) and summary passes plus a Cloud Tasks worker for parallel processing.
    • New Cassini ISS Cruise and Saturn dataset variants and expanded dataset selection/options.
    • Backplane outputs now include supplemental JSON metadata alongside FITS files.
  • Documentation

    • New user guide for PDS4 bundle generation and expanded developer/extending guides with examples and templates.
    • Updated supported-missions and quick-start CLI examples.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 23, 2025

Walkthrough

Adds PDS4 bundle-generation (labels/summary) and Cloud Tasks drivers, expands DataSet PDS4 APIs (and Cassini ISS Cruise/Saturn subclasses), and refactors backplane generation to exception-driven flow with changed return shapes and metadata outputs; many new PDS4 templates and CLI entry points included.

Changes

Cohort / File(s) Summary
Backplane core & writer
src/backplanes/backplanes.py, src/backplanes/merge.py, src/backplanes/writer.py
Switch to exception-driven errors; generate_backplanes_image_files now returns None; merge_sources_into_master returns (master_by_type, body_id_map); remove label-writing, use write_fits with bodies/rings metadata. Review: return-shape and call sites.
Body & ring backplane impl
src/backplanes/backplanes_bodies.py, src/backplanes/backplanes_rings.py
Add logger param; enforce per-backplane config keys (method,units); produce per-backplane arrays/masks and statistics; simulated-body generator added. Review: units/statistics conversion and simulated seeding.
Backplanes template removed
src/backplanes/templates/backplanes.lblx (deleted)
Legacy PDS4 backplanes label template removed — verify no remaining callers.
Backplanes smoke test
src/experiments/backplanes/smoke_backplanes_sim.py
FileCache root usage simplified (FileCache()); check test paths.
PDS4 package (new)
src/pds4/__init__.py, src/pds4/bundle_data.py, src/pds4/collections.py
New public APIs: generate_bundle_data_files, generate_collection_files, generate_global_index_files; implement label/template-driven bundle data, collections, and global indexes. Review: template rendering, file discovery, and LID/LIDVID mapping calls.
PDS4 templates (new)
src/pds4/templates/cassini_iss_saturn_1.0/*
New bundle/data/browse/collection/document/schema templates and readme; large XML templates added — validate placeholders and template variable coverage.
Bundle CLI & cloud worker
src/main/nav_create_bundle.py, src/main/nav_create_bundle_cloud_tasks.py
New entry points and dispatchers for labels/summary and Cloud Tasks worker (process_task), arg parsing, root resolution, logger wiring. Review: integration with config helpers and error payload shapes.
Backplanes CLI updates
src/main/nav_backplanes.py, src/main/nav_backplane_viewer.py, src/main/nav_backplanes_cloud_tasks.py
Migrate to config helper root resolution, centralized config loader, and try/except around new generate call; logging enhancements.
Config helpers & pds4 config
src/nav/config/config_helper.py, src/nav/config/config.py, src/nav/config/__init__.py, src/nav/config_files/config_95_pds4.yaml
Add get_*_results_root, load_default_and_user_config, Config.pds4 property; export helpers; add pds4 config defaults. Review: precedence and ValueError paths.
Dataset API & classes
src/nav/dataset/dataset.py, src/nav/dataset/* (many: dataset_pds3_cassini_iss.py, _galileo_ssi.py, _newhorizons_lorri.py, _voyager_iss.py, dataset_sim.py, dataset_pds3.py, __init__.py)
Add ImageFile.extra_params; introduce PDS4 abstract methods on DataSet and add/implement PDS4 support for Cassini ISS plus two new subclasses (Cruise, Saturn); add stubs for other datasets; update dataset name mappings. Review: API surface additions and NotImplementedError stubs.
Entry points & packaging
pyproject.toml
Add nav_create_bundle and nav_create_bundle_cloud_tasks CLI entry points; adjust nav_backplanes mapping.
Docs & README
README.md, docs/*
Add user/developer docs for PDS4 bundle workflow, class-hierarchy and extending guide, and CLI examples.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • rms-nav#48: Overlaps backplane generation refactor (backplanes, bodies/rings, merge, writer) — likely touches identical call sites and return-shape changes.
  • rms-nav#51: ImageFile API changes (extra_params) and propagation across image-processing paths — directly related to DataSet/ImageFile edits.
  • rms-nav#11: Dataset and Cassini ISS class hierarchy changes — related to the new subclasses and class-mapping updates.

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'First pass at PDS4 bundle generation' directly reflects the main objective described in the PR summary and aligns with the extensive PDS4-related additions throughout the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 90.48% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

codecov bot commented Dec 23, 2025

Codecov Report

❌ Patch coverage is 24.02089% with 291 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.90%. Comparing base (d16ff0e) to head (29300b6).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/nav/dataset/dataset_pds3_cassini_iss.py 15.00% 153 Missing ⚠️
src/nav/config/config_helper.py 10.93% 57 Missing ⚠️
src/nav/dataset/dataset_pds3_galileo_ssi.py 34.37% 21 Missing ⚠️
src/nav/dataset/dataset_pds3_newhorizons_lorri.py 34.37% 21 Missing ⚠️
src/nav/dataset/dataset_pds3_voyager_iss.py 34.37% 21 Missing ⚠️
src/nav/dataset/dataset.py 52.63% 9 Missing ⚠️
src/nav/dataset/dataset_sim.py 54.54% 5 Missing ⚠️
src/nav/config/config.py 66.66% 2 Missing ⚠️
src/nav/navigate_image_files.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #68      +/-   ##
==========================================
- Coverage   36.98%   35.90%   -1.09%     
==========================================
  Files          57       58       +1     
  Lines        4350     4726     +376     
  Branches      564      597      +33     
==========================================
+ Hits         1609     1697      +88     
- Misses       2641     2929     +288     
  Partials      100      100              

☔ 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.

Copy link

@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: 55

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/backplanes/merge.py (1)

22-24: Docstring is inconsistent with the new return signature.

The docstring on line 23 states "A tuple containing the master by type, body id map, and merge info" but the function now returns only two values. Update the docstring to match the new signature.

Suggested fix
     Returns:
-        A tuple containing the master by type, body id map, and merge info.
+        A tuple containing (master_by_type, body_id_map).
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d16ff0e and 87ad57b.

⛔ Files ignored due to path filters (3)
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_context.csv is excluded by !**/*.csv
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_document.csv is excluded by !**/*.csv
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_xml_schema.csv is excluded by !**/*.csv
📒 Files selected for processing (48)
  • README.md
  • docs/developer_guide_class_hierarchy.rst
  • docs/developer_guide_extending.rst
  • docs/index.rst
  • docs/user_guide_navigation.rst
  • docs/user_guide_pds4_bundle.rst
  • pyproject.toml
  • src/backplanes/backplanes.py
  • src/backplanes/backplanes_bodies.py
  • src/backplanes/backplanes_rings.py
  • src/backplanes/merge.py
  • src/backplanes/templates/backplanes.lblx
  • src/backplanes/writer.py
  • src/experiments/backplanes/smoke_backplanes_sim.py
  • src/main/nav_backplane_viewer.py
  • src/main/nav_backplanes.py
  • src/main/nav_backplanes_cloud_tasks.py
  • src/main/nav_create_bundle.py
  • src/main/nav_create_bundle_cloud_tasks.py
  • src/main/nav_offset.py
  • src/main/nav_offset_cloud_tasks.py
  • src/nav/config/config.py
  • src/nav/config_files/config_95_pds4.yaml
  • src/nav/dataset/__init__.py
  • src/nav/dataset/dataset.py
  • src/nav/dataset/dataset_pds3.py
  • src/nav/dataset/dataset_pds3_cassini_iss.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_voyager_iss.py
  • src/nav/dataset/dataset_sim.py
  • src/nav/navigate_image_files.py
  • src/pds4/__init__.py
  • src/pds4/bundle_data.py
  • src/pds4/collections.py
  • src/pds4/templates/cassini_iss_saturn_1.0/browse.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/bundle.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/cassini-iss-saturn-backplanes-user-guide.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_browse.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_context.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_data.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_document.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_xml_schema.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/data.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/data_orig.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/global_index_bodies.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/global_index_rings.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/readme.txt
💤 Files with no reviewable changes (1)
  • src/backplanes/templates/backplanes.lblx
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-11-24T19:48:51.676Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 48
File: main/nav_main_offset.py:167-171
Timestamp: 2025-11-24T19:48:51.676Z
Learning: In the nav_main_offset.py file, it is normal and expected for the nav_default_config.yaml file to be missing. The FileNotFoundError suppression when attempting to load this default config is intentional behavior, not an error condition that needs logging.

Applied to files:

  • pyproject.toml
  • src/main/nav_offset.py
  • src/main/nav_backplanes.py
📚 Learning: 2025-09-22T21:03:10.431Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 1
File: tests/nav/dataset/test_dataset_pds3_newhorizons_lorri.py:27-33
Timestamp: 2025-09-22T21:03:10.431Z
Learning: PDS3 (Planetary Data System version 3) archives are immutable and never updated once finalized. Exact count assertions in tests for PDS3 datasets are appropriate since the underlying data will never change.

Applied to files:

  • src/nav/dataset/dataset_pds3.py
  • src/nav/dataset/dataset_pds3_voyager_iss.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
  • src/nav/dataset/dataset.py
  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_cassini_iss.py
  • docs/developer_guide_class_hierarchy.rst
📚 Learning: 2025-09-22T23:18:15.371Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 1
File: tests/nav/dataset/test_dataset_pds3_cassini_iss.py:29-34
Timestamp: 2025-09-22T23:18:15.371Z
Learning: PDS3 dataset indices are stable and immutable once archived, making exact count assertions appropriate in tests rather than using lower-bound checks.

Applied to files:

  • src/nav/dataset/dataset_pds3.py
📚 Learning: 2025-12-04T23:41:21.874Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 52
File: nav/obs/obs_inst_voyager_iss.py:47-49
Timestamp: 2025-12-04T23:41:21.874Z
Learning: In the rms-nav codebase, `FCPath.get_local_path()` from the filecache library returns `Path | list[Path]`. When used with a single path argument, `cast(Path, fc_path.get_local_path())` is required to narrow the type to `Path` for type checking purposes. This pattern is intentionally used across observation instrument files (obs_inst_voyager_iss.py, obs_inst_newhorizons_lorri.py, obs_inst_cassini_iss.py, obs_inst_galileo_ssi.py).

Applied to files:

  • src/nav/dataset/dataset_pds3_galileo_ssi.py
  • src/backplanes/backplanes.py
📚 Learning: 2025-11-24T20:38:55.660Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 48
File: nav/backplanes/backplanes_bodies.py:90-97
Timestamp: 2025-11-24T20:38:55.660Z
Learning: In nav/backplanes/backplanes_bodies.py, the hash-based RNG seeding for simulated backplanes (using hash((body_name, name))) is acceptable and reproducibility across Python interpreter runs is not required for simulated mode.

Applied to files:

  • src/backplanes/backplanes_bodies.py
📚 Learning: 2025-09-22T21:16:27.113Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 1
File: docs/user_guide.rst:78-92
Timestamp: 2025-09-22T21:16:27.113Z
Learning: PdsTable uses the .lbl file to automatically locate and read the corresponding .tab file in PDS3 datasets. Code should return .lbl file paths only, as PdsTable handles finding and reading the .tab file internally. Both .lbl and .tab files exist in the PDS3 structure but only .lbl paths need to be specified in volume_to_index implementations.

Applied to files:

  • src/nav/dataset/dataset_pds3_cassini_iss.py
🧬 Code graph analysis (13)
src/nav/config/config.py (1)
src/nav/support/attrdict.py (1)
  • AttrDict (5-29)
src/nav/navigate_image_files.py (1)
src/nav/support/nav_base.py (1)
  • logger (38-40)
src/main/nav_create_bundle_cloud_tasks.py (4)
src/nav/dataset/dataset.py (2)
  • ImageFile (15-58)
  • ImageFiles (62-77)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_class (57-69)
src/nav/config/config.py (4)
  • pds4 (227-231)
  • read_config (60-81)
  • update_config (83-102)
  • environment (119-123)
src/pds4/bundle_data.py (1)
  • generate_bundle_data_files (14-131)
src/backplanes/writer.py (3)
src/nav/support/file.py (1)
  • json_as_string (94-102)
src/nav/obs/obs_snapshot.py (1)
  • closest_planet (302-303)
src/nav/config/config.py (1)
  • satellites (132-145)
src/pds4/__init__.py (2)
src/pds4/bundle_data.py (1)
  • generate_bundle_data_files (14-131)
src/pds4/collections.py (2)
  • generate_collection_files (13-126)
  • generate_global_index_files (129-322)
src/main/nav_offset_cloud_tasks.py (2)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_inst_name (72-84)
src/nav/obs/__init__.py (1)
  • inst_name_to_obs_class (26-35)
src/main/nav_offset.py (1)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/main/nav_create_bundle.py (3)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/pds4/bundle_data.py (1)
  • generate_bundle_data_files (14-131)
src/pds4/collections.py (2)
  • generate_collection_files (13-126)
  • generate_global_index_files (129-322)
src/nav/dataset/__init__.py (1)
src/nav/dataset/dataset_pds3_cassini_iss.py (3)
  • DataSetPDS3CassiniISS (14-621)
  • DataSetPDS3CassiniISSCruise (624-638)
  • DataSetPDS3CassiniISSSaturn (641-655)
src/nav/dataset/dataset.py (5)
src/nav/dataset/dataset_pds3_cassini_iss.py (9)
  • pds4_bundle_template_dir (311-333)
  • pds4_bundle_name (335-346)
  • pds4_bundle_path_for_image (349-368)
  • pds4_path_stub (370-384)
  • pds4_image_name_to_browse_lid (386-397)
  • pds4_image_name_to_browse_lidvid (399-410)
  • pds4_image_name_to_data_lid (412-423)
  • pds4_image_name_to_data_lidvid (425-436)
  • pds4_template_variables (438-597)
src/nav/dataset/dataset_pds3_newhorizons_lorri.py (5)
  • pds4_bundle_template_dir (182-197)
  • pds4_bundle_name (199-204)
  • pds4_bundle_path_for_image (207-209)
  • pds4_path_stub (211-213)
  • pds4_template_variables (215-222)
src/nav/dataset/dataset_sim.py (5)
  • pds4_bundle_template_dir (65-67)
  • pds4_bundle_name (69-71)
  • pds4_bundle_path_for_image (74-76)
  • pds4_path_stub (78-80)
  • pds4_template_variables (82-89)
src/nav/dataset/dataset_pds3_galileo_ssi.py (5)
  • pds4_bundle_template_dir (198-213)
  • pds4_bundle_name (215-220)
  • pds4_bundle_path_for_image (223-225)
  • pds4_path_stub (227-229)
  • pds4_template_variables (231-238)
src/nav/dataset/dataset_pds3_voyager_iss.py (5)
  • pds4_bundle_template_dir (189-204)
  • pds4_bundle_name (206-211)
  • pds4_bundle_path_for_image (214-216)
  • pds4_path_stub (218-220)
  • pds4_template_variables (222-229)
src/main/nav_backplanes_cloud_tasks.py (4)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_inst_name (72-84)
src/nav/obs/__init__.py (1)
  • inst_name_to_obs_class (26-35)
src/backplanes/backplanes.py (1)
  • generate_backplanes_image_files (18-102)
src/nav/dataset/dataset.py (1)
  • ImageFiles (62-77)
src/main/nav_backplanes.py (2)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/backplanes/backplanes.py (1)
  • generate_backplanes_image_files (18-102)
src/nav/dataset/dataset_pds3_cassini_iss.py (1)
src/nav/dataset/dataset_pds3_galileo_ssi.py (5)
  • pds4_bundle_template_dir (198-213)
  • pds4_bundle_name (215-220)
  • pds4_bundle_path_for_image (223-225)
  • pds4_path_stub (227-229)
  • pds4_template_variables (231-238)
🪛 Ruff (0.14.10)
src/pds4/bundle_data.py

34-35: Avoid specifying long messages outside the exception class

(TRY003)


45-45: Use explicit conversion flag

Replace with conversion flag

(RUF010)


107-107: Avoid specifying long messages outside the exception class

(TRY003)

src/nav/config/config.py

227-227: Dynamically typed expressions (typing.Any) are disallowed in pds4

(ANN401)

src/nav/navigate_image_files.py

64-64: Redundant exception object included in logging.exception call

(TRY401)


75-75: Redundant exception object included in logging.exception call

(TRY401)

src/main/nav_create_bundle_cloud_tasks.py

31-31: Unused function argument: task_id

(ARG001)

src/backplanes/backplanes_rings.py

53-53: Avoid specifying long messages outside the exception class

(TRY003)


70-70: Avoid specifying long messages outside the exception class

(TRY003)


73-73: Avoid specifying long messages outside the exception class

(TRY003)


75-75: Logging statement uses f-string

(G004)

src/pds4/collections.py

36-36: Avoid specifying long messages outside the exception class

(TRY003)

src/nav/dataset/dataset_pds3_voyager_iss.py

224-224: Unused method argument: image_file

(ARG002)


225-225: Unused method argument: nav_metadata

(ARG002)


226-226: Unused method argument: backplane_metadata

(ARG002)

src/nav/dataset/dataset_pds3_galileo_ssi.py

233-233: Unused method argument: image_file

(ARG002)


234-234: Unused method argument: nav_metadata

(ARG002)


235-235: Unused method argument: backplane_metadata

(ARG002)

src/backplanes/writer.py

88-89: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)


91-91: Do not catch blind exception: Exception

(BLE001)

src/backplanes/backplanes_bodies.py

54-54: Do not catch blind exception: Exception

(BLE001)


114-114: Avoid specifying long messages outside the exception class

(TRY003)


144-144: Avoid specifying long messages outside the exception class

(TRY003)


147-147: Avoid specifying long messages outside the exception class

(TRY003)


149-149: Logging statement uses f-string

(G004)

src/main/nav_create_bundle.py

38-38: Boolean-typed positional argument in function definition

(FBT001)


38-38: Boolean default positional argument in function definition

(FBT002)


156-158: Avoid specifying long messages outside the exception class

(TRY003)


188-190: Avoid specifying long messages outside the exception class

(TRY003)


202-204: Avoid specifying long messages outside the exception class

(TRY003)

src/main/nav_backplane_viewer.py

1450-1452: Avoid specifying long messages outside the exception class

(TRY003)


1464-1466: Avoid specifying long messages outside the exception class

(TRY003)

src/main/nav_backplanes.py

182-184: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

src/backplanes/backplanes.py

43-44: Avoid specifying long messages outside the exception class

(TRY003)


51-51: Use explicit conversion flag

Replace with conversion flag

(RUF010)


67-67: Prefer TypeError exception for invalid type

(TRY004)


67-67: Avoid specifying long messages outside the exception class

(TRY003)


72-72: Avoid specifying long messages outside the exception class

(TRY003)


74-74: Logging statement uses f-string

(G004)

src/nav/dataset/dataset_pds3_cassini_iss.py

443-443: Unused method argument: backplane_metadata

(ARG002)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test nav (ubuntu-latest, 3.10)
  • GitHub Check: Test nav (ubuntu-latest, 3.11)
  • GitHub Check: Test nav (ubuntu-latest, 3.13)
  • GitHub Check: Test nav (ubuntu-latest, 3.12)
🔇 Additional comments (52)
src/nav/config_files/config_95_pds4.yaml (1)

1-18: LGTM! Configuration structure is clear and extensible.

The YAML structure is well-organized with commented examples for future datasets. Consider whether the hardcoded year in bundle_name (rsfrench2027) should be parameterized or documented as intentional.

src/main/nav_backplane_viewer.py (2)

1448-1453: Good three-tier configuration fallback pattern.

The CLI → config → environment variable resolution order is clear and the error message helpfully enumerates all sources checked. The switch to FileCache() is consistent with other changes in this PR.


1462-1467: Consistent pattern with nav_results_root handling.

Same three-tier fallback approach applied correctly for backplane results root.

src/backplanes/backplanes_bodies.py (1)

12-62: Helper function looks correct.

The deterministic seeding via hash((body_name, backplane_name)) is acceptable per previous learnings. The fallback chain (mask_map → sim_body_index_map → full rect) provides robust handling for different simulation scenarios.

README.md (2)

36-37: Good feature documentation additions.

New features clearly describe the PDS4 bundle generation and backplane generation capabilities.


101-118: Clear and consistent Quick Start examples.

The new CLI examples follow the established pattern and demonstrate the workflow progression: navigation → backplanes → bundle generation. The coiss_saturn dataset name aligns with the new Cassini ISS Saturn dataset variant introduced in this PR.

docs/index.rst (1)

16-16: LGTM! The user_guide_pds4_bundle entry is correctly positioned in the toctree hierarchy, and the referenced documentation file exists.

src/nav/dataset/dataset_pds3.py (1)

57-61: Clarify intent of removing FileCache namespace for holdings cache.

The pds3_holdings_filecache no longer uses a named cache key (changed from FileCache('nav_pds3_holdings') to FileCache()), while index_filecache retains its namespace as FileCache('nav_pds3_index'). If this standardizes cache handling across the PR, confirm both should follow the same pattern. If holdings uses temporary caching while index uses persistent caching, the design difference should be documented.

src/nav/config/config.py (1)

29-29: LGTM: PDS4 configuration section follows established pattern.

The new PDS4 configuration section is implemented consistently with existing configuration sections (environment, general, backplanes, etc.). The three-part pattern (initialization in __init__, population in _update_attrdicts, and property accessor) is correctly applied.

Note: The static analysis warning about Any type hint is consistent with all other config property accessors in this file and can be safely ignored.

Also applies to: 46-46, 226-231

src/experiments/backplanes/smoke_backplanes_sim.py (1)

19-19: LGTM: FileCache initialization updated for consistency.

The change from FileCache('backplane_results') to FileCache() aligns with the broader refactoring pattern across the codebase to standardize root path resolution. Paths are still correctly derived via fc.new_path().

src/main/nav_offset.py (2)

57-57: LGTM: CLI usage messages updated for consistency.

The usage messages now correctly reference the installed entry point name nav_main_offset instead of the internal script path, improving user experience.

Also applies to: 65-65, 73-73


191-191: LGTM: FileCache initialization standardized.

The change from FileCache('nav_results').new_path(...) to FileCache().new_path(...) aligns with the broader refactoring to remove dataset-specific cache namespaces, consistent with changes in nav_backplanes.py and other modules.

src/pds4/templates/cassini_iss_saturn_1.0/collection_xml_schema.lblx (1)

57-74: Verify contributor sequence_number for Mitchell K. Gordon.

Line 63 sets sequence_number to 2 for Mitchell K. Gordon, which is correct as he is the second contributor in the List_Contributor. However, please verify this is intentional, as contributors appear in a specific order and sequence numbers should match.

docs/developer_guide_extending.rst (1)

32-56: LGTM: Clear documentation for PDS4 bundle generation extension points.

The new section clearly documents the five required abstract methods for PDS4 bundle support, including their purpose and expected behavior. The note about raising NotImplementedError for unsupported datasets is helpful, and the reference to a complete implementation example is valuable.

pyproject.toml (1)

77-77: LGTM: Entry points updated for PDS4 bundle generation.

The changes add two new CLI entry points (nav_create_bundle and nav_create_bundle_cloud_tasks) and standardize the path format for nav_backplanes to be consistent with other entry points. All now use the main.module:main pattern.

Also applies to: 80-81

src/pds4/templates/cassini_iss_saturn_1.0/browse.lblx (1)

1-70: LGTM: Well-structured PDS4 browse template.

The Product_Browse template is cleanly structured with proper identification, references, and file area sections. Template placeholders follow the established pattern for dynamic value substitution during bundle generation.

docs/user_guide_navigation.rst (2)

33-35: LGTM! Clear documentation of Cassini ISS variants.

The documentation clearly distinguishes between the three Cassini ISS variants and their volume coverage, which will help users select the appropriate dataset for their needs.


223-223: LGTM! Dataset list updated consistently.

The updated dataset selection documentation properly includes all new Cassini ISS variants (coiss_cruise, coiss_cruise_pds3, coiss_saturn, coiss_saturn_pds3) alongside the existing datasets.

src/pds4/templates/cassini_iss_saturn_1.0/collection_data.lblx (1)

191-223: LGTM! File_Area_Inventory structure is correct.

The inventory structure properly defines the CSV file metadata with appropriate placeholders for dynamic values (creation time, size, checksum, record count). The field definitions for Member Status and LIDVID_LID follow PDS4 standards.

src/pds4/__init__.py (1)

1-10: LGTM! Clean public API exposure.

The module initialization properly exposes the three main PDS4 bundle generation functions through __all__, establishing a clear public API surface. The imports are correctly structured using relative imports.

src/pds4/templates/cassini_iss_saturn_1.0/collection_browse.lblx (1)

129-161: LGTM! Consistent File_Area_Inventory structure.

The browse inventory structure is consistent with the data collection template and properly defines the CSV file metadata with appropriate placeholders.

src/pds4/templates/cassini_iss_saturn_1.0/data_orig.lblx (3)

36-36: Verify publication_year for backplanes product.

The publication_year is set to 2007, which may be appropriate for the original Cassini ISS data. However, since this is a template for backplanes derived products (as indicated by the keywords and the bundle name), the publication year should likely be the year of the backplanes product release (2027, as used in the collection templates). Please verify which year is appropriate.


176-185: TODO: Determine SPICE kernel handling strategy.

The comment indicates uncertainty about how to handle SPICE kernels in the dataset. This is a significant metadata requirement that should be resolved before the template is finalized.

Would you like me to open an issue to track this TODO and gather requirements for SPICE kernel documentation in PDS4 products?


226-226: TODO: Verify reference_type for source product.

The reference_type data_to_calibrated_source_product should be verified against PDS4 standards to ensure it's the correct relationship type for navigated backplanes derived from calibrated images.

src/main/nav_backplanes_cloud_tasks.py (3)

55-74: LGTM! Standardized error handling and FileCache usage.

The changes improve consistency by:

  1. Returning structured error payloads with status and status_error fields instead of plain strings
  2. Simplifying FileCache usage to a generic FileCache() initialization

These changes align with error handling patterns across the cloud-tasks infrastructure.


76-117: LGTM! Comprehensive validation with structured error returns.

The validation logic properly checks all required fields and returns consistent error payloads. The addition of status_exception for the unknown dataset error (line 88) provides valuable debugging context.


126-134: Review exception handling expectations for generate_backplanes_image_files.

The function returns (False, None) unconditionally without exception handling around generate_backplanes_image_files. If that call raises an exception, it will propagate uncaught. Clarify whether:

  1. The cloud tasks worker framework is expected to handle uncaught exceptions and respect the False return value for no-retry behavior, or
  2. Exceptions should be caught and converted to structured error responses for consistency with other handlers
src/main/nav_offset_cloud_tasks.py (2)

77-106: Structured error payloads improve error handling consistency.

The standardized error dictionaries with status and status_error keys provide a consistent API for consumers of task results. This aligns with the broader pattern introduced across related cloud-task modules.


139-145: No action required. The metadata returned by navigate_image_files follows the same structured format as other error payloads in the codebase, with consistent 'status' and 'status_error' keys, ensuring compatible downstream processing.

Likely an incorrect or invalid review comment.

docs/user_guide_pds4_bundle.rst (1)

1-63: Comprehensive documentation for PDS4 bundle generation.

The documentation provides clear explanations of the two-pass bundle generation process, bundle structure, and directory organization. The workflow is well-documented and aligns with the implementation in the CLI and cloud-task modules.

src/pds4/templates/cassini_iss_saturn_1.0/cassini-iss-saturn-backplanes-user-guide.lblx (1)

163-163: TODO: Target context references need to be added.

The comment <!-- TODO Need to add targets here --> indicates missing target context references in the Context_Area. This should be addressed to provide complete PDS4 compliance.

src/nav/dataset/dataset_sim.py (1)

65-89: Placeholder PDS4 methods correctly indicate unsupported functionality.

The five new PDS4-related methods appropriately raise NotImplementedError with a consistent message. This pattern aligns with the base DataSet interface and clearly indicates that PDS4 bundle generation is not supported for simulated datasets.

src/nav/dataset/__init__.py (1)

2-6: Dataset registry correctly extended for new Cassini ISS variants.

The new DataSetPDS3CassiniISSCruise and DataSetPDS3CassiniISSSaturn classes are properly imported, mapped with both standard and _pds3 suffixed names, and exported in __all__. The instrument name mappings correctly reference 'coiss' for all variants.

Also applies to: 16-19, 33-36, 89-90

src/backplanes/merge.py (2)

47-54: Good defensive handling for simulated snapshot NAIF IDs.

The fallback logic that generates deterministic fake NAIF IDs for simulated snapshots with unknown body names is a sensible approach that prevents crashes during testing while still raising errors for real data issues.


14-14: Breaking API change: verify all callers are updated.

The function now returns 2 values instead of 3, and expects bodies_result to be a dict keyed by body name (iterated via .items()) rather than containing a 'per_body' key. Ensure all callers of merge_sources_into_master are updated accordingly.

#!/bin/bash
# Find all usages of merge_sources_into_master to verify they handle the new return signature
rg -n "merge_sources_into_master" --type py -A 3

Also applies to: 34-34

src/pds4/templates/cassini_iss_saturn_1.0/data.lblx (2)

1-25: PDS4 template structure follows current schema versions.

The template correctly references PDS4 schema versions (1O00 series) and includes appropriate namespace declarations for rings, display, geometry, and Cassini mission-specific metadata.


93-99: Multiple TODOs for targets and ISS-specific attributes need tracking.

Lines 93, 97-98 indicate that target context and ISS-specific attributes are not yet implemented. These are important for complete PDS4 metadata. Consider creating issues to track these remaining items.

src/pds4/bundle_data.py (1)

114-122: Address inefficiency in summary PNG copying.

The current implementation works with cloud storage through filecache's local caching mechanism, but the TODO correctly notes this approach could be optimized. Rather than downloading a file, copying locally, then uploading, consider whether filecache or the destination FCPath object provides a direct copy method to avoid the intermediate local operations. If no such method exists, the current pattern remains the standard approach used throughout the codebase.

src/nav/dataset/dataset_pds3_galileo_ssi.py (1)

198-238: PDS4 method stubs are consistent with other datasets.

The placeholder implementations for pds4_bundle_path_for_image, pds4_path_stub, and pds4_template_variables follow the same pattern as other dataset classes. The unused arguments flagged by static analysis are expected for interface conformance.

Consider adding a TODO comment or docstring noting these require implementation for full PDS4 support.

src/main/nav_backplanes.py (1)

154-160: Good addition of startup logging for operational visibility.

The verbose startup logging provides useful diagnostic information for debugging and operational monitoring.

src/nav/dataset/dataset_pds3_voyager_iss.py (1)

189-229: PDS4 method stubs follow the established pattern.

The implementation is consistent with other dataset classes (Galileo SSI, New Horizons LORRI). The unused arguments are expected for interface conformance with the base DataSet class.

src/backplanes/backplanes.py (1)

81-101: Clean refactoring to exception-based error handling.

The shift from status-dict returns to exception propagation simplifies the caller's error handling and aligns with Python best practices. The updated write_fits call signature with bodies_result and rings_result properly passes context for metadata generation.

src/nav/dataset/dataset_pds3_newhorizons_lorri.py (1)

182-204: PDS4 bundle configuration methods are correctly implemented.

pds4_bundle_template_dir and pds4_bundle_name follow the same pattern as other dataset classes, with appropriate config lookups and defaults.

src/backplanes/writer.py (2)

94-120: Well-structured per-body metadata extraction.

The logic for extracting statistics and inventory data per body is clear. The coordinate swap from [u, v] to [v, u] is properly documented with an inline comment.


72-73: The code assumes filenames always contain _backplanes suffix, but this assumption lacks validation.

While the current call site always provides filenames with the _backplanes.fits suffix (constructed in backplanes.py line 49), the replace('_backplanes', '') call at lines 72-73 silently does nothing if the filename doesn't contain this suffix. Consider validating the input or using a more explicit approach to derive the metadata filename, such as using fits_file_path.stem[:-len('_backplanes')] with appropriate error handling.

src/main/nav_create_bundle_cloud_tasks.py (1)

138-143: Pass None handling to ImageFile.index_file_row — avoid type mismatch with default factory.

index_file_row is retrieved from task data via .get('index_file_row', None) (line 122) and can be None. However, the ImageFile field is defined with field(default_factory=dict), making it a dict[str, Any] type. Explicitly passing None differs from omitting the parameter: the former sets the field to None (violating the type annotation), while the latter invokes the default factory to set an empty dict. Either skip the parameter when None or replace it with an empty dict before passing.

src/nav/dataset/dataset.py (1)

152-280: Well-designed optional extension points for PDS4 support.

The approach of using concrete methods with NotImplementedError rather than abstract methods is a sound design choice. This allows existing datasets to continue working without PDS4 support while enabling new datasets to opt-in. The inline comments explaining this decision are helpful.

src/main/nav_create_bundle.py (2)

162-233: LGTM for the main_labels implementation.

The function correctly:

  • Reads configuration with proper fallback to default config
  • Derives roots with consistent priority (CLI > config > env)
  • Validates single-image batches as required by generate_bundle_data_files
  • Supports dry-run mode for testing

236-290: LGTM for the main_summary implementation.

The function properly handles errors for both collection and index file generation with appropriate logging and exit codes.

docs/developer_guide_class_hierarchy.rst (2)

28-59: Documentation accurately reflects the new PDS4 extension points and Cassini ISS subclasses.

The Mermaid class diagram correctly shows:

  • PDS4 methods added to DataSet and DataSetPDS3CassiniISS
  • New DataSetPDS3CassiniISSCruise and DataSetPDS3CassiniISSSaturn subclasses
  • Proper inheritance relationships

Also applies to: 255-256


333-349: Documentation for Dataset section properly updated.

The section now documents:

  • PDS4 abstract methods in the base class
  • New Cassini ISS subclasses with their volume ranges
  • Updated dataset name mappings including coiss_cruise and coiss_saturn
src/nav/dataset/dataset_pds3_cassini_iss.py (1)

624-655: Well-structured subclass implementations for Cruise and Saturn datasets.

The subclasses properly:

  • Override _ALL_VOLUME_NAMES to restrict to their respective volume ranges
  • Implement the three configuration methods (_dataset_name_for_pds4_config, _default_pds4_template_dir, _default_pds4_bundle_name)
  • Inherit all other functionality from the parent class

Copy link

@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.

Review continued from previous batch...

@rfrenchseti
Copy link
Collaborator Author

@CodeRabbit summary

@coderabbitai
Copy link

coderabbitai bot commented Dec 23, 2025

✅ Actions performed

Summary regeneration triggered.

Copy link

@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: 22

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/nav_backplanes_cloud_tasks.py (2)

31-33: Inconsistent task_id parameter naming.

In nav_create_bundle_cloud_tasks.py, the parameter is _task_id (with underscore) to indicate intentional non-use. Here it's task_id without underscore, though it's also unused. Consider aligning for consistency.

🔎 Proposed fix
 def process_task(
-    task_id: str, task_data: dict[str, Any], worker_data: WorkerData
+    _task_id: str, task_data: dict[str, Any], worker_data: WorkerData
 ) -> tuple[bool, Any]:

137-139: Confusing help text for --backplane-results-root.

The help text says "overrides NAV_RESULTS_ROOT or config" but this argument is for backplane results, not navigation results. The environment variable should be NAV_BACKPLANE_RESULTS_ROOT.

🔎 Proposed fix
     environment_group.add_argument(
         '--backplane-results-root', type=str, default=None,
-        help='Root directory for backplane results; overrides NAV_RESULTS_ROOT or config')
+        help='Root directory for backplane results; overrides NAV_BACKPLANE_RESULTS_ROOT or config')
♻️ Duplicate comments (5)
src/backplanes/backplanes_rings.py (3)

51-53: Error message is now correct.

The error message "Configuration has no rings section for backplanes" correctly describes the condition when rings_cfg is None.


71-73: Units validation now correctly implemented.

The units field is now retrieved without a default value, allowing the None check to properly validate that units are required.


91-101: Statistics collection and assignment correctly implemented.

The statistics dictionary is now properly populated inside the loop and assigned to result['statistics'] once after the loop completes (line 101). The unit conversion from radians to degrees is correctly applied before computing min/max.

src/pds4/bundle_data.py (1)

111-126: Verify browse template existence before instantiation.

Unlike the data template path (line 105-106), the browse template path at line 122-123 is not validated before creating PdsTemplate. If browse.lblx doesn't exist, an unclear error will occur.

This was flagged in a previous review and hasn't been addressed yet. Consider adding an existence check similar to:

if not browse_template_path.exists():
    logger.warning('Browse template not found: %s', browse_template_path)
    return
src/nav/dataset/dataset.py (1)

222-233: Docstring inconsistency: says "LID" but method returns "LIDVID".

The docstring says "Returns the browse LID" but the method is pds4_image_name_to_browse_lidvid which should return a LIDVID. The same issue exists for pds4_image_name_to_data_lidvid (lines 248-259).

🔎 Proposed fix
     def pds4_image_name_to_browse_lidvid(self, image_name: str) -> str:
-        """Returns the browse LIDVID for the given image name.
+        """Returns the browse LIDVID for the given image name.

         Parameters:
-            image_name: The image name to convert to a browse LID.
+            image_name: The image name to convert to a browse LIDVID.

         Returns:
-            The browse LID.
+            The browse LIDVID.
         """

And for pds4_image_name_to_data_lidvid:

     def pds4_image_name_to_data_lidvid(self, image_name: str) -> str:
-        """Returns the data LIDVID for the given image name.
+        """Returns the data LIDVID for the given image name.

         Parameters:
-            image_name: The image name to convert to a data LID.
+            image_name: The image name to convert to a data LIDVID.

         Returns:
-            The data LID.
+            The data LIDVID.
         """
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87ad57b and accc18d.

📒 Files selected for processing (27)
  • docs/developer_guide_class_hierarchy.rst
  • docs/developer_guide_extending.rst
  • docs/user_guide_pds4_bundle.rst
  • src/backplanes/backplanes.py
  • src/backplanes/backplanes_bodies.py
  • src/backplanes/backplanes_rings.py
  • src/backplanes/writer.py
  • src/main/nav_backplane_viewer.py
  • src/main/nav_backplanes.py
  • src/main/nav_backplanes_cloud_tasks.py
  • src/main/nav_create_bundle.py
  • src/main/nav_create_bundle_cloud_tasks.py
  • src/main/nav_offset.py
  • src/main/nav_offset_cloud_tasks.py
  • src/nav/config/__init__.py
  • src/nav/config/config_helper.py
  • src/nav/dataset/dataset.py
  • src/nav/dataset/dataset_pds3_cassini_iss.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_voyager_iss.py
  • src/pds4/bundle_data.py
  • src/pds4/collections.py
  • src/pds4/templates/cassini_iss_saturn_1.0/bundle.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_context.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/collection_document.lblx
  • src/pds4/templates/cassini_iss_saturn_1.0/readme.txt
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-24T19:48:51.676Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 48
File: main/nav_main_offset.py:167-171
Timestamp: 2025-11-24T19:48:51.676Z
Learning: In the nav_main_offset.py file, it is normal and expected for the nav_default_config.yaml file to be missing. The FileNotFoundError suppression when attempting to load this default config is intentional behavior, not an error condition that needs logging.

Applied to files:

  • src/main/nav_create_bundle_cloud_tasks.py
  • src/main/nav_offset.py
📚 Learning: 2025-11-24T20:38:55.660Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 48
File: nav/backplanes/backplanes_bodies.py:90-97
Timestamp: 2025-11-24T20:38:55.660Z
Learning: In nav/backplanes/backplanes_bodies.py, the hash-based RNG seeding for simulated backplanes (using hash((body_name, name))) is acceptable and reproducibility across Python interpreter runs is not required for simulated mode.

Applied to files:

  • src/backplanes/backplanes_bodies.py
📚 Learning: 2025-09-22T21:03:10.431Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 1
File: tests/nav/dataset/test_dataset_pds3_newhorizons_lorri.py:27-33
Timestamp: 2025-09-22T21:03:10.431Z
Learning: PDS3 (Planetary Data System version 3) archives are immutable and never updated once finalized. Exact count assertions in tests for PDS3 datasets are appropriate since the underlying data will never change.

Applied to files:

  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_voyager_iss.py
  • src/nav/dataset/dataset_pds3_cassini_iss.py
  • docs/developer_guide_class_hierarchy.rst
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
📚 Learning: 2025-12-04T23:41:21.874Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 52
File: nav/obs/obs_inst_voyager_iss.py:47-49
Timestamp: 2025-12-04T23:41:21.874Z
Learning: In the rms-nav codebase, `FCPath.get_local_path()` from the filecache library returns `Path | list[Path]`. When used with a single path argument, `cast(Path, fc_path.get_local_path())` is required to narrow the type to `Path` for type checking purposes. This pattern is intentionally used across observation instrument files (obs_inst_voyager_iss.py, obs_inst_newhorizons_lorri.py, obs_inst_cassini_iss.py, obs_inst_galileo_ssi.py).

Applied to files:

  • src/backplanes/backplanes.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
🧬 Code graph analysis (14)
src/main/nav_backplanes.py (2)
src/nav/config/config_helper.py (2)
  • get_backplane_results_root (7-38)
  • get_nav_results_root (41-72)
src/backplanes/backplanes.py (1)
  • generate_backplanes_image_files (18-99)
src/nav/config/__init__.py (1)
src/nav/config/config_helper.py (3)
  • get_backplane_results_root (7-38)
  • get_nav_results_root (41-72)
  • get_pds4_bundle_results_root (75-106)
src/nav/config/config_helper.py (1)
src/nav/config/config.py (2)
  • Config (9-231)
  • environment (119-123)
src/main/nav_create_bundle_cloud_tasks.py (4)
src/nav/dataset/dataset.py (2)
  • ImageFile (15-60)
  • ImageFiles (64-79)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_class (57-69)
src/nav/config/config_helper.py (3)
  • get_backplane_results_root (7-38)
  • get_nav_results_root (41-72)
  • get_pds4_bundle_results_root (75-106)
src/pds4/bundle_data.py (1)
  • generate_bundle_data_files (14-128)
src/backplanes/writer.py (3)
src/nav/support/file.py (1)
  • json_as_string (94-102)
src/nav/obs/obs_snapshot.py (1)
  • closest_planet (302-303)
src/nav/config/config.py (1)
  • satellites (132-145)
src/backplanes/backplanes_bodies.py (2)
src/nav/config/config.py (1)
  • backplanes (220-224)
src/nav/support/nav_base.py (1)
  • logger (38-40)
src/pds4/collections.py (2)
src/nav/dataset/dataset.py (5)
  • pds4_bundle_name (170-180)
  • pds4_bundle_template_dir (155-168)
  • pds4_image_name_to_data_lidvid (248-259)
  • pds4_image_name_to_browse_lidvid (222-233)
  • pds4_path_stub (196-207)
src/nav/dataset/dataset_pds3_cassini_iss.py (5)
  • pds4_bundle_name (335-346)
  • pds4_bundle_template_dir (311-333)
  • pds4_image_name_to_data_lidvid (425-436)
  • pds4_image_name_to_browse_lidvid (399-410)
  • pds4_path_stub (370-384)
src/main/nav_backplane_viewer.py (1)
src/nav/config/config_helper.py (2)
  • get_backplane_results_root (7-38)
  • get_nav_results_root (41-72)
src/main/nav_offset.py (2)
src/nav/config/config_helper.py (1)
  • get_nav_results_root (41-72)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/backplanes/backplanes_rings.py (3)
src/nav/config/config.py (1)
  • backplanes (220-224)
src/nav/obs/obs_snapshot.py (2)
  • closest_planet (302-303)
  • bp (332-338)
src/nav/support/nav_base.py (1)
  • logger (38-40)
src/main/nav_offset_cloud_tasks.py (3)
src/nav/config/config_helper.py (1)
  • get_nav_results_root (41-72)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_inst_name (72-84)
src/nav/obs/__init__.py (1)
  • inst_name_to_obs_class (26-35)
src/nav/dataset/dataset.py (5)
src/nav/dataset/dataset_pds3_cassini_iss.py (9)
  • pds4_bundle_template_dir (311-333)
  • pds4_bundle_name (335-346)
  • pds4_bundle_path_for_image (349-368)
  • pds4_path_stub (370-384)
  • pds4_image_name_to_browse_lid (386-397)
  • pds4_image_name_to_browse_lidvid (399-410)
  • pds4_image_name_to_data_lid (412-423)
  • pds4_image_name_to_data_lidvid (425-436)
  • pds4_template_variables (438-598)
src/nav/dataset/dataset_pds3_galileo_ssi.py (9)
  • pds4_bundle_template_dir (198-213)
  • pds4_bundle_name (215-220)
  • pds4_bundle_path_for_image (223-225)
  • pds4_path_stub (227-229)
  • pds4_image_name_to_browse_lid (231-240)
  • pds4_image_name_to_browse_lidvid (242-251)
  • pds4_image_name_to_data_lid (253-262)
  • pds4_image_name_to_data_lidvid (264-273)
  • pds4_template_variables (275-282)
src/nav/dataset/dataset_pds3_newhorizons_lorri.py (9)
  • pds4_bundle_template_dir (182-197)
  • pds4_bundle_name (199-204)
  • pds4_bundle_path_for_image (207-209)
  • pds4_path_stub (211-213)
  • pds4_image_name_to_browse_lid (215-224)
  • pds4_image_name_to_browse_lidvid (226-235)
  • pds4_image_name_to_data_lid (237-246)
  • pds4_image_name_to_data_lidvid (248-257)
  • pds4_template_variables (259-266)
src/nav/dataset/dataset_pds3_voyager_iss.py (9)
  • pds4_bundle_template_dir (189-204)
  • pds4_bundle_name (206-211)
  • pds4_bundle_path_for_image (214-216)
  • pds4_path_stub (218-220)
  • pds4_image_name_to_browse_lid (222-231)
  • pds4_image_name_to_browse_lidvid (233-242)
  • pds4_image_name_to_data_lid (244-253)
  • pds4_image_name_to_data_lidvid (255-264)
  • pds4_template_variables (266-273)
src/nav/dataset/dataset_sim.py (5)
  • pds4_bundle_template_dir (65-67)
  • pds4_bundle_name (69-71)
  • pds4_bundle_path_for_image (74-76)
  • pds4_path_stub (78-80)
  • pds4_template_variables (82-89)
src/nav/dataset/dataset_pds3_cassini_iss.py (2)
src/nav/dataset/dataset_pds3.py (2)
  • DataSetPDS3 (18-821)
  • add_selection_arguments (196-279)
src/nav/dataset/dataset.py (11)
  • add_selection_arguments (108-116)
  • pds4_bundle_template_dir (155-168)
  • pds4_bundle_name (170-180)
  • pds4_bundle_path_for_image (183-194)
  • pds4_path_stub (196-207)
  • ImageFile (15-60)
  • pds4_image_name_to_browse_lid (209-220)
  • pds4_image_name_to_browse_lidvid (222-233)
  • pds4_image_name_to_data_lid (235-246)
  • pds4_image_name_to_data_lidvid (248-259)
  • pds4_template_variables (261-282)
src/nav/dataset/dataset_pds3_galileo_ssi.py (3)
src/nav/dataset/dataset.py (10)
  • ImageFile (15-60)
  • pds4_bundle_template_dir (155-168)
  • pds4_bundle_name (170-180)
  • pds4_bundle_path_for_image (183-194)
  • pds4_path_stub (196-207)
  • pds4_image_name_to_browse_lid (209-220)
  • pds4_image_name_to_browse_lidvid (222-233)
  • pds4_image_name_to_data_lid (235-246)
  • pds4_image_name_to_data_lidvid (248-259)
  • pds4_template_variables (261-282)
src/nav/dataset/dataset_pds3_voyager_iss.py (9)
  • pds4_bundle_template_dir (189-204)
  • pds4_bundle_name (206-211)
  • pds4_bundle_path_for_image (214-216)
  • pds4_path_stub (218-220)
  • pds4_image_name_to_browse_lid (222-231)
  • pds4_image_name_to_browse_lidvid (233-242)
  • pds4_image_name_to_data_lid (244-253)
  • pds4_image_name_to_data_lidvid (255-264)
  • pds4_template_variables (266-273)
src/nav/config/config.py (1)
  • pds4 (227-231)
🪛 Ruff (0.14.10)
src/main/nav_backplanes.py

161-163: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

src/nav/config/__init__.py

6-6: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


8-13: __all__ is not sorted

Apply an isort-style sorting to __all__

(RUF022)

src/nav/config/config_helper.py

34-37: Avoid specifying long messages outside the exception class

(TRY003)


68-71: Avoid specifying long messages outside the exception class

(TRY003)


102-105: Avoid specifying long messages outside the exception class

(TRY003)

src/pds4/bundle_data.py

34-35: Avoid specifying long messages outside the exception class

(TRY003)


45-45: Use explicit conversion flag

Replace with conversion flag

(RUF010)

src/main/nav_create_bundle.py

40-40: Boolean-typed positional argument in function definition

(FBT001)


40-40: Boolean default positional argument in function definition

(FBT002)

src/backplanes/backplanes_bodies.py

54-54: Do not catch blind exception: Exception

(BLE001)


114-114: Avoid specifying long messages outside the exception class

(TRY003)


144-144: Avoid specifying long messages outside the exception class

(TRY003)


147-147: Avoid specifying long messages outside the exception class

(TRY003)


149-149: Logging statement uses f-string

(G004)

src/pds4/collections.py

36-36: Avoid specifying long messages outside the exception class

(TRY003)

src/backplanes/backplanes_rings.py

53-53: Avoid specifying long messages outside the exception class

(TRY003)


70-70: Avoid specifying long messages outside the exception class

(TRY003)


73-73: Avoid specifying long messages outside the exception class

(TRY003)


75-75: Logging statement uses f-string

(G004)

src/nav/dataset/dataset_pds3_cassini_iss.py

443-443: Unused method argument: backplane_metadata

(ARG002)

src/backplanes/backplanes.py

40-41: Avoid specifying long messages outside the exception class

(TRY003)


48-48: Use explicit conversion flag

Replace with conversion flag

(RUF010)


64-64: Avoid specifying long messages outside the exception class

(TRY003)


69-69: Avoid specifying long messages outside the exception class

(TRY003)


71-71: Logging statement uses f-string

(G004)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test nav (ubuntu-latest, 3.10)
  • GitHub Check: Test nav (ubuntu-latest, 3.11)
  • GitHub Check: Test nav (ubuntu-latest, 3.12)
  • GitHub Check: Test nav (ubuntu-latest, 3.13)
🔇 Additional comments (50)
src/pds4/templates/cassini_iss_saturn_1.0/bundle.lblx (1)

1-229: PDS4 bundle template structure looks good.

The template follows PDS4 standards with proper Identification_Area, Context_Area, Reference_List, Bundle, and Bundle_Member_Entry sections. Template variables ($BUNDLE_LID$, $CURRENT_ZULU(date_only=True)$, $EARLIEST_START_DATE_TIME$, $LATEST_STOP_DATE_TIME$) are appropriately placed for dynamic content generation.

The contributor sequence numbers (Lines 46, 64, 82, 100) are now correctly ordered 1-4 within the List_Contributor section.

docs/developer_guide_extending.rst (1)

36-75: Documentation for PDS4 bundle methods is clear and comprehensive.

The new section provides good guidance for implementing PDS4 bundle generation. The method descriptions include return types and purpose.

Minor observation: The documentation lists 9 methods but the bullet list shows 8 (combining LID and LIDVID variants). This is fine as written.

src/pds4/templates/cassini_iss_saturn_1.0/readme.txt (1)

1-44: Readme content now correctly describes backplane products.

The content has been updated to properly reference Cassini ISS backplane products instead of F ring mosaics.

docs/user_guide_pds4_bundle.rst (1)

1-408: Comprehensive and well-structured PDS4 bundle generation documentation.

The user guide provides thorough coverage of the bundle generation workflow, including:

  • Clear explanation of the two-pass workflow (Labels and Summary)
  • Complete CLI argument documentation
  • Input/output file specifications
  • Configuration options with priority order
  • Troubleshooting guidance
src/nav/config/__init__.py (1)

3-6: Re-exports correctly added for centralized root resolution.

The new helper functions are properly imported and will be available to consumers of the nav.config module.

Note: The static analysis hint about unused noqa directive (RUF100) appears to be a false positive - the # noqa: F401 is needed because these are re-exports that aren't directly used in this module.

src/main/nav_backplane_viewer.py (2)

41-43: Import of centralized root getters is correct.

The imports align with the new centralized root resolution pattern.


1442-1446: Centralized root resolution correctly implemented.

The code now uses the centralized helper functions get_nav_results_root() and get_backplane_results_root() instead of inline resolution logic. This improves consistency across the codebase.

The use of FileCache(None).new_path() is consistent with the pattern used in other modules after this refactor.

src/main/nav_offset.py (3)

30-31: Import of centralized root getter is correct.

The import aligns with the new centralized root resolution pattern used across the codebase.


179-180: Centralized root resolution correctly implemented.

The code now uses get_nav_results_root() for consistent root path resolution across the navigation tools. The FileCache(None).new_path() pattern is consistent with the refactored approach in other modules.


57-57: Usage messages simplified.

The usage messages now use a cleaner format without the script extension. This is a minor improvement in user-facing output.

src/main/nav_offset_cloud_tasks.py (1)

69-76: Clean integration with centralized root resolution.

The use of get_nav_results_root with try/except for ValueError and structured error payloads is consistent with the pattern used across other cloud-task handlers in this PR. The refactor cleanly replaces ad-hoc config/env fallbacks.

src/pds4/templates/cassini_iss_saturn_1.0/collection_context.lblx (1)

1-154: Template structure looks correct.

The PDS4 Product_Collection template follows the expected structure with proper schema references, identification, citation, and inventory sections. The file metadata placeholders now consistently use the COLLECTION_CONTEXT_CSV_PATH variable. The hardcoded bundle identifier (rsfrench2027) is noted to be addressed in #71.

src/main/nav_backplanes.py (3)

124-128: Clean refactor to centralized root resolution.

The use of get_nav_results_root and get_backplane_results_root with FileCache(None).new_path() is consistent with the pattern used across the codebase. This eliminates ad-hoc config/environment fallback logic.


133-139: Good addition of startup diagnostics.

The verbose logging of configuration state (dataset, roots, flags, arguments) at startup aids debugging and operational visibility.


152-164: Exception-based flow control is appropriate here.

The try/except pattern for FileNotFoundError provides a clean way to skip images with missing metadata while continuing the batch. The error message includes both the image path and the exception details.

src/pds4/templates/cassini_iss_saturn_1.0/collection_document.lblx (1)

1-156: Template structure is consistent with other collection templates.

The PDS4 Product_Collection template for documents follows the same pattern as other collection templates. File metadata placeholders correctly use COLLECTION_DOCUMENT_CSV_PATH. The hardcoded bundle identifier is noted to be addressed in #71.

src/pds4/bundle_data.py (1)

113-118: The local file copy approach won't work for cloud storage.

The TODO on line 115 correctly identifies that shutil.copy2 with local paths won't work when files are in cloud storage. The current implementation:

  1. Gets local paths (which may download files)
  2. Creates local directory
  3. Copies locally
  4. Uploads result

This may work for local testing but needs refactoring for cloud-native operation.

Please confirm this is intentional for the initial implementation and tracked for follow-up.

src/main/nav_create_bundle_cloud_tasks.py (1)

48-74: Clean integration with centralized root resolution helpers.

The try/except pattern for ValueError from root resolution helpers with structured error payloads is consistent across all cloud-task handlers. This provides clear, actionable error messages.

src/backplanes/backplanes_bodies.py (4)

12-62: LGTM: Simulated backplane helper is well-structured.

The helper correctly handles multiple fallback strategies for mask generation: body mask map → body index map → full rect fallback. The hash-based RNG seeding approach is acceptable per prior learnings.


113-114: Error message grammar is now correct.

The message "Configuration has no bodies section for backplanes" accurately describes the error condition. This addresses the previous review comment.


140-180: Result assignment now correctly placed outside inner loop.

The result[body_name] assignment (lines 182-187) is now outside the for bp_cfg in bodies_cfg: loop, ensuring all backplane types are accumulated before assignment. This correctly addresses the critical issue from the previous review.


172-180: Verify unit conversion for statistics is intentional.

When units.lower() == 'rad', the code converts valid_values to degrees before computing min/max. This means the statistics are stored in degrees even though the backplane arrays remain in radians. Ensure this asymmetry is intentional and documented, as consumers of the statistics must be aware the units differ from the arrays.

src/main/nav_create_bundle.py (1)

242-257: LGTM: Main entry point dispatch is clean.

The subcommand dispatch logic correctly validates input and routes to the appropriate handler.

src/backplanes/backplanes.py (3)

14-35: LGTM: Function signature and docstring are now consistent.

The return type is None and the docstring no longer claims to return a dictionary. This addresses the previous review comment.


63-65: Good: Now raises TypeError for type validation.

Using TypeError instead of ValueError is semantically correct for type mismatches.


77-98: LGTM: Backplane creation and writing flow is well-structured.

The function properly chains body backplanes → ring backplanes → merge → write_fits, passing the logger and result structures consistently.

src/pds4/collections.py (5)

43-51: Good: Image name extraction is now handled by a dedicated helper.

The get_image_name_from_label helper properly splits on _backplanes to extract the image name, fixing the previous bug where stem.replace('_backplanes.lblx', '') would never match.


61-64: Stem replacement is now correct.

The code now uses label_file.stem.replace('_backplanes', '') which correctly removes the suffix from the stem. This addresses the critical bug from the previous review.


99-102: Browse collection also correctly extracts image name.

Same fix applied consistently for the browse collection CSV generation.


289-303: Bodies template now has proper error handling.

The try/except block around template.write logs the error with context and re-raises, providing consistent error handling.


305-320: Rings template error handling is now consistent with bodies.

The rings template write (lines 313-318) now has the same try/except pattern as the bodies template, addressing the previous review comment about inconsistent error handling.

src/backplanes/writer.py (1)

14-36: LGTM: Function signature clearly documents new parameters.

The docstring accurately describes the new bodies_result and rings_result parameters.

src/nav/dataset/dataset.py (2)

23-32: Good: extra_params field extends ImageFile for flexible parameter passing.

The new extra_params field with default_factory=dict allows passing additional parameters to observation creation without breaking existing code.


154-282: LGTM: PDS4 interface stubs are appropriately designed.

Using NotImplementedError instead of @abstractmethod is a reasonable choice since not all datasets need to support PDS4 bundle generation. The inline comments explaining this design decision are helpful.

src/nav/dataset/dataset_pds3_galileo_ssi.py (2)

198-213: LGTM: Template directory resolution follows established pattern.

The implementation correctly checks config first, provides a sensible default, handles absolute paths, and resolves relative paths against the templates directory. This matches the pattern used in other dataset implementations.


215-220: LGTM: Bundle name resolution is consistent.

Config-driven with fallback default, matching the Voyager and New Horizons implementations.

src/nav/dataset/dataset_pds3_newhorizons_lorri.py (2)

182-197: LGTM: Template directory resolution matches established pattern.

Consistent with Galileo SSI implementation.


199-204: LGTM: Bundle name resolution is consistent.

Follows the same pattern as other dataset implementations.

src/nav/dataset/dataset_pds3_voyager_iss.py (3)

189-204: LGTM on template directory resolution logic.

The implementation correctly checks config first, falls back to default, and handles both absolute and relative paths. This matches the pattern in DataSetPDS3CassiniISS.


206-211: LGTM on bundle name resolution.

Config-first lookup with sensible default follows the established pattern.


213-273: Stub methods are appropriate for first pass.

The NotImplementedError stubs for the remaining PDS4 methods are acceptable for this initial implementation, matching the base class interface from dataset.py.

docs/developer_guide_class_hierarchy.rst (4)

28-34: LGTM on class diagram updates.

The PDS4 method additions to the DataSet abstract class are correctly documented.


55-63: LGTM on new Cassini ISS subclass documentation.

The DataSetPDS3CassiniISSCruise and DataSetPDS3CassiniISSSaturn classes are correctly documented with their public interface.


259-260: LGTM on inheritance diagram.

The inheritance relationships correctly show the new Cassini ISS subclasses extending DataSetPDS3CassiniISS.


337-354: LGTM on narrative documentation.

The text accurately describes the new PDS4 methods, dataset subclasses with their volume ranges, and updated dataset name mappings.

src/nav/dataset/dataset_pds3_cassini_iss.py (5)

311-333: LGTM on template directory resolution.

The implementation correctly checks config, falls back to subclass default, and handles absolute vs relative paths.


335-346: LGTM on bundle name resolution.

Config-first lookup with subclass-provided default follows the established pattern.


456-598: Comprehensive template variable mapping.

The pds4_template_variables method provides thorough mapping from PDS3 index columns to PDS4 template variables. The hardcoded placeholder values for compression parameters (lines 550-553) and the SOURCE_IMAGE_LIDVID placeholder (lines 493-495) are acceptable for a first pass but should be tracked for resolution before production use.


600-622: Reasonable use of NotImplementedError for abstract-like methods.

Raising NotImplementedError in the base DataSetPDS3CassiniISS class for _dataset_name_for_pds4_config, _default_pds4_template_dir, and _default_pds4_bundle_name ensures subclasses must provide their own implementations. This is appropriate since the base class includes all volumes and PDS4 bundle generation requires mission-phase-specific configuration.


625-656: LGTM on new Cassini ISS subclasses.

DataSetPDS3CassiniISSCruise and DataSetPDS3CassiniISSSaturn correctly:

  • Override _ALL_VOLUME_NAMES with appropriate volume ranges
  • Implement required PDS4 configuration methods with mission-phase-specific values
  • Follow naming conventions consistent with the dataset mapping in __init__.py

Copy link

@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: 3

♻️ Duplicate comments (4)
src/main/nav_create_bundle_cloud_tasks.py (1)

118-127: Add exception handling for missing metadata files.

generate_bundle_data_files can raise FileNotFoundError when navigation or backplane metadata files are missing. Without a try/except, the task will crash rather than returning a structured error.

🔎 Proposed fix
+    try:
         generate_bundle_data_files(
             dataset=dataset,
             image_files=ImageFiles(image_files=image_files),
             nav_results_root=nav_results_root,
             backplane_results_root=backplane_results_root,
             bundle_results_root=bundle_results_root,
             logger=DEFAULT_LOGGER
         )
+    except FileNotFoundError as e:
+        return False, {
+            'status': 'error',
+            'status_error': 'missing_metadata',
+            'status_exception': str(e)
+        }

     return False, {'status': 'success'}  # No retry under any circumstances
src/main/nav_create_bundle.py (2)

164-181: Add exception handling to continue processing on individual image failures.

The call to generate_bundle_data_files is unprotected. If processing one image fails (e.g., missing metadata), the entire run stops. Consider wrapping in a try/except to log the error and continue with remaining images.

🔎 Proposed fix
         if arguments.dry_run:
             MAIN_LOGGER.info('Would process: %s',
                              imagefiles.image_files[0].label_file_url.as_posix())
             continue

+        try:
             generate_bundle_data_files(
                 dataset=DATASET,
                 image_files=imagefiles,
                 nav_results_root=nav_results_root,
                 backplane_results_root=backplane_results_root,
                 bundle_results_root=bundle_results_root,
                 logger=MAIN_LOGGER
             )
+        except Exception:
+            MAIN_LOGGER.exception('Failed to process: %s',
+                                  imagefiles.image_files[0].label_file_url.as_posix())
+            continue

189-198: Config loading duplicates pattern from main_labels (optional refactor).

Lines 189-198 manually load configuration using the same pattern as the helper load_default_and_user_config used in main_labels (line 145). Consider using the helper here as well for consistency:

-    # Read configuration files
-    DEFAULT_CONFIG.read_config()
-    if arguments.config_file:
-        for config_file in arguments.config_file:
-            DEFAULT_CONFIG.update_config(config_file)
-    else:
-        try:
-            DEFAULT_CONFIG.update_config('nav_default_config.yaml')
-        except FileNotFoundError:
-            pass
+    load_default_and_user_config(arguments, DEFAULT_CONFIG)
src/main/nav_backplanes_cloud_tasks.py (1)

109-117: Add exception handling and return consistent success payload.

Two issues:

  1. Missing exception handling: generate_backplanes_image_files can raise FileNotFoundError when metadata is missing. Unlike nav_backplanes.py (lines 145-157) which catches this, the cloud-tasks version will crash the task.

  2. Inconsistent success response: Returns (False, None) on success while nav_create_bundle_cloud_tasks.py returns (False, {'status': 'success'}).

🔎 Proposed fix
+    try:
         generate_backplanes_image_files(
             obs_class,
             ImageFiles(image_files=image_files),
             nav_results_root=nav_results_root,
             backplane_results_root=backplane_results_root,
             write_output_files=True
         )
+    except FileNotFoundError as e:
+        return False, {
+            'status': 'error',
+            'status_error': 'missing_metadata',
+            'status_exception': str(e)
+        }

-    return False, None  # No retry under any circumstances
+    return False, {'status': 'success'}  # No retry under any circumstances
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between accc18d and e09cb9d.

📒 Files selected for processing (17)
  • docs/user_guide_backplanes.rst
  • docs/user_guide_pds4_bundle.rst
  • src/backplanes/writer.py
  • src/main/nav_backplanes.py
  • src/main/nav_backplanes_cloud_tasks.py
  • src/main/nav_create_bundle.py
  • src/main/nav_create_bundle_cloud_tasks.py
  • src/main/nav_offset.py
  • src/main/nav_offset_cloud_tasks.py
  • src/nav/config/__init__.py
  • src/nav/config/config_helper.py
  • src/nav/dataset/dataset_pds3.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_voyager_iss.py
  • src/pds4/collections.py
  • src/pds4/templates/cassini_iss_saturn_1.0/readme.txt
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-11-24T19:48:51.676Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 48
File: main/nav_main_offset.py:167-171
Timestamp: 2025-11-24T19:48:51.676Z
Learning: In the nav_main_offset.py file, it is normal and expected for the nav_default_config.yaml file to be missing. The FileNotFoundError suppression when attempting to load this default config is intentional behavior, not an error condition that needs logging.

Applied to files:

  • src/main/nav_offset_cloud_tasks.py
  • src/main/nav_offset.py
  • src/main/nav_create_bundle_cloud_tasks.py
  • src/main/nav_backplanes.py
  • src/main/nav_backplanes_cloud_tasks.py
📚 Learning: 2025-12-23T19:46:29.815Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 68
File: src/nav/dataset/dataset_pds3_cassini_iss.py:241-241
Timestamp: 2025-12-23T19:46:29.815Z
Learning: In Python, for staticmethod methods, super() cannot be used because there is no class or instance context. If a subclass static method needs to call a parent class's static method, invoke it directly as ParentClass.method_name() rather than super().method_name(). This applies broadly to Python files in the repository; ensure the parent method is defined as a static method or accessible in the class hierarchy and that imports are correct.

Applied to files:

  • src/main/nav_offset_cloud_tasks.py
  • src/main/nav_offset.py
  • src/nav/config/config_helper.py
  • src/backplanes/writer.py
  • src/main/nav_create_bundle_cloud_tasks.py
  • src/main/nav_backplanes.py
  • src/main/nav_create_bundle.py
  • src/nav/dataset/dataset_pds3_voyager_iss.py
  • src/main/nav_backplanes_cloud_tasks.py
  • src/nav/dataset/dataset_pds3.py
  • src/nav/config/__init__.py
  • src/pds4/collections.py
  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
📚 Learning: 2025-09-22T21:03:10.431Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 1
File: tests/nav/dataset/test_dataset_pds3_newhorizons_lorri.py:27-33
Timestamp: 2025-09-22T21:03:10.431Z
Learning: PDS3 (Planetary Data System version 3) archives are immutable and never updated once finalized. Exact count assertions in tests for PDS3 datasets are appropriate since the underlying data will never change.

Applied to files:

  • src/nav/dataset/dataset_pds3.py
  • src/nav/dataset/dataset_pds3_newhorizons_lorri.py
  • src/nav/dataset/dataset_pds3_galileo_ssi.py
📚 Learning: 2025-09-22T23:18:15.371Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 1
File: tests/nav/dataset/test_dataset_pds3_cassini_iss.py:29-34
Timestamp: 2025-09-22T23:18:15.371Z
Learning: PDS3 dataset indices are stable and immutable once archived, making exact count assertions appropriate in tests rather than using lower-bound checks.

Applied to files:

  • src/nav/dataset/dataset_pds3.py
📚 Learning: 2025-11-10T22:24:08.880Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 14
File: nav/obs/__init__.py:36-44
Timestamp: 2025-11-10T22:24:08.880Z
Learning: In nav/obs/__init__.py, the __all__ list should maintain semantic grouping rather than alphabetical ordering: generic classes (Obs, ObsSnapshot, ObsSnapshotInst) first, followed by specific instrument classes (ObsCassiniISS, etc.), then helper functions (inst_names, inst_name_to_obs_class).

Applied to files:

  • src/nav/config/__init__.py
📚 Learning: 2025-12-23T19:48:24.234Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 68
File: src/pds4/collections.py:293-303
Timestamp: 2025-12-23T19:48:24.234Z
Learning: In the rms-nav repository, pdstemplate.write() automatically handles uploading to remote storage when the target path is an FCPath or URL-based path. Explicit .upload() calls after pdstemplate.write() are redundant for FCPath objects.

Applied to files:

  • src/pds4/collections.py
📚 Learning: 2025-12-04T23:41:21.874Z
Learnt from: rfrenchseti
Repo: SETI/rms-nav PR: 52
File: nav/obs/obs_inst_voyager_iss.py:47-49
Timestamp: 2025-12-04T23:41:21.874Z
Learning: In the rms-nav codebase, `FCPath.get_local_path()` from the filecache library returns `Path | list[Path]`. When used with a single path argument, `cast(Path, fc_path.get_local_path())` is required to narrow the type to `Path` for type checking purposes. This pattern is intentionally used across observation instrument files (obs_inst_voyager_iss.py, obs_inst_newhorizons_lorri.py, obs_inst_cassini_iss.py, obs_inst_galileo_ssi.py).

Applied to files:

  • src/nav/dataset/dataset_pds3_galileo_ssi.py
🧬 Code graph analysis (10)
src/main/nav_offset_cloud_tasks.py (3)
src/nav/config/config_helper.py (2)
  • get_nav_results_root (45-79)
  • load_default_and_user_config (120-141)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_inst_name (72-84)
src/nav/obs/__init__.py (1)
  • inst_name_to_obs_class (26-35)
src/main/nav_offset.py (2)
src/nav/config/config_helper.py (2)
  • get_nav_results_root (45-79)
  • load_default_and_user_config (120-141)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/nav/config/config_helper.py (1)
src/nav/config/config.py (4)
  • Config (9-231)
  • environment (119-123)
  • read_config (60-81)
  • update_config (83-102)
src/backplanes/writer.py (3)
src/nav/support/file.py (1)
  • json_as_string (94-102)
src/nav/obs/obs_snapshot.py (1)
  • closest_planet (302-303)
src/nav/config/config.py (2)
  • Config (9-231)
  • satellites (132-145)
src/main/nav_create_bundle_cloud_tasks.py (3)
src/nav/dataset/__init__.py (1)
  • dataset_name_to_class (57-69)
src/nav/config/config_helper.py (4)
  • get_backplane_results_root (7-42)
  • get_nav_results_root (45-79)
  • get_pds4_bundle_results_root (82-117)
  • load_default_and_user_config (120-141)
src/pds4/bundle_data.py (1)
  • generate_bundle_data_files (14-128)
src/main/nav_backplanes.py (3)
src/nav/config/config_helper.py (3)
  • get_backplane_results_root (7-42)
  • get_nav_results_root (45-79)
  • load_default_and_user_config (120-141)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/backplanes/backplanes.py (1)
  • generate_backplanes_image_files (18-99)
src/main/nav_create_bundle.py (3)
src/nav/dataset/__init__.py (2)
  • dataset_names (52-54)
  • dataset_name_to_class (57-69)
src/pds4/bundle_data.py (1)
  • generate_bundle_data_files (14-128)
src/pds4/collections.py (2)
  • generate_collection_files (13-125)
  • generate_global_index_files (128-322)
src/main/nav_backplanes_cloud_tasks.py (2)
src/nav/config/config_helper.py (3)
  • get_backplane_results_root (7-42)
  • get_nav_results_root (45-79)
  • load_default_and_user_config (120-141)
src/backplanes/backplanes.py (1)
  • generate_backplanes_image_files (18-99)
src/nav/config/__init__.py (1)
src/nav/config/config_helper.py (4)
  • get_backplane_results_root (7-42)
  • get_nav_results_root (45-79)
  • get_pds4_bundle_results_root (82-117)
  • load_default_and_user_config (120-141)
src/nav/dataset/dataset_pds3_galileo_ssi.py (4)
src/nav/dataset/dataset.py (10)
  • ImageFile (15-60)
  • pds4_bundle_template_dir (155-168)
  • pds4_bundle_name (170-180)
  • pds4_bundle_path_for_image (183-194)
  • pds4_path_stub (196-207)
  • pds4_image_name_to_browse_lid (209-220)
  • pds4_image_name_to_browse_lidvid (222-233)
  • pds4_image_name_to_data_lid (235-246)
  • pds4_image_name_to_data_lidvid (248-259)
  • pds4_template_variables (261-282)
src/nav/dataset/dataset_pds3_newhorizons_lorri.py (9)
  • pds4_bundle_template_dir (182-197)
  • pds4_bundle_name (199-204)
  • pds4_bundle_path_for_image (207-209)
  • pds4_path_stub (211-213)
  • pds4_image_name_to_browse_lid (215-224)
  • pds4_image_name_to_browse_lidvid (226-235)
  • pds4_image_name_to_data_lid (237-246)
  • pds4_image_name_to_data_lidvid (248-257)
  • pds4_template_variables (259-267)
src/nav/dataset/dataset_pds3_voyager_iss.py (9)
  • pds4_bundle_template_dir (189-204)
  • pds4_bundle_name (206-211)
  • pds4_bundle_path_for_image (214-216)
  • pds4_path_stub (218-220)
  • pds4_image_name_to_browse_lid (222-231)
  • pds4_image_name_to_browse_lidvid (233-242)
  • pds4_image_name_to_data_lid (244-253)
  • pds4_image_name_to_data_lidvid (255-264)
  • pds4_template_variables (266-274)
src/nav/config/config.py (1)
  • pds4 (227-231)
🪛 Ruff (0.14.10)
src/nav/config/config_helper.py

38-41: Avoid specifying long messages outside the exception class

(TRY003)


75-78: Avoid specifying long messages outside the exception class

(TRY003)


113-116: Avoid specifying long messages outside the exception class

(TRY003)


134-134: Consider moving this statement to an else block

(TRY300)

src/main/nav_backplanes.py

154-156: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

src/nav/config/__init__.py

7-7: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


9-15: __all__ is not sorted

Apply an isort-style sorting to __all__

(RUF022)

src/pds4/collections.py

36-36: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test nav (ubuntu-latest, 3.12)
  • GitHub Check: Test nav (ubuntu-latest, 3.13)
  • GitHub Check: Test nav (ubuntu-latest, 3.11)
  • GitHub Check: Test nav (ubuntu-latest, 3.10)
🔇 Additional comments (43)
src/nav/dataset/dataset_pds3_galileo_ssi.py (3)

3-6: LGTM! Import addition is necessary.

The ImageFile import is required for the type annotation in pds4_template_variables method signature.


198-220: LGTM! Implementations follow established patterns.

The pds4_bundle_template_dir and pds4_bundle_name methods correctly follow the same configuration-driven pattern used in Voyager ISS and New Horizons LORRI dataset classes, with appropriate defaults for Galileo SSI.


222-283: LGTM! Stub methods are consistent with other dataset implementations.

All PDS4-related stub methods follow the same signatures and patterns as Voyager ISS and New Horizons LORRI datasets. The pds4_template_variables method now correctly includes the keyword-only marker (*,) at line 277, resolving the previously flagged signature mismatch. The NotImplementedError placeholders are appropriate for this initial PDS4 implementation pass.

src/nav/dataset/dataset_pds3_newhorizons_lorri.py (9)

6-6: LGTM: Import added for PDS4 extension methods.

The ImageFile import is necessary for type hints in the new PDS4-related methods.


182-197: LGTM: Configuration-driven template directory resolution.

The method correctly resolves template directories from configuration with appropriate fallback to a default template name, and handles both absolute and relative paths.


199-204: LGTM: Simple configuration-driven bundle name getter.

The method provides appropriate configuration lookup with a reasonable default value.


211-213: Intentional extension point established.

This placeholder method is part of the PDS4 scaffolding pattern for path stub generation.


215-224: Intentional extension point established.

This placeholder method is part of the PDS4 scaffolding pattern for LID mapping. The docstring correctly describes the method's purpose.


226-235: Intentional extension point established with correct documentation.

This placeholder method is part of the PDS4 scaffolding pattern. The docstring correctly describes returning a LIDVID (the previous docstring inconsistency has been resolved).


237-246: Intentional extension point established.

This placeholder method is part of the PDS4 scaffolding pattern for data LID mapping. The docstring correctly describes the method's purpose.


248-257: Intentional extension point established.

This placeholder method is part of the PDS4 scaffolding pattern for data LIDVID mapping. The docstring correctly describes the method's purpose.


259-267: Intentional extension point established with correct signature.

This placeholder method is part of the PDS4 scaffolding pattern for template variable generation. The signature correctly uses keyword-only parameters (the previous signature mismatch has been resolved).

src/nav/config/__init__.py (2)

3-7: LGTM - Imports are clean and well-organized.

The new imports from config_helper expose essential path resolution and configuration loading utilities that are consumed by multiple CLI modules (backplanes, offset, bundle generation).


9-15: __all__ ordering is semantically grouped and appropriate.

The current ordering (Config objects first, then helper functions) is consistent with the repository's preference for semantic grouping over strict alphabetical sorting. Static analysis suggesting alphabetical sorting can be safely ignored here.

Based on learnings, semantic grouping is preferred for __all__ lists in this repository.

src/nav/dataset/dataset_pds3_voyager_iss.py (2)

189-211: LGTM - Config-driven PDS4 bundle defaults are well-implemented.

The template directory and bundle name methods properly fall back to sensible defaults (voyager_iss_1.0 and voyager_iss_backplanes_rsfrench2027) when not configured, and correctly resolve relative paths relative to the pds4/templates directory.


213-274: LGTM - PDS4 method placeholders provide clear extension points.

These NotImplementedError placeholders establish the PDS4 interface for future implementation while documenting the expected signatures and return types. The docstrings correctly distinguish between LID and LIDVID methods.

src/backplanes/writer.py (2)

14-36: LGTM - Function signature refactored to support new metadata workflow.

The function signature changes (removing label_file_path, adding bodies_result and rings_result) align with the broader PR refactoring that moves PDS4 label generation to a separate bundle generation pass. The new parameters enable metadata aggregation from backplane creation results.


71-124: LGTM - Metadata construction and JSON serialization are well-structured.

The backplane metadata construction properly:

  • Initializes inv to an empty dict (line 89) when closest_planet is None, avoiding UnboundLocalError
  • Extracts per-body statistics and inventory data (lines 92-117)
  • Correctly reorders center_uv from [u, v] to [v, u] format (lines 103-104)
  • Handles optional ring statistics (lines 119-121)
  • Writes clean JSON via json_as_string helper (line 123)
docs/user_guide_backplanes.rst (1)

27-28: LGTM - Documentation updates are clear and concise.

The updated descriptions for --nav-results-root and --backplane-results-root accurately reflect the centralized root resolution behavior introduced in the config helpers.

src/pds4/templates/cassini_iss_saturn_1.0/readme.txt (1)

1-44: LGTM - Bundle readme content is accurate and well-structured.

The readme correctly describes the Cassini ISS Saturn backplanes bundle with:

  • Appropriate content description (backplanes products, not F-ring mosaics)
  • Consistent URN identifiers throughout
  • Clear citation template with TODO for DOI
  • Contact information for support

Previous concerns about F-ring content mismatch have been addressed.

src/main/nav_offset.py (2)

30-32: LGTM - Config refactoring centralizes root resolution cleanly.

The refactoring consolidates configuration loading and navigation root resolution into shared helper functions from nav.config, eliminating duplicated logic. The use of FileCache(None).new_path() is consistent with the pattern in dataset_pds3.py (line 59).

Also applies to: 167-171


58-58: LGTM - Usage string updates make CLI documentation more generic.

Removing the script name prefix (python nav_main_offset.py) from usage messages makes the documentation cleaner and more suitable for installed CLI commands.

Also applies to: 66-66, 74-74

docs/user_guide_pds4_bundle.rst (2)

1-400: LGTM - Comprehensive PDS4 bundle generation documentation.

The documentation provides clear, thorough coverage of:

  • Two-pass workflow (labels and summary passes)
  • Bundle directory structure and file organization
  • CLI interfaces for both local and cloud-based processing
  • Configuration options and template system
  • Complete workflow examples
  • Troubleshooting guidance

This is excellent documentation for users implementing PDS4 bundle generation.


93-95: No issues found. The CLI argument --bundle-results-root correctly converts to arguments.bundle_results_root in the argparse Namespace, and the implementation in config_helper.py correctly accesses this attribute.

src/main/nav_offset_cloud_tasks.py (2)

25-67: LGTM! Solid refactoring to centralized configuration helpers.

The migration to load_default_and_user_config and get_nav_results_root eliminates ad-hoc configuration handling and standardizes error responses across cloud-tasks entry points.


72-115: LGTM! Consistent error handling across validation paths.

All validation failures now return structured error payloads with status and status_error keys, enabling better monitoring and retry logic in the cloud-tasks framework.

src/main/nav_backplanes.py (3)

26-29: LGTM! Configuration loading aligns with centralized pattern.

The migration to load_default_and_user_config and the new root resolution helpers (get_nav_results_root, get_backplane_results_root) eliminates environment-variable fallback code and centralizes the resolution logic.

Also applies to: 114-121


126-132: LGTM! Enhanced startup logging improves observability.

Logging the configuration state (roots, flags, arguments) at startup aids in debugging and operational monitoring.


145-157: LGTM! Exception handling allows continued processing despite missing metadata.

The try/except block gracefully handles missing metadata files, logs the error with context, and continues processing remaining images.

src/main/nav_backplanes_cloud_tasks.py (2)

24-57: LGTM! Centralized root resolution with consistent error handling.

Both navigation and backplane roots are resolved using the new helpers with proper try/except blocks returning structured error payloads.


60-100: LGTM! Validation errors use consistent structured payloads.

All validation failures return dictionaries with status and status_error keys, improving monitoring and debugging capabilities.

src/main/nav_create_bundle_cloud_tasks.py (2)

24-66: LGTM! Consistent root resolution across all three required roots.

Navigation, backplane, and bundle roots are all resolved using the centralized helpers with proper error handling.


68-116: LGTM! Comprehensive validation with consistent error reporting.

All validation steps return structured error payloads, enabling proper error tracking and monitoring.

src/nav/config/config_helper.py (1)

120-141: LGTM! Config loading centralizes the pattern used across entry points.

The function properly handles user-specified config files with fallback to the default. Based on learnings, the FileNotFoundError suppression for nav_default_config.yaml is intentional.

src/pds4/collections.py (5)

13-52: LGTM! Clear structure for collection file generation.

The function properly scans for label files, validates directory existence, and sorts by image name.


54-90: LGTM! Collection data generation with proper error handling.

The CSV and label generation follow proper patterns with exception handling around template writes.


92-125: LGTM! Browse collection generation mirrors data collection pattern.

Consistent structure with proper error handling for template operations.


128-226: LGTM! Global index row collection with resilient error handling.

The function scans supplemental files and builds index rows for bodies and rings. The exception handling at lines 178-181 allows processing to continue when individual files fail, as acknowledged in past reviews.


228-322: LGTM! Index file and label generation with consistent error handling.

Both bodies and rings index files are generated with proper formatting, and labels are rendered with matching exception handling. As noted in past reviews, pdstemplate.write() handles upload automatically for FCPath objects.

src/main/nav_create_bundle.py (4)

40-72: LGTM! Common argument helper with proper keyword-only parameter.

The for_labels parameter is now keyword-only, improving call-site clarity as suggested in past reviews.


74-136: LGTM! Argument parsers with proper dataset validation.

Both subcommand parsers validate dataset names early with clear error messages.


139-162: LGTM! Config loading and root resolution use centralized helpers.

The labels subcommand properly loads configuration and resolves all required roots using the new helper functions.


211-234: LGTM! Summary generation with proper error handling and cleanup.

Both collection and global index generation are wrapped in try/except blocks with appropriate logging and exit behavior.

@rfrenchseti rfrenchseti merged commit cc9feb2 into main Dec 23, 2025
6 checks passed
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.

Write summary image label generator Implement backplane aggregator and label generator

2 participants