Skip to content

fix(flags): clamp the day after every step in relative month lookbacks - #356

Merged
marandaneto merged 1 commit into
PostHog:mainfrom
luantaraschi:fix/relative-date-month-clamp
Nov 11, 2026
Merged

marandaneto merged 1 commit into
PostHog:mainfrom
luantaraschi:fix/relative-date-month-clamp

Conversation

@luantaraschi

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

relative_date_parse_for_feature_flag_matching uses prev_month(n) and prev_year(n), which jump in one go and clamp the day once at the end. The local evaluator spec subtracts one unit at a time and clamps after every step, so 2m on March 31 should be January 28 (the spec's own scenario) rather than January 31, and 4y on February 29, 2024 should be February 28, 2020. 1m and 1y already match the spec. The same change was merged for posthog-python (PostHog/posthog-python#1212), posthog-js (PostHog/posthog-js#5626) and posthog-go (PostHog/posthog-go#426), and is open for posthog-php (PostHog/posthog-php#315).

For a flag with an is_date_after 2m condition evaluated locally on March 31, a person whose date was January 29 to 31 matched.

The parser still works in UTC where the spec asks for the team's timezone. I left that alone.

💚 How did you test it?

  • A new spec with 12 cases in feature_flag_spec.rb. Four of them fail on main (2m and 13m from March 31, 12m from January 29, 4y from February 29).
  • I compared the parser with a month-by-month loop for every day from 2019 through 2028, with lookbacks of 1 to 25 months and 1 to 5 years: 109,590 cases. main differs in 5,111 of them, all with a lookback of two or more units. With this change there are no differences.
  • I evaluated a flag locally through PostHog::Client, with the clock frozen at 2025-03-31 and an is_date_after 2m condition. A last_purchase of January 29 no longer matches, February 1 still does and January 27 still doesn't.
  • In Docker: bundle exec rspec on Ruby 3.2, 3.3 and 3.4 (2502 examples, 0 failures), bundle exec rubocop and bundle exec rake public_api:check.

📝 Checklist

  • All commits are signed (see Commit signing)
  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Added a changeset for posthog-ruby (written by hand, I didn't run pnpm changeset)

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Luan Taraschi directed the work and reviewed the diff. Claude Code (Claude Opus 5.5) wrote the change and ran the checks. The loop steps one month at a time only while the day is above 28 and then does the rest with a single prev_month, so it runs at most 11 times whatever the lookback. Years take one step and then one jump, since only February 29 can clamp.

prev_month(n) and prev_year(n) jump in one go and clamp the day once, so 2m on March 31 landed on January 31 and 4y on February 29, 2024 on February 29, 2020. Step back one unit at a time while the day can still clamp, as the SDK spec asks.
@luantaraschi
luantaraschi requested a review from a team as a code owner November 10, 2026 21:15

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code looks good; no qualifying findings. Verdict: correct.

@marandaneto
marandaneto merged commit 1e29b54 into PostHog:main Nov 11, 2026
29 checks passed
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.

2 participants