Skip to content

feat(datasource-toolkit): make every date interval half-open - #1892

Open
Tonours wants to merge 2 commits into
mainfrom
fix/date-interval-inclusive-start
Open

Tonours wants to merge 2 commits into
mainfrom
fix/date-interval-inclusive-start

Conversation

@Tonours

@Tonours Tonours commented Sep 10, 2026

Copy link
Copy Markdown
Member

What

One rule, applied everywhere it had been written down: a date interval is half-open, [start, end).

  • datasource-toolkitinterval() now emits GreaterThanOrEqual on a Date column, as it already did on Dateonly. Covers Today, Yesterday, PreviousWeek/Month/Quarter/Year, PreviousXDays and the …ToDate family.
  • datasource-toolkitFilterFactory.getPreviousPeriodFilter, the comparison window of the growth charts, gets the same inclusive start and a proper exclusive end (it used endOf, which dropped the period's final millisecond).
  • workflow-executor — the deterministic condition evaluator deliberately mirrored the old asymmetry; it now mirrors the new rule.

Why

On a Date column both bounds were strict, so a record stored at exactly local midnight satisfied none of them: not Today, not Yesterday, not PreviousMonth. It was unreachable by every date filter the product offers. Rows that no question can return is the defect here — the fix stands on its own, with or without a second agent generation in the picture.

The blast radius is larger than "one instant per day" suggests. Columns fed by an import or by a business date are routinely truncated to midnight; for a project whose timezone matches the truncation zone, the unreachable set is not a row, it is a table. #1231 fixed this for Dateonly and left Date behind.

The v1/v2 observation that surfaced it — the same Today question returning the row on a v1 liana and not on a v2 agent — is a consequence of the defect, not the reason to fix it. v1 was right.

Why the other two files

Fixing only interval() would have moved the disagreement rather than ended it:

  • The growth charts would have compared a current period that includes its first instant against a previous period that excludes it. Same operator, two conventions, in one number.
  • A workflow Decision and a list filter would have answered "today" differently for the same record. deterministic-condition-evaluator.ts says in a comment that it replicates the toolkit's bound precisely so that they agree; the comment and the test that pinned it both move with the rule.

Scope and safety

The change is monotone. A row that satisfied an interval still satisfies it; rows are only added. Nothing empties, no screen breaks, no query shape is new — the Or that appears for a datasource without a native GreaterThanOrEqual is the pre-existing comparison.ts fallback, the same shape the search decorator already emits on every field type.

It is still a behaviour change: counts go up and a KPI can move. It should ship as a minor with a release note, not as a silent patch — hence feat: rather than fix:.

Not changed: Dateonly (already inclusive), the upper bound (inclusive on both ends would put a midnight record in two days and double-count it), and the operator set advertised to the frontend.

How to test

datasource-toolkit 489/489, workflow-executor 1783 passed / 7 skipped, agent chart routes 24/24, datasource-customizer green. The datasource-sequelize and datasource-mongoose integration suites need database containers; without them every failure is a connection error and there are zero assertion mismatches.

The invariant is pinned in two places rather than asserted through expected operator strings: time.test.ts evaluates an instant at local midnight through ConditionTree.match and checks it is in Today and in no other day; deterministic-condition-evaluator.test.ts checks the same tiling property for the evaluator.

Known limitation

The other SDKs (Python, PHP, Ruby) carry the same interval() and keep the strict bound until this is ported. Until then Node v2 agrees with v1 lianas and differs from its sibling SDKs on the boundary instant.

Definition of Done

General

  • Write an explicit title for the Pull Request, following Conventional Commits specification
  • Test manually the implemented changes
  • Validate the code quality (indentation, syntax, style, simplicity, readability)

Security

  • Consider the security impact of the changes made

@Tonours
Tonours force-pushed the fix/date-interval-inclusive-start branch from d08a614 to 1e7d0c9 Compare September 10, 2026 16:41
@qltysh

qltysh Bot commented Sep 10, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

This PR will not change total coverage.

Modified Files with Diff Coverage (2)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
...ow-executor/src/executors/deterministic-condition-evaluator.ts100.0%
Coverage rating: A Coverage rating: A
...ages/datasource-toolkit/src/interfaces/query/filter/factory.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@Tonours Tonours changed the title fix(datasource-toolkit): include the first instant of a date interval feat(datasource-toolkit): make every date interval half-open Sep 11, 2026
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