Refuse multi-class predictions in the postprocess CLI - #428
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens the jabs-cli postprocess pipeline by explicitly refusing multi-class prediction inputs, preventing confusing shape-validation crashes and avoiding creation of partially written output files. It aligns CLI behavior with the GUI’s existing “binary-only” postprocessing gate.
Changes:
- Add a pre-flight validation (
_multiclass_behaviors) to detect multi-class behaviors (viaclass_names) and fail early with a clearClickException. - Preserve
class_nameswhen rebuilding and savingBehaviorPredictionto avoid metadata being dropped during writes. - Add regression tests covering refusal behavior, output-file non-creation, mixed binary+multiclass files, and preservation of multi-class metadata for untouched behaviors.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/jabs/scripts/cli/postprocessing.py |
Adds early multi-class refusal and ensures class_names is carried through when rewriting predictions. |
tests/scripts/test_apply_postprocessing.py |
Adds regression tests for multi-class refusal, file safety (no partial outputs), and mixed-content prediction files. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
jabs-cli postprocesscannot process a multi-class prediction file, and fails in the worst way: an unhandledValueErrorabout array shapes, after leaving a partially written output file behind.Found while reviewing #427, where the justification for a change cited the GUI's binary-only gate (
MultiClassClassifyStrategy.postprocess_identityreturnsNone). The CLI has no equivalent gate.What happens today
run_apply_postprocessingloads the predictions (includingclass_names), runs every stage over the multi-class vectors, then rebuildsBehaviorPredictionwithout passingclass_namesthrough. The dataclass validator infers the binary probability shape from aNoneclass_namesand rejects the 3-D array. The construction is not inside atry, so the user gets a raw traceback whose message says nothing about multi-class files.Two consequences beyond the traceback:
out.h5is created before the failure (the source file is copied up front), so the run leaves an output file with no postprocessed data in it.states == ClassLabels.BEHAVIOR), so those results were meaningless — only the crash kept them off disk.Change
Refuse multi-class input, checked in the existing pre-flight validation block alongside the "behavior not found in file" check, so it fails before the output file is created:
A new
_multiclass_behaviors()helper identifies them by the presence of aclass_namesdataset, mirroring how_list_behaviors()inspects the file. Only the behaviors named in the config are checked, so a binary behavior still processes normally from a file that also contains multi-class predictions.Pass
class_namesthrough when rebuildingBehaviorPrediction. It isNonefor every binary file, so this is a no-op today, but it closes a latent hazard: the HDF5 adapter deletes an existingclass_namesdataset when the field isNone, which would have silently stripped that metadata had the validator not raised first.Refusing rather than supporting is deliberate: making the stages meaningful for multi-class predictions is a feature (they would need to know which class is the behavior, or operate per class), not a bug fix. This matches the GUI, which declines the same work.
Verification
Before and after, same input, through the real CLI:
ValueError: probabilities shape (2, 50, 3) does not match expected shape (2, 50)(traceback)Error: Post-processing supports binary predictions only...Four regression tests: the refusal and its message, the file being left untouched, a multi-class behavior named alongside binary ones aborting before any output, and a binary behavior still processing from a file that also holds multi-class predictions (asserting the untouched group keeps its class names).
ruff check,ruff format,pytest(1010 passed) andpytest packages/jabs-behavior/tests(101 passed) are clean.