Skip to content

Multi indexed migration - #218

Merged
JoeyBF merged 9 commits into
SpectralSequences:masterfrom
JoeyBF:multi_indexed_migration
Mar 26, 2026
Merged

Multi indexed migration#218
JoeyBF merged 9 commits into
SpectralSequences:masterfrom
JoeyBF:multi_indexed_migration

Conversation

@JoeyBF

@JoeyBF JoeyBF commented Mar 16, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • Refactor
    • Restructured spectral sequence data storage and access patterns for improved efficiency.
    • Simplified initialization API by removing minimum bidegree parameter from constructors.
    • Updated bidegree-based data lookups for direct, content-driven access.

@coderabbitai

coderabbitai Bot commented Mar 16, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR refactors the spectral sequence module by replacing DenseBigradedModule with a new generic Bigraded<V> wrapper type that stores content via MultiIndexed<2, V>. The change eliminates explicit dimension tracking and replaces nested 2D array access throughout Sseq, SseqWrapper, and related code with direct bidegree-indexed lookups.

Changes

Cohort / File(s) Summary
Core bigraded type
ext/crates/sseq/src/bigraded.rs, ext/crates/sseq/src/lib.rs
Replaced DenseBigradedModule with generic Bigraded<V>(MultiIndexed<2, V>). Removed dimension-tracking API; added content-based operations (get, insert, iter), indexing support via Index/IndexMut traits, and Default impl. Updated exports to explicitly re-export only Bigraded.
Sseq core refactoring
ext/crates/sseq/src/sseq.rs
Restructured Sseq from nested 2D arrays (page_data[x][y][r], differentials[x][y][r], etc.) plus Arc<DenseBigradedModule> to single data: Bigraded<BidegreeData>. Updated new() to remove min parameter and start empty. Refactored all core algorithms (clear, add_permanent_class, extend_differential, etc.) to use per-bidegree access via data[b]. Changed Product to store matrices in Bigraded<Matrix> instead of nested vectors. Updated write_to_graph iteration from nested x/y loops to bidegree iteration.
GUI wrapper updates
web_ext/sseq_gui/src/sseq.rs
Refactored SseqWrapper fields stale and class_names from nested BiVec to Bigraded. Removed min parameter from new(). Updated refresh() to collect invalid bidegrees first, then iterate over stale entries. Changed product and class-name access from 2D indexing to Bigraded lookups and insertions.
Integration points
ext/src/chain_complex/mod.rs, web_ext/sseq_gui/src/managers.rs
Updated to_sseq() to call Sseq::new(p) without min bidegree. Simplified filtration_one_products() to use direct Bigraded::new() construction and insertion. Removed min argument from SseqWrapper::new() call in SseqManager::resolving().

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 From dense dimensions, we leap and bound,
Bigraded maps each bidegree around,
No 2D arrays block our swift advance,
Just get() and insert() in a graceful dance!
MultiIndexed powers our spectral stride. ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Multi indexed migration' is directly related to the primary change: replacing the old dimension-tracking representation with a new generic Bigraded wrapper based on MultiIndexed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@ext/crates/once/src/multiindexed/mod.rs`:
- Line 1: The file imports std::sync::atomic::AtomicI32 directly which bypasses
the crate's loom-compatible atomics; change the import to use the crate
compatibility layer (crate::std_or_loom::sync::atomic::AtomicI32 or the crate's
re-export) so loom sees these atomics, updating the use statement in
multiindexed/mod.rs and any other direct std::sync::atomic references; if
AtomicI32 is not yet re-exported, add or use the appropriate re-export in
crate::std_or_loom so the bounds/synchronization helpers are modeled by loom and
adjust any Ordering uses to come from the same compatibility module.
- Around line 256-285: The current is_empty() only checks dimension 0 and can
return false while other dimensions still hold sentinel values; change
is_empty() to iterate all dimensions and return true if any
self.min_coords[i].load(...) > self.max_coords[i].load(...) (i.e. treat the
structure as empty if any dimension is uninitialized), so min_coords() and
max_coords() never expose sentinel values; reference update_bounds(),
is_empty(), min_coords(), max_coords(), and the min_coords / max_coords arrays
when making this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d19cc091-0745-486d-9805-89c1e4f83826

📥 Commits

Reviewing files that changed from the base of the PR and between 52aabe5 and c6291a2.

📒 Files selected for processing (8)
  • ext/crates/once/src/grove/block.rs
  • ext/crates/once/src/multiindexed/iter.rs
  • ext/crates/once/src/multiindexed/kdtrie.rs
  • ext/crates/once/src/multiindexed/mod.rs
  • ext/crates/sseq/src/bigraded.rs
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/sseq.rs
  • web_ext/sseq_gui/src/sseq.rs
💤 Files with no reviewable changes (2)
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/bigraded.rs

Comment thread ext/crates/once/src/multiindexed/mod.rs Outdated
Comment thread ext/crates/once/src/multiindexed/mod.rs
@JoeyBF
JoeyBF force-pushed the multi_indexed_migration branch from ed75fce to 4b4c863 Compare March 16, 2026 19:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
ext/crates/once/src/multiindexed/mod.rs (1)

268-294: ⚠️ Potential issue | 🟠 Major

is_empty() still leaks the sentinel when the last coordinate is i32::MIN.

Using Lines 273-274 as the publication guard still collides with a valid inserted value. If the first visible insert ends in i32::MIN, is_empty() can flip to false without a distinguishable publish on that guard coordinate, and min_coords() / max_coords() can still read i32::MAX / i32::MIN from earlier dimensions. A separate initialized flag, or reverting to an all-dimension emptiness check, avoids that edge case.

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

Inline comments:
In `@ext/crates/sseq/src/sseq.rs`:
- Around line 180-200: The code panics for omitted/zero-dimensional targets
because extend_differential blindly creates a Differential sized by
self.dimension(target) and extend_page_data clones the last page_data even when
none exists; modify extend_differential (function extend_differential) to check
the target dimension (let target = P::profile(r, b); let target_dim =
self.dimension(target)) and if target_dim == 0 create a Differential with zero
target dimension (or skip adding basis entries) instead of unwrapping or
assuming nonzero, and modify extend_page_data (function extend_page_data) to
handle an empty bd.page_data by pushing a default/zero PageData (construct an
empty page representation) when bd.page_data.is_empty() rather than calling
bd.page_data.last().unwrap().clone(), so extending works for omitted zero
bidegrees and higher-page differentials without panicking.
- Around line 97-109: The constructor Sseq::new currently ignores its _min
parameter so Sseq::min() returns (0,0) until data has entries; update the Sseq
struct to store the provided min (e.g., add a field like initial_min or
min_bidegree), set that field in Sseq::new(p: ValidPrime, min: Bidegree), and
modify Sseq::min() to return the stored min when self.data.min_coords() yields
None (otherwise keep returning Bidegree::x_y(min[0], min[1]) as before). Ensure
fields referenced are the existing ones (p, data, profile) and adjust any
constructors/usages accordingly so web_ext/sseq_gui’s calls to inner.min().y()
see the configured minimum before any insertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a06bb28b-0fb4-4d9c-af2a-51c6ed9ca157

📥 Commits

Reviewing files that changed from the base of the PR and between ed75fce and 4b4c863.

📒 Files selected for processing (6)
  • ext/crates/once/src/multiindexed/iter.rs
  • ext/crates/once/src/multiindexed/mod.rs
  • ext/crates/sseq/src/bigraded.rs
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/sseq.rs
  • web_ext/sseq_gui/src/sseq.rs
💤 Files with no reviewable changes (2)
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/bigraded.rs

Comment thread ext/crates/sseq/src/sseq.rs Outdated
Comment thread ext/crates/sseq/src/sseq.rs Outdated
@JoeyBF
JoeyBF force-pushed the multi_indexed_migration branch from 4b4c863 to 6728523 Compare March 17, 2026 05:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
ext/crates/once/src/multiindexed/mod.rs (1)

261-265: ⚠️ Potential issue | 🟠 Major

The emptiness publication still aliases a valid coordinate at i32::MIN.

Line 273 fixed the old “check dimension 0” bug, but the new scheme still uses a real coordinate value as the published empty/non-empty boundary. On a first insert whose last coordinate is i32::MIN, min_coords[K - 1] can already read i32::MIN while max_coords[K - 1] is still the initializer i32::MIN, so is_empty() returns false without synchronizing with the insert. In that window, min_coords() / max_coords() can still leak sentinels from earlier dimensions. This needs a separate initialized flag or another non-aliasing publication mechanism.

Also applies to: 269-275

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ext/crates/once/src/multiindexed/mod.rs` around lines 261 - 265, The
published empty/non-empty boundary currently aliases real coordinate value
i32::MIN causing is_empty() to misreport when a true coordinate equals the
sentinel; update_bounds (and related code that reads min_coords, max_coords,
min_coords(), max_coords(), and is_empty) should stop using a real coordinate as
the sentinel and instead publish initialization state separately—introduce a
per-dimension AtomicBool (or a single AtomicBool for the whole point if
appropriate) that is set when a dimension has been initialized, update
update_bounds to set that flag after storing min/max, and update
is_empty/min_coords/max_coords readers to consult thatinitialized flag before
trusting min/max values so no real coordinate value can be confused with the
sentinel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ext/crates/sseq/src/sseq.rs`:
- Around line 363-369: The current multiply implementation treats a missing
Product matrix as the zero map by creating a zero FpVector and proceeding;
instead, preserve the "undefined" contract by returning None when the product
entry is missing. Change multiply (in ext/crates/sseq/src/sseq.rs) to compute
target_b and call get_dimension(target_b)? first, then check
prod.matrices.get(elem.degree()) and if it is None return None immediately; only
when the matrix exists create the FpVector, call matrix.apply(...), and return
Some(BidegreeElement::new(...)). Ensure you reference the existing symbols
multiply, BidegreeElement, Product, prod.matrices.get, get_dimension, and
FpVector so the check and early return replace the current zero-vector behavior.

In `@web_ext/sseq_gui/src/sseq.rs`:
- Around line 490-500: The add_product replay path currently calls
Bigraded::insert on product.inner.matrices which panics if an entry for (name,
b) already exists; change this to have overwrite semantics: either use the
Bigraded API that replaces existing entries (e.g. an
insert_or_replace/replace/overwrite variant) or explicitly remove the existing
key from product.inner.matrices before inserting the new matrix (call remove(&b)
then insert). Also, if clear() is intended to discard old user matrices,
reinitialize or clear product.inner.matrices in the clear() implementation so
stale storage isn’t preserved for undo/redo.

---

Duplicate comments:
In `@ext/crates/once/src/multiindexed/mod.rs`:
- Around line 261-265: The published empty/non-empty boundary currently aliases
real coordinate value i32::MIN causing is_empty() to misreport when a true
coordinate equals the sentinel; update_bounds (and related code that reads
min_coords, max_coords, min_coords(), max_coords(), and is_empty) should stop
using a real coordinate as the sentinel and instead publish initialization state
separately—introduce a per-dimension AtomicBool (or a single AtomicBool for the
whole point if appropriate) that is set when a dimension has been initialized,
update update_bounds to set that flag after storing min/max, and update
is_empty/min_coords/max_coords readers to consult thatinitialized flag before
trusting min/max values so no real coordinate value can be confused with the
sentinel.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7c961713-b4c4-44ca-b978-b746d904b064

📥 Commits

Reviewing files that changed from the base of the PR and between 4b4c863 and 6728523.

📒 Files selected for processing (6)
  • ext/crates/once/src/multiindexed/mod.rs
  • ext/crates/sseq/src/bigraded.rs
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/sseq.rs
  • ext/src/chain_complex/mod.rs
  • web_ext/sseq_gui/src/sseq.rs

Comment thread ext/crates/sseq/src/sseq.rs
Comment thread web_ext/sseq_gui/src/sseq.rs
@JoeyBF
JoeyBF force-pushed the multi_indexed_migration branch from 6728523 to 7ffcd0a Compare March 17, 2026 22:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@ext/crates/sseq/src/bigraded.rs`:
- Around line 53-65: Add doc comments to the Index and IndexMut impls for
Bigraded<V> stating that index(&self, b: Bidegree) and index_mut(&mut self, b:
Bidegree) will panic if the bidegree is not present (they call
self.get(b).unwrap() / self.get_mut(b).unwrap()), and that callers must ensure
the bidegree is defined before indexing; reference the alternative get/get_mut
which return Option to make the difference explicit.

In `@ext/crates/sseq/src/sseq.rs`:
- Around line 140-147: Add clear doc comments to clarify panicking vs Option
semantics: update the doc for dimension(&self, b: Bidegree) to state it returns
the dimension for an existing bidegree and will panic if the bidegree is
undefined (so callers should ensure existence or use get_dimension), and update
the doc for get_dimension(&self, b: Bidegree) to state it returns Option<usize>
and should be used when the bidegree may be undefined (per the "undefined means
undefined" design contract). Reference the functions dimension and get_dimension
and mention the panic condition and preferred call sites.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 28395562-43e2-44d2-8ac6-365f61f6b6d7

📥 Commits

Reviewing files that changed from the base of the PR and between 6728523 and 7ffcd0a.

📒 Files selected for processing (5)
  • ext/crates/sseq/src/bigraded.rs
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/sseq.rs
  • ext/src/chain_complex/mod.rs
  • web_ext/sseq_gui/src/sseq.rs

Comment thread ext/crates/sseq/src/bigraded.rs
Comment thread ext/crates/sseq/src/sseq.rs
@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown

❌ Failed to create PR with unit tests: AGENT_CHAT: Failed to open pull request

@JoeyBF
JoeyBF force-pushed the multi_indexed_migration branch from 7ffcd0a to 9a8d56d Compare March 22, 2026 01:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
web_ext/sseq_gui/src/sseq.rs (1)

89-98: ⚠️ Potential issue | 🔴 Critical

Undo or redo is no longer clearing sparse state safely.

clear() still preserves inner, class_names, and stale, but those are now presence-based Bigradeds. Old bidegrees therefore survive an undo, and replaying set_dimension() at Lines 300-311 hits insert on the same keys again; if dimensions are not replayed, stale names and flags from the old history remain live. This needs a real reset for the sparse maps, or set_dimension() must reinitialize existing entries instead of inserting.

🧹 Minimal safe reset
     pub fn clear(&mut self) {
         for prod in self.products.values_mut() {
             if prod.user {
                 prod.permanent = false;
             }
             prod.differential = None;
         }

-        self.inner.clear();
+        self.inner = Sseq::new(self.p, Bidegree::zero());
+        self.class_names = Bigraded::new();
+        self.stale = Bigraded::new();
     }

Based on learnings: In ext/crates/sseq/src/sseq.rs, the design contract for Sseq is "undefined means undefined, do not assume anything" — a bidegree not present in data: MultiIndexed<2, BidegreeData> is simply not yet set; callers must not treat absence as zero-dimensional.

Also applies to: 300-311

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web_ext/sseq_gui/src/sseq.rs` around lines 89 - 98, The clear() method
currently leaves presence-based Bigraded sparse maps intact (self.inner,
self.class_names, self.stale), which preserves old bidegree keys across
undo/redo; update clear() to fully reset those sparse maps (e.g., call clear()
or reinitialize the MultiIndexed/Biggraded structures for self.inner,
self.class_names, and self.stale) so no old bidegrees remain, or alternately
change set_dimension() to reinitialize existing entries instead of calling
insert (use entry API or replace existing BidegreeData) — locate clear(), the
fields products, inner, class_names, stale, and the set_dimension()
implementation (the insert calls at the set_dimension() block) and make one of
these two consistent fixes.
♻️ Duplicate comments (1)
ext/crates/once/src/multiindexed/mod.rs (1)

285-291: ⚠️ Potential issue | 🟠 Major

is_empty() leaks partially initialized state when first inserted point has coords[K - 1] == i32::MIN.

With sentinels min_coords = i32::MAX and max_coords = i32::MIN, the check at line 290 becomes i32::MIN > i32::MIN = false when the first insert has that coordinate value, falsely reporting the array as non-empty without synchronizing with all dimension updates. Earlier dimensions remain uninitialized sentinels but are returned by min_coords() and max_coords() after trusting the false is_empty() check. Check all K dimensions to detect the sentinel pattern in any dimension:

Suggested fix
     pub fn is_empty(&self) -> bool {
-        // We check the last coordinate because it is the one that is written to last when we
-        // insert. Observing a consistent last coordinate means that all coordinates are consistent,
-        // and calling `min_coords` or `max_coords` will not return nonsense.
-        self.min_coords[K - 1].load(Ordering::Acquire)
-            > self.max_coords[K - 1].load(Ordering::Acquire)
+        (0..K).any(|i| {
+            self.min_coords[i].load(Ordering::Acquire)
+                > self.max_coords[i].load(Ordering::Acquire)
+        })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ext/crates/once/src/multiindexed/mod.rs` around lines 285 - 291, is_empty
currently only checks the last dimension and can misreport non-empty when a
newly inserted value equals i32::MIN in that last coordinate; change is_empty to
iterate all K dimensions and perform Acquire loads from min_coords[i] and
max_coords[i], returning true only if every dimension satisfies min > max (the
sentinel empty condition), otherwise return false as soon as any dimension shows
min <= max; update references to min_coords, max_coords, K, and the
Ordering::Acquire loads accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@web_ext/sseq_gui/src/sseq.rs`:
- Around line 89-98: The clear() method currently leaves presence-based Bigraded
sparse maps intact (self.inner, self.class_names, self.stale), which preserves
old bidegree keys across undo/redo; update clear() to fully reset those sparse
maps (e.g., call clear() or reinitialize the MultiIndexed/Biggraded structures
for self.inner, self.class_names, and self.stale) so no old bidegrees remain, or
alternately change set_dimension() to reinitialize existing entries instead of
calling insert (use entry API or replace existing BidegreeData) — locate
clear(), the fields products, inner, class_names, stale, and the set_dimension()
implementation (the insert calls at the set_dimension() block) and make one of
these two consistent fixes.

---

Duplicate comments:
In `@ext/crates/once/src/multiindexed/mod.rs`:
- Around line 285-291: is_empty currently only checks the last dimension and can
misreport non-empty when a newly inserted value equals i32::MIN in that last
coordinate; change is_empty to iterate all K dimensions and perform Acquire
loads from min_coords[i] and max_coords[i], returning true only if every
dimension satisfies min > max (the sentinel empty condition), otherwise return
false as soon as any dimension shows min <= max; update references to
min_coords, max_coords, K, and the Ordering::Acquire loads accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ec00182b-ddbb-4903-bc7b-b358f8952968

📥 Commits

Reviewing files that changed from the base of the PR and between 6728523 and 9a8d56d.

📒 Files selected for processing (7)
  • ext/crates/once/src/multiindexed/iter.rs
  • ext/crates/once/src/multiindexed/mod.rs
  • ext/crates/sseq/src/bigraded.rs
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/sseq.rs
  • ext/src/chain_complex/mod.rs
  • web_ext/sseq_gui/src/sseq.rs

JoeyBF and others added 9 commits March 25, 2026 12:21
Replace .get_mut(b).unwrap() and .get(b).unwrap() calls on Bigraded
fields (stale, class_names) with index operator syntax. The Index and
IndexMut impls already provide a panic message with the bidegree on
missing entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@JoeyBF
JoeyBF force-pushed the multi_indexed_migration branch from 9a8d56d to 6a27390 Compare March 25, 2026 17:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
web_ext/sseq_gui/src/sseq.rs (1)

53-69: 🛠️ Refactor suggestion | 🟠 Major

Make inner private before the sparse side tables can drift out of sync.

stale and class_names now only get entries through SseqWrapper::set_dimension. Keeping inner publicly mutable lets outside code insert bidegrees through inner.set_dimension(...) without creating those companion entries, and the next refresh, send_class_data, or set_class_name can panic on self.stale[b] / self.class_names[b].

🔒 Minimal API tightening
 pub struct SseqWrapper<P: SseqProfile = Adams> {
     pub p: ValidPrime,
     name: SseqChoice,
-    pub inner: Sseq<P>,
+    inner: Sseq<P>,
impl<P: SseqProfile> SseqWrapper<P> {
    pub fn inner(&self) -> &Sseq<P> {
        &self.inner
    }
}

Based on learnings: in ext/crates/sseq/src/sseq.rs, missing bidegrees are undefined, not zero-dimensional.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web_ext/sseq_gui/src/sseq.rs` around lines 53 - 69, SseqWrapper exposes its
inner Sseq via the pub field `inner`, letting external code call
`inner.set_dimension(...)` and create bidegrees without updating
`stale`/`class_names`, causing panics; make the `inner` field private (remove
`pub` on `inner`) and add a public accessor `fn inner(&self) -> &Sseq<P>` so
callers can read but not mutate the inner Sseq; update any callsites that relied
on mutating `inner` to go through SseqWrapper methods (e.g. `set_dimension`) so
`stale` and `class_names` are kept in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@web_ext/sseq_gui/src/sseq.rs`:
- Around line 53-69: SseqWrapper exposes its inner Sseq via the pub field
`inner`, letting external code call `inner.set_dimension(...)` and create
bidegrees without updating `stale`/`class_names`, causing panics; make the
`inner` field private (remove `pub` on `inner`) and add a public accessor `fn
inner(&self) -> &Sseq<P>` so callers can read but not mutate the inner Sseq;
update any callsites that relied on mutating `inner` to go through SseqWrapper
methods (e.g. `set_dimension`) so `stale` and `class_names` are kept in sync.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 829d9a61-2db7-482c-8475-3f7d22979055

📥 Commits

Reviewing files that changed from the base of the PR and between 9a8d56d and 6a27390.

📒 Files selected for processing (6)
  • ext/crates/sseq/src/bigraded.rs
  • ext/crates/sseq/src/lib.rs
  • ext/crates/sseq/src/sseq.rs
  • ext/src/chain_complex/mod.rs
  • web_ext/sseq_gui/src/managers.rs
  • web_ext/sseq_gui/src/sseq.rs

@JoeyBF
JoeyBF merged commit d447c36 into SpectralSequences:master Mar 26, 2026
24 checks passed
@JoeyBF
JoeyBF deleted the multi_indexed_migration branch March 26, 2026 15:41
github-actions Bot added a commit to JoeyBF/sseq that referenced this pull request Mar 26, 2026
* Change Sseq internals

* Remove `DenseBigradedModule`

* Add `Sseq::iter_bidegrees`

* More migration

* Introduce `Bigraded` thin wrapper

* Fix Sseq::multiply

* Add error messages to `Index`

* Remove useless `min` parameter

* Use Bigraded indexing instead of get/get_mut().unwrap()

Replace .get_mut(b).unwrap() and .get(b).unwrap() calls on Bigraded
fields (stale, class_names) with index operator syntax. The Index and
IndexMut impls already provide a panic message with the bidegree on
missing entries.
github-actions Bot added a commit that referenced this pull request Mar 26, 2026
* Change Sseq internals

* Remove `DenseBigradedModule`

* Add `Sseq::iter_bidegrees`

* More migration

* Introduce `Bigraded` thin wrapper

* Fix Sseq::multiply

* Add error messages to `Index`

* Remove useless `min` parameter

* Use Bigraded indexing instead of get/get_mut().unwrap()

Replace .get_mut(b).unwrap() and .get(b).unwrap() calls on Bigraded
fields (stale, class_names) with index operator syntax. The Index and
IndexMut impls already provide a panic message with the bidegree on
missing entries.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant