Skip to content

Canonicalize a coordinate only when it keeps its values - #898

Merged
d-chambers merged 2 commits into
devfrom
coord-manager-preserve-values
Aug 13, 2026
Merged

Canonicalize a coordinate only when it keeps its values#898
d-chambers merged 2 commits into
devfrom
coord-manager-preserve-values

Conversation

@d-chambers

Copy link
Copy Markdown
Contributor

Description

Closes #896.

Passing an already-constructed BaseCoord to get_coord_manager did not preserve it. Anything that was not a CoordRange was dumped back to a dict and re-inferred through get_coord, which snaps near-evenly-sampled values onto a regular range. Because that evenness test is tolerant — all_diffs_close_enough uses rtol=0.001 — the result was not merely a different coordinate class; the sample values themselves were silently rewritten:

vals = np.array([0.0, 1.0, 2.0005, 3.0015, 4.002])
coord = CoordMonotonicArray(values=vals)
cm = dc.get_coord_manager({"distance": coord}, dims=("distance",))
cm.coord_map["distance"].values
# array([0.    , 1.0005, 2.001 , 3.0015, 4.002 ])   <- values 1 and 2 invented

The same happened through the public Patch constructor. Afterwards the coordinate reported itself as an evenly sampled CoordRange, so nothing downstream could tell the spacing had been made up.

The re-parse itself is deliberate and worth keeping: array coords can be left non-canonical by slicing, so an evenly spaced subset should collapse back to a CoordRange. The problem is only that the collapse was allowed to move values. This keeps the canonicalization and restricts it to the case where it is a pure change of representation — if the resulting range does not reproduce the original values exactly, the coordinate that was passed in is kept.

A CoordPartial is explicitly excluded: its values are all NaN placeholders, so it has nothing to lose and canonicalizing it is the entire point. An existing test (test_full_partial_canonicalizes_to_range) caught that when I first wrote the guard too broadly.

This is the mechanism behind the caveat noted in #895, where a Febus reader could build an exact acquisition-window coordinate with get_exact_coord and still have the coord manager convert it back to a range. That comment is now stale, so it is corrected here, and a Febus test pins the end-to-end behavior: spans that drift steadily — the shape most vulnerable to being snapped away — now survive the read.

Nothing about this is Febus-specific. It applies to any coordinate carrying small, physically real irregularity: GPS-derived positions, per-sample timing jitter, measured channel spacing.

Notes

  • Behavior only changes where the old path was lossy. An exactly evenly spaced array coord still canonicalizes to a CoordRange, raw-array inference through get_coord(data=...) is untouched, and CoordRange inputs keep their existing short-circuit.
  • The comparison is skipped unless the result is a CoordRange built from a non-range, non-partial coord we were handed, so the common paths do no extra work.
  • Whether get_coord(data=...) should keep snapping this aggressively when inferring from a raw array is left alone. That path is documented as tolerant inference and is defensible; silently discarding a caller's explicit, exact coordinate was not.

Changelog

  • fixed: Building a coordinate manager or patch from an explicitly constructed coordinate no longer rewrites its values, which previously happened when the sample spacing was within a tenth of a percent of being even.

Checklist

I have:

  • filled in the Changelog section above (see docs/contributing/general_guidelines.qmd).

I have (if applicable):

  • referenced the GitHub issue this PR closes.
  • documented the new feature with docstrings and/or appropriate doc page.
  • included tests. See testing guidelines.
  • added the "ready_for_review" tag once the PR is ready to be reviewed.

get_coord_manager re-inferred every non-CoordRange coord through
get_coord to canonicalize it, but that evenness test is tolerant
(rtol 1e-3), so a coord whose spacing varied by less than a tenth of a
percent was replaced by an idealized ramp. The values were rewritten
silently and the result claimed to be evenly sampled, so nothing
downstream could tell the spacing had been invented.

The collapse is still worth doing when it is a pure change of
representation, so it now happens only when the resulting range
reproduces the original values exactly. A CoordPartial is excluded: its
values are NaN placeholders, so canonicalizing it is the whole point.

This is what kept the Febus acquisition-window coord from being exact
even when built with get_exact_coord, so that caveat comes off the
comment and a test pins the drifting-span case end to end.
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@d-chambers, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 34 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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

How do review 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 refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 40f478d1-9df7-41c0-9e87-b81115e0a70f

📥 Commits

Reviewing files that changed from the base of the PR and between e7fe7c6 and 454016d.

📒 Files selected for processing (4)
  • dascore/core/coordmanager.py
  • dascore/io/febus/g1utils.py
  • tests/test_core/test_coordmanager.py
  • tests/test_io/test_febus/test_febusbsl.py

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.

@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (e7fe7c6) to head (454016d).

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #898   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          182       182           
  Lines        21961     21971   +10     
=========================================
+ Hits         21961     21971   +10     
Flag Coverage Δ
network 45.10% <50.00%> (+<0.01%) ⬆️
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

A CoordRange never reaches the helper: the caller returns it before
consulting it. The shape comparison could not fail either, since
canonicalization re-labels a coordinate rather than resampling it, so it
becomes an assert of that invariant instead of a dead branch.
@d-chambers
d-chambers merged commit bf3cfcb into dev Aug 13, 2026
30 checks passed
@d-chambers
d-chambers deleted the coord-manager-preserve-values branch August 13, 2026 18:05
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