Parent PRD
#245
What to build
Replace the single "Remove intermediate files" checkbox in the napari Settings widget with a new collapsible per-output retention group, and update SettingsConfig to carry a frozenset[str] of drop keys instead of a bool:
SettingsConfig schema change: replace remove_intermediates: bool with cleanup_drop_keys: frozenset[str] (default-factory frozenset). Update to_config to populate it from the new widget; update apply_config to push it into the new widget.
- New widget composition (in
nellie_napari/nellie_settings.py): a QGroupBox titled "Intermediate file retention," default-collapsed, placed where the old single checkbox lived. Composition:
- A horizontal preset radio row at top: "Keep everything" (default-selected), "Masks + CSVs only," "CSVs only," "Custom" (auto-selected when individual toggles diverge from a named preset; not user-clickable).
- Below the radio: stage-grouped checkbox subgroups under headers
Filter, Label, Network, Markers, Tracking, Voxel reassignment, Hierarchy, Pipeline input. The 14 checkboxes correspond exactly to the 14 keys in DROPPABLE_KEYS. Each checkbox label has the form Friendly Name (raw_key) — see PRD §Implementation Decisions for the stage-to-key mapping.
- Checkbox semantics: checked = drop, unchecked = keep. Tooltips on each checkbox list consumer stages.
- Preset radio behavior: clicking a preset sets the per-output checkbox states to match the preset's drop set. Toggling any individual checkbox flips the radio to "Custom" automatically.
- Remove the old
remove_intermediates_checkbox — its layout slot is reclaimed by the new group. The new group sits in the same subprocessor_layout1 position (or however the new layout best fits).
This slice does NOT touch nellie_napari/nellie_processor.py — that wiring is filed as Slice 4.
Acceptance criteria
Blocked by
User stories addressed
From PRD #245:
- User story 1 (per-output toggles for masks-only retention).
- User story 2 (one-click "CSVs only" preset).
- User story 3 (backward-compat preset name recognizable).
- User story 4 ("Custom" preset auto-selected on divergence).
- User story 9 (default = "Keep everything").
- User story 10 (tooltips list consumer stages).
- User story 13 (
im_path in its own "Pipeline input" group).
- User story 14 (collapsible group, default-collapsed).
- User story 15 (preset radio at top).
- User story 16 ("Custom" auto-flip).
Wiki context
wiki/napari-plugin/ — current widget structure for reference.
wiki/pipeline.md — stage→output mapping that the UI groups follow.
wiki/decisions/0014-intermediates-policy-frozenset.md — the API-shape decision and the rationale behind frozenset[str] + presets-as-constants.
Parent PRD
#245
What to build
Replace the single "Remove intermediate files" checkbox in the napari Settings widget with a new collapsible per-output retention group, and update
SettingsConfigto carry afrozenset[str]of drop keys instead of a bool:SettingsConfigschema change: replaceremove_intermediates: boolwithcleanup_drop_keys: frozenset[str](default-factoryfrozenset). Updateto_configto populate it from the new widget; updateapply_configto push it into the new widget.nellie_napari/nellie_settings.py): aQGroupBoxtitled "Intermediate file retention," default-collapsed, placed where the old single checkbox lived. Composition:Filter,Label,Network,Markers,Tracking,Voxel reassignment,Hierarchy,Pipeline input. The 14 checkboxes correspond exactly to the 14 keys inDROPPABLE_KEYS. Each checkbox label has the formFriendly Name (raw_key)— see PRD §Implementation Decisions for the stage-to-key mapping.remove_intermediates_checkbox— its layout slot is reclaimed by the new group. The new group sits in the samesubprocessor_layout1position (or however the new layout best fits).This slice does NOT touch
nellie_napari/nellie_processor.py— that wiring is filed as Slice 4.Acceptance criteria
SettingsConfig.cleanup_drop_keys: frozenset[str]field exists; default isfrozenset().SettingsConfig.remove_intermediatesfield is gone.to_config()returnscleanup_drop_keysasfrozenset[str]populated from the per-output checkbox states (collect keys whose checkbox is checked).apply_config(config)sets per-output checkboxes fromconfig.cleanup_drop_keysand selects the preset radio that matches the loaded drop set (or "Custom" if none).DROPPABLE_KEYS, grouped under the 8 stage headers per the PRD's mapping. Friendly labels include the raw key in parens.DROPPABLE_KEYS.im_instance_label,im_branch_label_reassigned,im_obj_label_reassigned,im_pathare unchecked; the other 10 are checked → drop set isMASKS_AND_CSVS_PRESET.tests/test_napari_settings.py, creating the file if it does not exist; useqtbotfixture frompytest-qtif available, otherwise minimal direct-instantiation tests):test_settings_config_default_cleanup_drop_keys_is_empty_frozenset.test_apply_config_then_to_config_round_trip— parametrize over each preset.test_widget_preset_radio_reflects_loaded_drop_set— apply each preset; assert the matching radio is selected; apply a non-preset drop set; assert "Custom" is selected.test_widget_toggle_after_preset_switches_to_custom— applyKEEP_EVERYTHING_PRESET; toggle one checkbox; assert "Custom" is selected.pytest tests/test_napari_settings.py -qpasses.pytest -q --ignore=tests/test_*_perf.py) still pass — no regression.Blocked by
DROPPABLE_KEYSand the preset constants).User stories addressed
From PRD #245:
im_pathin its own "Pipeline input" group).Wiki context
wiki/napari-plugin/— current widget structure for reference.wiki/pipeline.md— stage→output mapping that the UI groups follow.wiki/decisions/0014-intermediates-policy-frozenset.md— the API-shape decision and the rationale behindfrozenset[str]+ presets-as-constants.