| """harness/windows.py β the DATE WINDOW vocabulary (CG-7, owner item 2, 2026-07-26). |
| |
| A filter condition on a measure reads: |
| |
| Where [Sales] [in the last 90 days] [>] [5,000] |
| |
| The middle bracket is this module. It turns a window SPEC β a small JSON object a saved view can |
| persist β into a concrete `(date_from, date_to)` pair of ISO dates. |
| |
| WHY IT IS ITS OWN MODULE, AND WHY IT TAKES `today` AS AN ARGUMENT |
| ----------------------------------------------------------------------------------------------- |
| Two engines must agree on what "this quarter" means: this one (which compiles the SQL) and |
| `customer-grid/windows.ts` (which renders the label the user reads and the bounds the client |
| engine would use). If they disagree by one day, the grid shows a number the label denies, and |
| nothing errors. `aios-web/verify_windows.py` holds them in lock-step over a fixed set of probe |
| dates, exactly as verify_filter_engine.py does for the filter tree. |
| |
| `today` is a PARAMETER, never `date.today()` read inside. Three reasons, all learned: |
| - a gate cannot compare two engines on "now" β the two runs are milliseconds apart and land on |
| different sides of midnight roughly once every few thousand runs, which is the worst kind of |
| flake because it looks like a real divergence |
| - a window resolved during a request must not shift between the count query and the row query |
| - the tenant's day boundary is the tenant's, not the server's |
| |
| DESIGN NOTES THAT ARE EASY TO GET WRONG |
| ----------------------------------------------------------------------------------------------- |
| - Bounds are INCLUSIVE at both ends and are DATES, not timestamps. `store_query` casts both |
| sides to TIMESTAMP and appends 23:59:59 to the upper bound, so a bare date is correct there; |
| the client compares the 10-char ISO prefix, so a bare date is correct there too. |
| - "Last N days" INCLUDES today. Airtable's "the past week" means the last 7 days up to and |
| including now, not the 7 days before yesterday. Off-by-one here silently drops today's |
| orders from every "recent" filter β invisible until someone asks why a sale they just |
| entered is missing. |
| - Week starts MONDAY (ISO 8601). Stated rather than defaulted: Python's weekday() is |
| Monday=0 and JavaScript's getDay() is Sunday=0, so the two engines disagree unless one of |
| them is explicitly corrected. That correction is the single most likely divergence in this |
| file, and the gate probes a Sunday and a Monday for exactly that reason. |
| - A `custom` window with only one bound is legal and means open-ended on the other side. |
| - An UNRESOLVABLE window returns None rather than a default. A window that quietly becomes |
| "all time" would widen a filter while still reporting an authoritative count. |
| """ |
| import datetime as _dt |
|
|
| |
| |
| |
| WINDOW_KINDS = ( |
| "all_time", |
| "today", |
| "yesterday", |
| "this_week", |
| "last_week", |
| "this_month", |
| "last_month", |
| "this_quarter", |
| "last_quarter", |
| "this_year", |
| "last_year", |
| "ytd", |
| "ytd_last_year", |
| "ltm", |
| "past_week", |
| "past_month", |
| "past_year", |
| "last_n_days", |
| "next_n_days", |
| "custom", |
| ) |
|
|
| |
| N_KINDS = frozenset({"last_n_days", "next_n_days"}) |
|
|
| |
| |
| WINDOW_LABELS = { |
| "all_time": "all time", |
| "today": "today", |
| "yesterday": "yesterday", |
| "this_week": "this week", |
| "last_week": "last week", |
| "this_month": "this month", |
| "last_month": "last month", |
| "this_quarter": "this quarter", |
| "last_quarter": "last quarter", |
| "this_year": "this year", |
| "last_year": "last year", |
| "ytd": "year to date", |
| |
| |
| |
| |
| "ytd_last_year": "last year to date", |
| "ltm": "the last 12 months", |
| "past_week": "the past week", |
| "past_month": "the past month", |
| "past_year": "the past year", |
| "last_n_days": "the last {n} days", |
| "next_n_days": "the next {n} days", |
| "custom": "a custom range", |
| } |
|
|
| MAX_N = 3650 |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| ANCHOR_MODES = ( |
| "today", |
| "yesterday", |
| "one_week_ago", |
| "one_month_ago", |
| "n_days_ago", |
| "exact", |
| ) |
|
|
| |
| |
| |
| |
| |
| ANCHOR_VALUE_FREE = frozenset({"today", "yesterday", "one_week_ago", "one_month_ago"}) |
|
|
| ANCHOR_LABELS = { |
| "today": "today", |
| "yesterday": "yesterday", |
| "one_week_ago": "one week ago", |
| "one_month_ago": "one month ago", |
| "n_days_ago": "{n} days ago", |
| "exact": "an exact date", |
| } |
|
|
|
|
| def _iso(d): |
| return d.isoformat() |
|
|
|
|
| def _month_start(d): |
| return d.replace(day=1) |
|
|
|
|
| def _month_end(d): |
| return _next_month(d.replace(day=1)) - _dt.timedelta(days=1) |
|
|
|
|
| def _next_month(d): |
| return (d.replace(day=28) + _dt.timedelta(days=4)).replace(day=1) |
|
|
|
|
| def _quarter_start(d): |
| return _dt.date(d.year, 3 * ((d.month - 1) // 3) + 1, 1) |
|
|
|
|
| def _days_in_month(y, m): |
| return (_dt.date(y + (m == 12), 1 if m == 12 else m + 1, 1) - _dt.timedelta(days=1)).day |
|
|
|
|
| def _shift_months(d, n): |
| """`d` moved `n` months, CLAMPING the day to the target month's length. |
| |
| Jan 31 back one month is Dec 31, but Mar 31 back one month is Feb 28 (or 29) β there is no |
| Feb 31 to land on. Both engines must clamp identically or "the past month" differs by up to |
| three days for a third of the calendar; the gate probes a 31st and a leap day for exactly it. |
| """ |
| total = (d.year * 12 + (d.month - 1)) + n |
| y, m = divmod(total, 12) |
| m += 1 |
| return _dt.date(y, m, min(d.day, _days_in_month(y, m))) |
|
|
|
|
| def _parse_date(v): |
| """Accept 'YYYY-MM-DD' (and tolerate a longer ISO timestamp by taking its date part).""" |
| if isinstance(v, _dt.date): |
| return v |
| s = str(v or "").strip()[:10] |
| if not s: |
| return None |
| try: |
| return _dt.date.fromisoformat(s) |
| except ValueError: |
| return None |
|
|
|
|
| def normalize(spec): |
| """Coerce an untrusted window spec to `{kind, n?, from?, to?}` or None. |
| |
| Fail-closed on the KIND (an unknown kind is not a window), tolerant on the rest β the same |
| split `clean_filter_tree` uses, so one malformed window cannot cost a user their saved view. |
| """ |
| if not isinstance(spec, dict): |
| return None |
| kind = spec.get("kind") |
| if kind not in WINDOW_KINDS: |
| return None |
| out = {"kind": kind} |
| if kind in N_KINDS: |
| try: |
| n = int(spec.get("n")) |
| except (TypeError, ValueError): |
| return None |
| if n < 1 or n > MAX_N: |
| return None |
| out["n"] = n |
| if kind == "custom": |
| f, t = _parse_date(spec.get("from")), _parse_date(spec.get("to")) |
| if f is None and t is None: |
| return None |
| if f is not None and t is not None and f > t: |
| f, t = t, f |
| if f is not None: |
| out["from"] = _iso(f) |
| if t is not None: |
| out["to"] = _iso(t) |
| return out |
|
|
|
|
| def resolve(spec, today): |
| """Window spec + the tenant's today -> `(date_from, date_to)`, both inclusive ISO dates. |
| |
| Either side may be None, meaning open-ended. Returns None when the spec is not a window at |
| all β callers MUST treat that as "this condition cannot be evaluated" and refuse, never as |
| "no window", which would silently widen the result to all time. |
| """ |
| spec = normalize(spec) |
| if spec is None: |
| return None |
| kind = spec["kind"] |
| d = _parse_date(today) |
| if d is None: |
| raise ValueError("resolve() needs an explicit `today` β see this module's docstring") |
|
|
| if kind == "all_time": |
| return (None, None) |
| if kind == "today": |
| return (_iso(d), _iso(d)) |
| if kind == "yesterday": |
| y = d - _dt.timedelta(days=1) |
| return (_iso(y), _iso(y)) |
|
|
| |
| |
| if kind == "this_week": |
| start = d - _dt.timedelta(days=d.weekday()) |
| return (_iso(start), _iso(start + _dt.timedelta(days=6))) |
| if kind == "last_week": |
| start = d - _dt.timedelta(days=d.weekday() + 7) |
| return (_iso(start), _iso(start + _dt.timedelta(days=6))) |
|
|
| if kind == "this_month": |
| return (_iso(_month_start(d)), _iso(_month_end(d))) |
| if kind == "last_month": |
| prev = _month_start(d) - _dt.timedelta(days=1) |
| return (_iso(_month_start(prev)), _iso(prev)) |
|
|
| if kind == "this_quarter": |
| qs = _quarter_start(d) |
| qe = _month_end(_dt.date(qs.year, qs.month + 2, 1)) |
| return (_iso(qs), _iso(qe)) |
| if kind == "last_quarter": |
| prev_end = _quarter_start(d) - _dt.timedelta(days=1) |
| qs = _quarter_start(prev_end) |
| return (_iso(qs), _iso(prev_end)) |
|
|
| if kind == "this_year": |
| return (_iso(_dt.date(d.year, 1, 1)), _iso(_dt.date(d.year, 12, 31))) |
| if kind == "last_year": |
| return (_iso(_dt.date(d.year - 1, 1, 1)), _iso(_dt.date(d.year - 1, 12, 31))) |
| if kind == "ytd": |
| |
| |
| |
| return (_iso(_dt.date(d.year, 1, 1)), _iso(d)) |
| if kind == "ytd_last_year": |
| |
| |
| |
| |
| |
| |
| return (_iso(_dt.date(d.year - 1, 1, 1)), _iso(_shift_months(d, -12))) |
| if kind == "ltm": |
| |
| return (_iso(d - _dt.timedelta(days=364)), _iso(d)) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| if kind == "past_week": |
| return (_iso(d - _dt.timedelta(days=6)), _iso(d)) |
| if kind == "past_month": |
| return (_iso(_shift_months(d, -1) + _dt.timedelta(days=1)), _iso(d)) |
| if kind == "past_year": |
| return (_iso(_shift_months(d, -12) + _dt.timedelta(days=1)), _iso(d)) |
|
|
| if kind == "last_n_days": |
| |
| |
| return (_iso(d - _dt.timedelta(days=spec["n"] - 1)), _iso(d)) |
| if kind == "next_n_days": |
| return (_iso(d), _iso(d + _dt.timedelta(days=spec["n"] - 1))) |
|
|
| if kind == "custom": |
| return (spec.get("from"), spec.get("to")) |
| raise AssertionError(f"unhandled window kind {kind!r}") |
|
|
|
|
| def label(spec): |
| """How a window reads in the condition sentence ('in the last 90 days').""" |
| spec = normalize(spec) |
| if spec is None: |
| return "an invalid range" |
| return WINDOW_LABELS[spec["kind"]].format(n=spec.get("n")) |
|
|
|
|
| def resolve_anchor(mode, value, today): |
| """A date condition's right-hand side -> ONE inclusive ISO date, or None. |
| |
| `mode` is an entry of ANCHOR_MODES; None/'' means `exact`, which is what every view saved |
| before anchors existed carries (op + an ISO date in `value`). `value` supplies the number for |
| `n_days_ago` and the date for `exact`, and is ignored by the four value-free modes. |
| |
| Returns None when the anchor cannot be resolved β an unknown mode, a non-numeric N, a value |
| that is not a date. The caller must then treat the CONDITION as unanswerable and match |
| nothing. It must NOT fall through to "no condition": that widens the result while the count |
| beside it still looks authoritative, which is the whole reason this returns None rather than |
| a best guess (same contract as `resolve()` above). |
| |
| `n_days_ago` accepts n = 0 where a WINDOW requires n >= 1. A zero-day window is empty and |
| could only be a mistake; "0 days ago" is today, which is a date a person can mean. |
| """ |
| m = mode or "exact" |
| if m not in ANCHOR_MODES: |
| return None |
| d = _parse_date(today) |
| if d is None: |
| raise ValueError("resolve_anchor() needs an explicit `today` β see this module's " |
| "docstring on why the clock is never read here") |
| if m == "today": |
| return _iso(d) |
| if m == "yesterday": |
| return _iso(d - _dt.timedelta(days=1)) |
| if m == "one_week_ago": |
| |
| |
| return _iso(d - _dt.timedelta(days=7)) |
| if m == "one_month_ago": |
| return _iso(_shift_months(d, -1)) |
| if m == "n_days_ago": |
| s = str("" if value is None else value).strip() |
| |
| |
| |
| if not s or not all("0" <= ch <= "9" for ch in s): |
| return None |
| n = int(s) |
| |
| |
| |
| if n > MAX_N: |
| return None |
| return _iso(d - _dt.timedelta(days=n)) |
| parsed = _parse_date(value) |
| return None if parsed is None else _iso(parsed) |
|
|
|
|
| def anchor_label(mode, value): |
| """How an anchor reads in the condition sentence ('one month ago', '30 days ago').""" |
| m = mode or "exact" |
| if m not in ANCHOR_MODES: |
| return "an invalid date" |
| if m == "n_days_ago": |
| return ANCHOR_LABELS[m].format(n=str("" if value is None else value).strip() or "N") |
| if m == "exact": |
| return str("" if value is None else value).strip() or ANCHOR_LABELS[m] |
| return ANCHOR_LABELS[m] |
|
|