Add trying variants to a bunch of APIs - #243
Conversation
|
Warning Review limit reached
More reviews will be available in 34 minutes and 14 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (15)
📝 WalkthroughWalkthroughThe PR adds fallible ChangesFallible helpers and explicit errors
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
96f8f06 to
aab655e
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ext/crates/algebra/src/algebra/adem_algebra.rs`:
- Around line 1320-1338: The try_beps_pn lookup can still panic because
try_basis_element_to_index reads from basis_element_to_index_map before the
requested degree has been generated. Update try_beps_pn in AdemAlgebra to
compute the target degree first and call self.compute_basis(degree) before
constructing the AdemBasisElement and delegating to try_basis_element_to_index,
so the try_ path remains non-panicking for callers that have not precomputed the
basis.
In `@ext/crates/algebra/src/module/module_trait.rs`:
- Around line 88-89: In `Module::basis` and the related fallible helper that
calls `compute_basis` and `dimension`, validate the incoming
`mod_degree`/`input_degree` against `self.min_degree()` before invoking any
implementor-provided methods. Move the minimum-degree guard ahead of
`compute_basis(...)` and `self.dimension(...)`, and return the existing
below-minimum error early so invalid binding input never reaches
implementation-specific panic paths.
In `@ext/crates/sseq/src/sseq.rs`:
- Around line 465-471: The doc comment on try_write_to_graph is stale: it still
says the method “shifts the sseq horizontally,” but this function only validates
the min-y precondition and performs graph writing. Update the documentation near
try_write_to_graph to remove that sentence and keep the description aligned with
its actual behavior, while preserving the notes about write_to_graph and the
Err(String) precondition check.
In `@ext/src/chain_complex/mod.rs`:
- Around line 120-130: The try_filtration_one_product path can still panic on
invalid negative inputs before the existing computed-bidegree checks protect the
indexing calls. Add early validation in try_filtration_one_product for
source.s() and op_deg so any negative values return an error before calling
self.module(target.s() - 1), self.module(target.s()), or
self.algebra().dimension_unstable. Keep the guard close to the start of the
function, using the existing target/source/bidegree logic to preserve the
current behavior for valid inputs.
In `@ext/src/secondary.rs`:
- Around line 529-532: The try_compute_homotopy_step path currently indexes
self.homotopies()[b.s()] directly, which can panic before the Result-based error
handling is reached. Update try_compute_homotopy_step to use a fallible lookup
with get on the homotopies collection, and return an anyhow error with context
when the homotopy degree is uninitialized or out of bounds so callers receive
Err instead of a panic.
In `@ext/src/utils.rs`:
- Around line 238-246: The cofiber path in `new_output`/`row_mut` can panic
because `Matrix::row_mut` is called with `cofiber.idx()` before checking bounds.
Add a validation step in this cofiber handling logic to ensure the parsed `idx`
is less than
`resolution.module(cofiber.s()).number_of_gens_in_degree(cofiber.t())`, and
return a contextual error if it is out of range instead of proceeding to
`row_mut`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9f0afc3a-fd3c-4100-8c20-923af105bb7d
📒 Files selected for processing (15)
ext/crates/algebra/src/algebra/adem_algebra.rsext/crates/algebra/src/algebra/algebra_trait.rsext/crates/algebra/src/algebra/milnor_algebra.rsext/crates/algebra/src/module/finite_dimensional_module.rsext/crates/algebra/src/module/mod.rsext/crates/algebra/src/module/module_trait.rsext/crates/sseq/src/sseq.rsext/src/chain_complex/mod.rsext/src/secondary.rsext/src/utils.rsext/src/yoneda.rsext/tests/construct_cofiber_error.rsext/tests/filtration_one_product.rsext/tests/parse_module_name.rsext/tests/try_yoneda.rs
| self.compute_basis(mod_degree); | ||
| let mod_dim = self.dimension(mod_degree); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Check the module degree before calling implementor methods.
Both fallible helpers still pass arbitrary mod_degree / input_degree into compute_basis and dimension before rejecting below-minimum degrees, so invalid binding input can still reach implementation-specific panic paths. Guard against degree < self.min_degree() first.
Proposed fix
- self.compute_basis(mod_degree);
+ let min_degree = self.min_degree();
+ if mod_degree < min_degree {
+ return Err(ActError::IndexOutOfRange(format!(
+ "mod_degree {mod_degree} is below module minimum degree {min_degree}"
+ )));
+ }
+ self.compute_basis(mod_degree);
let mod_dim = self.dimension(mod_degree);- self.compute_basis(input_degree);
+ let min_degree = self.min_degree();
+ if input_degree < min_degree {
+ return Err(ActError::IndexOutOfRange(format!(
+ "input_degree {input_degree} is below module minimum degree {min_degree}"
+ )));
+ }
+ self.compute_basis(input_degree);
let input_dim = self.dimension(input_degree);Also applies to: 125-126
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ext/crates/algebra/src/module/module_trait.rs` around lines 88 - 89, In
`Module::basis` and the related fallible helper that calls `compute_basis` and
`dimension`, validate the incoming `mod_degree`/`input_degree` against
`self.min_degree()` before invoking any implementor-provided methods. Move the
minimum-degree guard ahead of `compute_basis(...)` and `self.dimension(...)`,
and return the existing below-minimum error early so invalid binding input never
reaches implementation-specific panic paths.
| /// - the length of `class` must match the number of generators of `cc` in bidegree `b`. | ||
| /// | ||
| /// (The internal Euler-characteristic / lift sanity checks remain as `assert!`s, as they witness | ||
| /// mathematical invariants that cannot be checked without replaying the computation.) |
There was a problem hiding this comment.
We should replace those asserts by anyhow::bail
The op_idx bounds check on filtration_one_product was gated behind `if U`, so stable resolutions (U == false) skipped it. This let an out-of-range op_idx flow into FreeModule::operation_generator_to_index and FpVector::entry, causing a panic for large op_idx or a silent read of a neighbouring generator's coefficient for moderate op_idx. Add try_filtration_one_product returning anyhow::Result<Vec<Vec<u32>>>, which errors (rather than panicking or silently misreading) when the target bidegree is uncomputed or op_idx is out of range. filtration_one_product is now try_filtration_one_product(..).ok(), so it returns Some when the product is defined and None otherwise.
beps_pn is now try_beps_pn(..).unwrap(), so existing callers are unaffected while a fallible variant is available.
Use try_beps_pn / try_basis_element_to_index instead of the panicking variants, and compute the basis first for Adem, so nonexistent or out-of-profile names yield None instead of aborting the process.
…icking) Additive default trait methods that guard indices/degrees and delegate, leaving existing methods unchanged. try_act/try_act_on_basis return a typed ActError whose IndexOutOfRange and InvalidInput variants let callers (the Python bindings) map them to distinct exception types (IndexError vs ValueError).
parse_module_name previously panicked on a non-integer shift field; it now surfaces that via anyhow. load_module_json returns a typed LoadModuleError whose NotFound and Read variants let callers (the Python bindings) distinguish a missing module file (FileNotFoundError) from a read/parse failure (RuntimeError) without matching on error strings.
The cofiber-handling path in construct_standard panicked on malformed/unsupported specs: - assert!(!U, ...) aborted for unstable (U=true) cofiber specs - .unwrap() on cofiber["s"/"t"/"idx"] aborted on missing/non-integer fields - .expect(...) on module.max_degree() aborted for unbounded modules Convert these to anyhow errors (bail/context + ?) so the public construct/construct_standard/construct_nassau entry points return Err(...) for bad specs instead of panicking. Success behaviour is unchanged.
try_ variants added, each holding the actual logic with the panicking
function reduced to `try_x(..).unwrap()`:
- yoneda::try_yoneda_representative_element -> anyhow::Result<Yoneda<CC>>:
validates bidegree is computed and class length matches generator count.
yoneda_representative_element is now try_yoneda_representative_element(..)
.unwrap(). (Its internal Euler-characteristic / lift asserts remain, as
they witness invariants that cannot be checked without replaying the
computation.)
- Sseq::try_write_to_graph -> Result<Result<(), T::Error>, String>:
validates the min y-coordinate == 0 precondition (sseq crate has no anyhow
dependency, so a String error is used). write_to_graph is now
try_write_to_graph(..).unwrap().
Left as residue (must stay catch_unwind in bindings):
- secondary::{extend_all, compute_*}: the panics (quasi-inverse assert and
"Failed to lift" check) are mathematical failures only detectable while
replaying the lift computation; no clean up-front guard exists.
- Sseq::update / Sseq::leibniz: panics arise from internal indexing into
self-consistent data structures and are entangled with internal control
flow; no cheaply-checkable external precondition.
compute_homotopy_step is now try_compute_homotopy_step(b).unwrap(). The two invalid-input asserts (quasi-inverse application and the lift check) became anyhow errors via anyhow::ensure!. The top-level extend_* drivers stay panicking because they run through the parallel iter_s_t, which would need a fallible parallel-iteration refactor.
To help with Python bindings.
Summary by CodeRabbit
New Features
Noneinstead of panicking in common edge cases.Bug Fixes