Skip to content

Release 0.3.0: stop reading the system timezone - #6

Merged
neosergio merged 1 commit into
mainfrom
feat/v0.3.0
Jul 13, 2026
Merged

Release 0.3.0: stop reading the system timezone#6
neosergio merged 1 commit into
mainfrom
feat/v0.3.0

Conversation

@neosergio

Copy link
Copy Markdown
Owner

The default clock was datetime.now(), naive local time, so the date part of a reference depended on the machine that produced it. The same identifier at the same instant became 20260713... on a Lima server and 20260714... on a Tokyo one. Determinism is what this library sells, and it did not survive a fleet.

generate_reference() takes tz, defaulting to UTC. generated_at=None reads datetime.now(tz); an aware generated_at is converted into tz; a naive one is taken at face value, as the wall clock the caller chose. Nothing in the module can reach the environment any more, which is the actual fix -- not "use UTC" but "never ask the machine what time it thinks it is".

This moves references, and not at the margin: a reference changes whenever the local date differs from the UTC date, which is 21% of the day at UTC-5 and 38% at UTC+9. Stored references are strings in a column and are untouched; what changes is what new calls return. A caller who recomputes rather than stores can pin the old behaviour with the zone their servers ran in. The README and changelog say so plainly, because a caller who finds this out from a lookup miss has already lost.

expected_rejected_inserts() lands with it. A unique constraint rejects inserts, not pairs, and the two part company once a bucket fills: two thousand references over three digits is 1999 pairs but 1135 rejections. The pair count also has no ceiling, while rejections cannot exceed the reference count, because an insert can only be rejected once. Callers sizing a retry budget want the latter. Verified against simulation across four orders of magnitude.

suffix_length_for() inverts max_references(), which answered the sizing question backwards and left the README instructing callers to write a loop over lengths. Verified to return the smallest length meeting the target, and to round-trip against max_references().

expected_collisions() becomes expected_colliding_pairs(). The old name implied a count of collisions to handle, and until 0.2.1 the docs said so; it counts pairs. The old name warns and goes away in 1.0.0. pytest treats warnings as errors, so it found all 22 call sites that needed migrating.

The default clock was datetime.now(), naive local time, so the date part
of a reference depended on the machine that produced it. The same
identifier at the same instant became 20260713... on a Lima server and
20260714... on a Tokyo one. Determinism is what this library sells, and
it did not survive a fleet.

generate_reference() takes tz, defaulting to UTC. generated_at=None reads
datetime.now(tz); an aware generated_at is converted into tz; a naive one
is taken at face value, as the wall clock the caller chose. Nothing in the
module can reach the environment any more, which is the actual fix -- not
"use UTC" but "never ask the machine what time it thinks it is".

This moves references, and not at the margin: a reference changes whenever
the local date differs from the UTC date, which is 21% of the day at UTC-5
and 38% at UTC+9. Stored references are strings in a column and are
untouched; what changes is what new calls return. A caller who recomputes
rather than stores can pin the old behaviour with the zone their servers
ran in. The README and changelog say so plainly, because a caller who
finds this out from a lookup miss has already lost.

expected_rejected_inserts() lands with it. A unique constraint rejects
inserts, not pairs, and the two part company once a bucket fills: two
thousand references over three digits is 1999 pairs but 1135 rejections.
The pair count also has no ceiling, while rejections cannot exceed the
reference count, because an insert can only be rejected once. Callers
sizing a retry budget want the latter. Verified against simulation across
four orders of magnitude.

suffix_length_for() inverts max_references(), which answered the sizing
question backwards and left the README instructing callers to write a
loop over lengths. Verified to return the smallest length meeting the
target, and to round-trip against max_references().

expected_collisions() becomes expected_colliding_pairs(). The old name
implied a count of collisions to handle, and until 0.2.1 the docs said so;
it counts pairs. The old name warns and goes away in 1.0.0. pytest treats
warnings as errors, so it found all 22 call sites that needed migrating.
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 736ad48b-ee6d-46d5-a347-2235f28c6698

📥 Commits

Reviewing files that changed from the base of the PR and between 523241b and cc86145.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • README.md
  • ROADMAP.md
  • pyproject.toml
  • src/compactref/__init__.py
  • src/compactref/core.py
  • tests/test_core.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v0.3.0

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.

@neosergio
neosergio merged commit 0192033 into main Jul 13, 2026
8 checks passed
@neosergio
neosergio deleted the feat/v0.3.0 branch July 13, 2026 17:42
@neosergio
neosergio restored the feat/v0.3.0 branch July 13, 2026 17:42
@neosergio
neosergio deleted the feat/v0.3.0 branch July 13, 2026 17:42
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