diff --git a/docs/reference/expression-coverage-scoped.md b/docs/reference/expression-coverage-scoped.md index 25753fdf..f0d97929 100644 --- a/docs/reference/expression-coverage-scoped.md +++ b/docs/reference/expression-coverage-scoped.md @@ -5,7 +5,7 @@ Scoped deviations — dialect, parameter, option, value-class; function-level coverage and matrices live in [`expression-coverage.md`](expression-coverage.md). -Declarations: 42 · Facts: 1560 · Registered operations: 324 · Implementation records: 972 +Declarations: 43 · Facts: 1462 · Registered operations: 326 · Implementation records: 978 Legend — scoped deviations: @@ -131,39 +131,32 @@ Legend — scoped deviations: | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| narwhals-pandas | unit | — | duration_multiplier | unsupported | gate | build | — | narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result | — | — | 2026-07-25 | — | — | -| narwhals-pandas | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | -| narwhals-polars | unit | — | duration_multiplier | unsupported | gate | build | — | narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result | — | — | 2026-07-25 | — | — | -| narwhals-polars | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | +| narwhals-pandas | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-pandas | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | ### `CEIL` × ibis (FKEY_MOUNTAINASH_SCALAR_DATETIME) | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| * | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| * | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | -| ibis-duckdb | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| ibis-duckdb | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | +| ibis-polars | unit | 1mo, 1q, 1y, month, quarter, year | — | unsupported | gate | build | — | ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | +| ibis-sqlite | unit | 1h, 1m, 1ms, 1q, 1s, 1us, hour, microsecond, millisecond, minute, quarter, second | — | unsupported | gate | build | — | ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | ### `FLOOR` × narwhals (FKEY_MOUNTAINASH_SCALAR_DATETIME) | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| narwhals-pandas | unit | 1w | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | -| narwhals-pandas | unit | week | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | -| narwhals-polars | unit | 1w | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | -| narwhals-polars | unit | week | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | +| narwhals-pandas | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-pandas | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | ### `FLOOR` × ibis (FKEY_MOUNTAINASH_SCALAR_DATETIME) | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| * | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| * | unit | 1q | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | -| * | unit | quarter | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | -| ibis-duckdb | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| ibis-duckdb | unit | 1q | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | -| ibis-duckdb | unit | quarter | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | +| ibis-sqlite | unit | 1h, 1m, 1ms, 1q, 1s, 1us, hour, microsecond, millisecond, minute, quarter, second | — | unsupported | gate | build | — | ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | ### `IS_DST` × ibis (FKEY_MOUNTAINASH_SCALAR_DATETIME) @@ -176,19 +169,17 @@ Legend — scoped deviations: | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| narwhals-pandas | unit | — | duration_multiplier | unsupported | gate | build | — | narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result | — | — | 2026-07-25 | — | — | -| narwhals-pandas | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | -| narwhals-polars | unit | — | duration_multiplier | unsupported | gate | build | — | narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result | — | — | 2026-07-25 | — | — | -| narwhals-polars | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | +| narwhals-pandas | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-pandas | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | ### `ROUND` × ibis (FKEY_MOUNTAINASH_SCALAR_DATETIME) | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| * | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| * | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | -| ibis-duckdb | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| ibis-duckdb | unit | 1d, 1h, 1m, 1mo, 1ms, 1q, 1s, 1us, 1w, 1y, day, hour, microsecond, millisecond, minute, month, quarter, second, week, year | — | unsupported | gate | build | — | ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value | — | — | 2026-07-24 | — | — | +| ibis-polars | unit | 1mo, 1q, 1y, month, quarter, year | — | unsupported | gate | build | — | ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | +| ibis-sqlite | unit | 1h, 1m, 1ms, 1q, 1s, 1us, hour, microsecond, millisecond, minute, quarter, second | — | unsupported | gate | build | — | ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | ### `TO_TIMEZONE` × ibis (FKEY_MOUNTAINASH_SCALAR_DATETIME) @@ -201,21 +192,16 @@ Legend — scoped deviations: | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| narwhals-pandas | unit | 1w | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | -| narwhals-pandas | unit | week | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | -| narwhals-polars | unit | 1w | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | -| narwhals-polars | unit | week | — | unsupported | gate | build | — | narwhals truncate rejects the week unit '1w' (and its friendly alias 'week') | — | — | 2026-07-24 | — | — | +| narwhals-pandas | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-pandas | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | 1w | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | +| narwhals-polars | unit | week | — | unsupported | gate | build | — | narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects | — | — | 2026-08-16 | — | — | ### `TRUNCATE` × ibis (FKEY_MOUNTAINASH_SCALAR_DATETIME) | Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| * | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| * | unit | 1q | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | -| * | unit | quarter | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | -| ibis-duckdb | unit | — | duration_multiplier | unsupported | gate | build | — | ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted | — | — | 2026-07-25 | — | — | -| ibis-duckdb | unit | 1q | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | -| ibis-duckdb | unit | quarter | — | unsupported | gate | build | — | ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter') | — | — | 2026-07-24 | — | — | +| ibis-sqlite | unit | 1h, 1m, 1ms, 1q, 1s, 1us, hour, microsecond, millisecond, minute, quarter, second | — | unsupported | gate | build | — | ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | ### `CONTAINS` × narwhals (FKEY_MOUNTAINASH_SCALAR_LIST) @@ -1021,6 +1007,22 @@ Legend — scoped deviations: | * | timezone | — | iana_timezone | unsupported | gate | build | — | local_timestamp returns the UTC wall clock, not the target-zone wall clock -- ibis has no timezone method and the naive re-cast discards the conversion (verified 2026-07-29, ibis 12.0.0/duckdb: 12:00 instead of 17:30 for Asia/Kolkata) | — | — | 2026-07-29 | — | — | | ibis-duckdb | timezone | — | iana_timezone | unsupported | gate | build | — | local_timestamp returns the UTC wall clock, not the target-zone wall clock -- ibis has no timezone method and the naive re-cast discards the conversion (verified 2026-07-29, ibis 12.0.0/duckdb: 12:00 instead of 17:30 for Asia/Kolkata) | — | — | 2026-07-29 | — | — | +### `ROUND_CALENDAR` × ibis (FKEY_SUBSTRAIT_SCALAR_DATETIME) + +| Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| ibis-polars | unit | MONTH | — | unsupported | gate | build | — | ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- CEIL/ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | +| ibis-polars | unit | YEAR | — | unsupported | gate | build | — | ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- CEIL/ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | +| ibis-sqlite | multiple | 3 | — | unsupported | gate | build | — | ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is unsupported for every unit; verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | +| ibis-sqlite | unit | HOUR, MICROSECOND, MILLISECOND, MINUTE, SECOND | — | unsupported | gate | build | — | ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | + +### `ROUND_TEMPORAL` × ibis (FKEY_SUBSTRAIT_SCALAR_DATETIME) + +| Dialect | Param | Option values | Value class | Level | Enforcement | Boundary | Condition | Message | Workaround | Upstream | Since | Native errors | Probe-exempt | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| ibis-sqlite | multiple | 2 | — | unsupported | gate | build | — | ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is unsupported for every unit; verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | +| ibis-sqlite | unit | HOUR, MICROSECOND, MILLISECOND, MINUTE, SECOND | — | unsupported | gate | build | — | ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0 | — | — | 2026-08-16 | — | — | + ### `STRPTIME_DATE` × narwhals (FKEY_SUBSTRAIT_SCALAR_DATETIME) #### Dialect-scoped whole-op diff --git a/docs/reference/expression-coverage.json b/docs/reference/expression-coverage.json index 3d7842fb..4d115178 100644 --- a/docs/reference/expression-coverage.json +++ b/docs/reference/expression-coverage.json @@ -1,68 +1,68 @@ { "stamp": { - "declarations": 42, - "facts": 1560, - "operations": 324, - "implementation_records": 972 + "declarations": 43, + "facts": 1462, + "operations": 326, + "implementation_records": 978 }, "stats": { "backends": { "polars": { "by_impl": { - "implemented": 321, + "implemented": 323, "implemented_via_handler": 3, "not_implemented": 0, "unknown": 0 }, "default_capable": 191, - "audited_clean": 81, + "audited_clean": 83, "constrained": 52, "audited_unknown": 0 }, "narwhals": { "by_impl": { - "implemented": 321, + "implemented": 323, "implemented_via_handler": 3, "not_implemented": 0, "unknown": 0 }, "default_capable": 97, - "audited_clean": 149, + "audited_clean": 151, "constrained": 78, "audited_unknown": 0 }, "ibis": { "by_impl": { - "implemented": 321, + "implemented": 323, "implemented_via_handler": 3, "not_implemented": 0, "unknown": 0 }, "default_capable": 138, "audited_clean": 111, - "constrained": 75, + "constrained": 77, "audited_unknown": 0 } }, "contradictions": 0, - "ops_total": 324, + "ops_total": 326, "facts_by_level": { "expr_capable": 149, "literal_only": 65, "polymorphic": 9, - "unsupported": 1337 + "unsupported": 1239 }, "facts_by_enforcement": { - "gate": 1553, + "gate": 1455, "router_metadata": 3, "materialize_residue": 4 }, "facts_by_backend": { "polars": 265, - "narwhals": 662, - "ibis": 633 + "narwhals": 586, + "ibis": 611 }, - "facts_total": 1560 + "facts_total": 1462 }, "families": [ { @@ -1719,109 +1719,113 @@ "contradiction": false, "selector_counts": { "params": 1, - "option_selectors": 20, - "value_classes": 1, + "option_selectors": 2, + "value_classes": 0, "dialects": 2 }, "constraints": [ { "dialect": "narwhals-pandas", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1d", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-pandas", "param": "unit", - "option_value": "1h", + "option_value": "week", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "narwhals-polars", "param": "unit", - "option_value": "1m", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "narwhals-polars", "param": "unit", - "option_value": "1mo", + "option_value": "week", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null - }, + } + ], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "ceil_dt", + "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": true, + "contradiction": false, + "selector_counts": { + "params": 1, + "option_selectors": 16, + "value_classes": 0, + "dialects": 2 + }, + "constraints": [ { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", - "option_value": "1ms", + "option_value": "1mo", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "1q", "value_class": null, @@ -1829,63 +1833,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "1y", "value_class": null, @@ -1893,95 +1849,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "month", "value_class": null, @@ -1989,15 +1865,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "quarter", "value_class": null, @@ -2005,47 +1881,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "year", "value_class": null, @@ -2053,47 +1897,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1h", "value_class": null, @@ -2101,15 +1913,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1m", "value_class": null, @@ -2117,31 +1929,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1ms", "value_class": null, @@ -2149,15 +1945,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1q", "value_class": null, @@ -2165,15 +1961,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1s", "value_class": null, @@ -2181,15 +1977,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1us", "value_class": null, @@ -2197,63 +1993,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "hour", "value_class": null, @@ -2261,15 +2009,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "microsecond", "value_class": null, @@ -2277,15 +2025,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "millisecond", "value_class": null, @@ -2293,15 +2041,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "minute", "value_class": null, @@ -2309,31 +2057,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "quarter", "value_class": null, @@ -2341,15 +2073,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "second", "value_class": null, @@ -2357,42 +2089,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } @@ -2400,695 +2100,68 @@ "residue": [], "routed": [], "refinements": [] + } + } + }, + { + "op": { + "family": "FKEY_MOUNTAINASH_SCALAR_DATETIME", + "op": "DATE" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "date", + "impl_protocol": "MountainAshPolarsScalarDatetimeExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "date", + "impl_protocol": "MountainAshNarwhalsScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] }, "ibis": { "impl": "implemented", - "impl_method": "ceil_dt", + "impl_method": "date", "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, - "constrained": true, + "constrained": false, "contradiction": false, "selector_counts": { - "params": 1, - "option_selectors": 20, - "value_classes": 1, - "dialects": 1 + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 }, - "constraints": [ - { - "dialect": null, - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - } - ], + "constraints": [], "residue": [], "routed": [], "refinements": [] @@ -3098,12 +2171,12 @@ { "op": { "family": "FKEY_MOUNTAINASH_SCALAR_DATETIME", - "op": "DATE" + "op": "DAYS_IN_MONTH" }, "cells": { "polars": { "impl": "implemented", - "impl_method": "date", + "impl_method": "days_in_month", "impl_protocol": "MountainAshPolarsScalarDatetimeExpressionSystem", "audited": false, "whole_op": null, @@ -3122,7 +2195,7 @@ }, "narwhals": { "impl": "implemented", - "impl_method": "date", + "impl_method": "days_in_month", "impl_protocol": "MountainAshNarwhalsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -3141,72 +2214,7 @@ }, "ibis": { "impl": "implemented", - "impl_method": "date", - "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", - "audited": true, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "FKEY_MOUNTAINASH_SCALAR_DATETIME", - "op": "DAYS_IN_MONTH" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "days_in_month", - "impl_protocol": "MountainAshPolarsScalarDatetimeExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "days_in_month", - "impl_protocol": "MountainAshNarwhalsScalarDatetimeExpressionSystem", - "audited": true, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "days_in_month", + "impl_method": "days_in_month", "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -4769,10 +3777,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, @@ -4785,10 +3793,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, @@ -4801,10 +3809,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, @@ -4817,10 +3825,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } @@ -4839,29 +3847,61 @@ "contradiction": false, "selector_counts": { "params": 1, - "option_selectors": 2, - "value_classes": 1, + "option_selectors": 12, + "value_classes": 0, "dialects": 1 }, "constraints": [ { - "dialect": null, + "dialect": "ibis-sqlite", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "1h", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1m", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1ms", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1q", "value_class": null, @@ -4869,63 +3909,111 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "quarter", + "option_value": "1s", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "1us", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "1q", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "microsecond", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "millisecond", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "minute", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", "param": "unit", "option_value": "quarter", "value_class": null, @@ -4933,10 +4021,26 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "second", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } @@ -5405,109 +4509,113 @@ "contradiction": false, "selector_counts": { "params": 1, - "option_selectors": 20, - "value_classes": 1, + "option_selectors": 2, + "value_classes": 0, "dialects": 2 }, "constraints": [ { "dialect": "narwhals-pandas", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1d", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-pandas", "param": "unit", - "option_value": "1h", + "option_value": "week", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "narwhals-polars", "param": "unit", - "option_value": "1m", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "narwhals-polars", "param": "unit", - "option_value": "1mo", + "option_value": "week", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null - }, + } + ], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "round_dt", + "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": true, + "contradiction": false, + "selector_counts": { + "params": 1, + "option_selectors": 16, + "value_classes": 0, + "dialects": 2 + }, + "constraints": [ { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", - "option_value": "1ms", + "option_value": "1mo", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "1q", "value_class": null, @@ -5515,63 +4623,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "1y", "value_class": null, @@ -5579,95 +4639,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "month", "value_class": null, @@ -5675,15 +4655,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "quarter", "value_class": null, @@ -5691,47 +4671,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "ibis-polars", "param": "unit", "option_value": "year", "value_class": null, @@ -5739,47 +4687,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1h", "value_class": null, @@ -5787,15 +4703,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1m", "value_class": null, @@ -5803,31 +4719,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1ms", "value_class": null, @@ -5835,15 +4735,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1q", "value_class": null, @@ -5851,15 +4751,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1s", "value_class": null, @@ -5867,15 +4767,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1us", "value_class": null, @@ -5883,202 +4783,106 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "1y", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "day", + "option_value": "microsecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "hour", + "option_value": "millisecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "microsecond", + "option_value": "minute", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "millisecond", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "minute", + "option_value": "second", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } @@ -6086,758 +4890,66 @@ "residue": [], "routed": [], "refinements": [] + } + } + }, + { + "op": { + "family": "FKEY_MOUNTAINASH_SCALAR_DATETIME", + "op": "TIME" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "time", + "impl_protocol": "MountainAshPolarsScalarDatetimeExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "time", + "impl_protocol": "MountainAshNarwhalsScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] }, "ibis": { "impl": "implemented", - "impl_method": "round_dt", + "impl_method": "time", "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, - "constrained": true, + "constrained": false, "contradiction": false, "selector_counts": { - "params": 1, - "option_selectors": 20, - "value_classes": 1, - "dialects": 1 - }, - "constraints": [ - { - "dialect": null, - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - } - ], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "FKEY_MOUNTAINASH_SCALAR_DATETIME", - "op": "TIME" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "time", - "impl_protocol": "MountainAshPolarsScalarDatetimeExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "time", - "impl_protocol": "MountainAshNarwhalsScalarDatetimeExpressionSystem", - "audited": true, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "time", - "impl_protocol": "MountainAshIbisScalarDatetimeExpressionSystem", - "audited": true, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 }, "constraints": [], "residue": [], @@ -7513,10 +5625,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, @@ -7529,10 +5641,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, @@ -7545,10 +5657,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, @@ -7561,10 +5673,10 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } @@ -7583,29 +5695,61 @@ "contradiction": false, "selector_counts": { "params": 1, - "option_selectors": 2, - "value_classes": 1, + "option_selectors": 12, + "value_classes": 0, "dialects": 1 }, "constraints": [ { - "dialect": null, + "dialect": "ibis-sqlite", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "1h", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1m", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1ms", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", "param": "unit", "option_value": "1q", "value_class": null, @@ -7613,63 +5757,111 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "quarter", + "option_value": "1s", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "1us", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": "ibis-sqlite", "param": "unit", - "option_value": "1q", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "microsecond", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "millisecond", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "minute", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", "param": "unit", "option_value": "quarter", "value_class": null, @@ -7677,10 +5869,26 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "second", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } @@ -32203,12 +30411,12 @@ { "op": { "family": "FKEY_SUBSTRAIT_SCALAR_DATETIME", - "op": "STRFTIME" + "op": "ROUND_CALENDAR" }, "cells": { "polars": { "impl": "implemented", - "impl_method": "strftime", + "impl_method": "round_calendar", "impl_protocol": "SubstraitPolarsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -32227,7 +30435,7 @@ }, "narwhals": { "impl": "implemented", - "impl_method": "strftime", + "impl_method": "round_calendar", "impl_protocol": "SubstraitNarwhalsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -32246,19 +30454,148 @@ }, "ibis": { "impl": "implemented", - "impl_method": "strftime", + "impl_method": "round_calendar", "impl_protocol": "SubstraitIbisScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, - "constrained": false, + "constrained": true, "contradiction": false, "selector_counts": { - "params": 0, - "option_selectors": 0, + "params": 2, + "option_selectors": 8, "value_classes": 0, - "dialects": 0 + "dialects": 2 }, - "constraints": [], + "constraints": [ + { + "dialect": "ibis-polars", + "param": "unit", + "option_value": "MONTH", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- CEIL/ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-polars", + "param": "unit", + "option_value": "YEAR", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- CEIL/ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "multiple", + "option_value": "3", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is unsupported for every unit; verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "HOUR", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MICROSECOND", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MILLISECOND", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MINUTE", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "SECOND", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + } + ], "residue": [], "routed": [], "refinements": [] @@ -32268,12 +30605,12 @@ { "op": { "family": "FKEY_SUBSTRAIT_SCALAR_DATETIME", - "op": "STRPTIME_DATE" + "op": "ROUND_TEMPORAL" }, "cells": { "polars": { "impl": "implemented", - "impl_method": "strptime_date", + "impl_method": "round_temporal", "impl_protocol": "SubstraitPolarsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -32292,70 +30629,133 @@ }, "narwhals": { "impl": "implemented", - "impl_method": "strptime_date", + "impl_method": "round_temporal", "impl_protocol": "SubstraitNarwhalsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, - "constrained": true, + "constrained": false, "contradiction": false, "selector_counts": { "params": 0, "option_selectors": 0, "value_classes": 0, - "dialects": 1 + "dialects": 0 }, - "constraints": [ - { - "dialect": "narwhals-pandas", - "param": "*", - "option_value": null, - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "narwhals raises NotImplementedError for str.to_date() on the default pandas backend (it would return an object-dtype Series, diverging from the polars API); str.to_datetime() is unaffected and stays supported", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-30", - "native_errors": [], - "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" - } - ], + "constraints": [], "residue": [], "routed": [], "refinements": [] }, "ibis": { "impl": "implemented", - "impl_method": "strptime_date", + "impl_method": "round_temporal", "impl_protocol": "SubstraitIbisScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, "constrained": true, "contradiction": false, "selector_counts": { - "params": 0, - "option_selectors": 0, + "params": 2, + "option_selectors": 6, "value_classes": 0, "dialects": 1 }, "constraints": [ { "dialect": "ibis-sqlite", - "param": "*", - "option_value": null, + "param": "multiple", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite has no compilation rule for StringToDate/StringToTimestamp (OperationNotDefinedError); format-driven parsing is unavailable on this dialect, so it is gated rather than left to fail natively", + "message": "ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is unsupported for every unit; verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-30", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "HOUR", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MICROSECOND", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MILLISECOND", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MINUTE", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "SECOND", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null } ], "residue": [], @@ -32367,12 +30767,12 @@ { "op": { "family": "FKEY_SUBSTRAIT_SCALAR_DATETIME", - "op": "STRPTIME_TIMESTAMP" + "op": "STRFTIME" }, "cells": { "polars": { "impl": "implemented", - "impl_method": "strptime_timestamp", + "impl_method": "strftime", "impl_protocol": "SubstraitPolarsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -32391,7 +30791,7 @@ }, "narwhals": { "impl": "implemented", - "impl_method": "strptime_timestamp", + "impl_method": "strftime", "impl_protocol": "SubstraitNarwhalsScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, @@ -32410,51 +30810,215 @@ }, "ibis": { "impl": "implemented", - "impl_method": "strptime_timestamp", + "impl_method": "strftime", "impl_protocol": "SubstraitIbisScalarDatetimeExpressionSystem", "audited": true, "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } + }, + { + "op": { + "family": "FKEY_SUBSTRAIT_SCALAR_DATETIME", + "op": "STRPTIME_DATE" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "strptime_date", + "impl_protocol": "SubstraitPolarsScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "strptime_date", + "impl_protocol": "SubstraitNarwhalsScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, "constrained": true, "contradiction": false, "selector_counts": { - "params": 1, + "params": 0, "option_selectors": 0, - "value_classes": 1, - "dialects": 2 + "value_classes": 0, + "dialects": 1 }, "constraints": [ { - "dialect": null, - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", - "workaround": null, - "upstream_ref": null, - "since": "2026-08-15", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "timezone", + "dialect": "narwhals-pandas", + "param": "*", "option_value": null, - "value_class": "iana_timezone", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", + "message": "narwhals raises NotImplementedError for str.to_date() on the default pandas backend (it would return an object-dtype Series, diverging from the polars API); str.to_datetime() is unaffected and stays supported", "workaround": null, "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-30", "native_errors": [], - "probe_exempt": null - }, + "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" + } + ], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "strptime_date", + "impl_protocol": "SubstraitIbisScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": true, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 1 + }, + "constraints": [ + { + "dialect": "ibis-sqlite", + "param": "*", + "option_value": null, + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis-sqlite has no compilation rule for StringToDate/StringToTimestamp (OperationNotDefinedError); format-driven parsing is unavailable on this dialect, so it is gated rather than left to fail natively", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-30", + "native_errors": [], + "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" + } + ], + "residue": [], + "routed": [], + "refinements": [] + } + } + }, + { + "op": { + "family": "FKEY_SUBSTRAIT_SCALAR_DATETIME", + "op": "STRPTIME_TIMESTAMP" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "strptime_timestamp", + "impl_protocol": "SubstraitPolarsScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "strptime_timestamp", + "impl_protocol": "SubstraitNarwhalsScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "strptime_timestamp", + "impl_protocol": "SubstraitIbisScalarDatetimeExpressionSystem", + "audited": true, + "whole_op": null, + "constrained": true, + "contradiction": false, + "selector_counts": { + "params": 1, + "option_selectors": 0, + "value_classes": 1, + "dialects": 2 + }, + "constraints": [ + { + "dialect": null, + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-15", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-duckdb", + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-15", + "native_errors": [], + "probe_exempt": null + }, { "dialect": "ibis-sqlite", "param": "*", @@ -45908,2235 +44472,810 @@ "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", "audited": false, "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "DENSE_RANK" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "dense_rank", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "dense_rank", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "dense_rank", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "FIRST_VALUE" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "first_value", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "first_value", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "first_value", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "LAG" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "lag", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "lag", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "lag", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "LAST_VALUE" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "last_value", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "last_value", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "last_value", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "LEAD" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "lead", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "lead", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "lead", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "NTH_VALUE" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "nth_value", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "nth_value", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "nth_value", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "NTILE" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "ntile", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "ntile", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "ntile", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "PERCENT_RANK" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "percent_rank", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "percent_rank", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "percent_rank", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "RANK" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "rank", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "rank", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "rank", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - }, - { - "op": { - "family": "SUBSTRAIT_ARITHMETIC_WINDOW", - "op": "ROW_NUMBER" - }, - "cells": { - "polars": { - "impl": "implemented", - "impl_method": "row_number", - "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "narwhals": { - "impl": "implemented", - "impl_method": "row_number", - "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - }, - "ibis": { - "impl": "implemented", - "impl_method": "row_number", - "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", - "audited": false, - "whole_op": null, - "constrained": false, - "contradiction": false, - "selector_counts": { - "params": 0, - "option_selectors": 0, - "value_classes": 0, - "dialects": 0 - }, - "constraints": [], - "residue": [], - "routed": [], - "refinements": [] - } - } - } - ] - } - ], - "declarations": [ - { - "backend": "ibis", - "source": "mountainash", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-05", - "library_versions": [], - "fixtures": [] - }, - "facts": [ - { - "dialect": null, - "param": "days", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "hours", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "microseconds", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "milliseconds", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "minutes", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "months", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "seconds", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "years", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Ibis datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "IB-DT-01", - "since": "2026-07-05", - "native_errors": [], - "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "mountainash", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-24", - "library_versions": [], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ - { - "dialect": null, - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "second", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "week", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": "year", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1d", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1h", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1m", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1mo", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1ms", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1q", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1s", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1us", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1w", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "1y", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "day", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "hour", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "DENSE_RANK" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "dense_rank", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "dense_rank", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "dense_rank", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "microsecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "FIRST_VALUE" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "first_value", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "first_value", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "first_value", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "LAG" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "lag", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "lag", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "lag", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "millisecond", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "LAST_VALUE" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "last_value", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "last_value", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "last_value", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "LEAD" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "lead", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "lead", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "lead", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "minute", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "NTH_VALUE" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "nth_value", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "nth_value", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "nth_value", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "NTILE" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "ntile", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "ntile", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "ntile", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "month", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "PERCENT_RANK" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "percent_rank", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "percent_rank", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "percent_rank", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "RANK" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "rank", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "rank", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "rank", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "quarter", - "value_class": null, - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", - "native_errors": [], - "probe_exempt": null - }, + "op": { + "family": "SUBSTRAIT_ARITHMETIC_WINDOW", + "op": "ROW_NUMBER" + }, + "cells": { + "polars": { + "impl": "implemented", + "impl_method": "row_number", + "impl_protocol": "SubstraitPolarsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "narwhals": { + "impl": "implemented", + "impl_method": "row_number", + "impl_protocol": "SubstraitNarwhalsWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + }, + "ibis": { + "impl": "implemented", + "impl_method": "row_number", + "impl_protocol": "SubstraitIbisWindowArithmeticExpressionSystem", + "audited": false, + "whole_op": null, + "constrained": false, + "contradiction": false, + "selector_counts": { + "params": 0, + "option_selectors": 0, + "value_classes": 0, + "dialects": 0 + }, + "constraints": [], + "residue": [], + "routed": [], + "refinements": [] + } + } + } + ] + } + ], + "declarations": [ + { + "backend": "ibis", + "source": "mountainash", + "domain": "datetime", + "evidence": { + "probe_date": "2026-07-05", + "library_versions": [], + "fixtures": [] + }, + "facts": [ { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "quarter", + "dialect": null, + "param": "days", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "quarter", + "dialect": null, + "param": "hours", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "second", + "dialect": null, + "param": "microseconds", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "second", + "dialect": null, + "param": "milliseconds", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "week", + "dialect": null, + "param": "minutes", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "week", + "dialect": null, + "param": "months", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "year", + "dialect": null, + "param": "seconds", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": "year", + "dialect": null, + "param": "years", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Ibis datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "IB-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null } @@ -48147,13 +45286,10 @@ "source": "mountainash", "domain": "datetime", "evidence": { - "probe_date": "2026-07-25", + "probe_date": "2026-08-16", "library_versions": [], "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" + "ibis-duckdb" ] }, "facts": [ @@ -48189,70 +45325,6 @@ "native_errors": [], "probe_exempt": null }, - { - "dialect": null, - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, { "dialect": "ibis-duckdb", "param": "timezone", @@ -48284,1151 +45356,1120 @@ "since": "2026-08-16", "native_errors": [], "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": "ibis-duckdb", - "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null } ] }, { "backend": "ibis", "source": "mountainash", - "domain": "relation", + "domain": "datetime", "evidence": { - "probe_date": "2026-07-05", + "probe_date": "2026-08-16", "library_versions": [], - "fixtures": [] + "fixtures": [ + "ibis-sqlite", + "ibis-polars", + "narwhals-polars", + "narwhals-pandas" + ] }, "facts": [ { - "dialect": null, - "param": "resource", - "option_value": null, + "dialect": "ibis-polars", + "param": "unit", + "option_value": "1mo", + "value_class": null, + "level": "unsupported", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", + "native_errors": [], + "probe_exempt": null + }, + { + "dialect": "ibis-polars", + "param": "unit", + "option_value": "1mo", "value_class": null, "level": "unsupported", - "enforcement": "router_metadata", + "enforcement": "gate", "boundary": "build", - "condition": "resource.dialect.escape_char is set", - "message": "CSV dialect field 'escape_char' is not native-safe on this backend's reader — routed to the CsvSpec fallback reader", - "workaround": "none needed — mountainash routes automatically", + "condition": null, + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "router, not gate — fallback handles it; behaviour covered by relations resource tests" + "probe_exempt": null }, { "dialect": "ibis-polars", - "param": "*", - "option_value": null, + "param": "unit", + "option_value": "1q", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "with_row_index lowers to a window function (row_number); the ibis Polars backend has no WindowFunction translation rule.", - "workaround": "Use ibis-duckdb/ibis-sqlite, or polars/narwhals backends.", - "upstream_ref": "IB-REL-01", - "since": "2026-08-01", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, + "upstream_ref": null, + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "relation op-level gap; covered by relation with_row_index cross-backend tests" - } - ] - }, - { - "backend": "ibis", - "source": "mountainash", - "domain": "set", - "evidence": null, - "facts": [ + "probe_exempt": null + }, { - "dialect": null, - "param": "haystack", - "option_value": null, + "dialect": "ibis-polars", + "param": "unit", + "option_value": "1q", "value_class": null, - "level": "polymorphic", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "literal collections unwrap to raw values; expressions compile through (LIST-wrapper marker)", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "polymorphic — both paths supported by design" + "probe_exempt": null }, { - "dialect": null, - "param": "haystack", - "option_value": null, + "dialect": "ibis-polars", + "param": "unit", + "option_value": "1y", "value_class": null, - "level": "polymorphic", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "literal collections unwrap to raw values; expressions compile through (LIST-wrapper marker)", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "polymorphic — both paths supported by design" - } - ] - }, - { - "backend": "ibis", - "source": "mountainash", - "domain": "ternary", - "evidence": null, - "facts": [ + "probe_exempt": null + }, { - "dialect": null, - "param": "*", - "option_value": null, + "dialect": "ibis-polars", + "param": "unit", + "option_value": "1y", "value_class": null, - "level": "polymorphic", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "literal collections unwrap to raw values; expressions compile through (LIST-wrapper marker)", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "polymorphic — both paths supported by design" - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "arithmetic", - "evidence": { - "probe_date": "2026-07-21", - "library_versions": [], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + "probe_exempt": null + }, { - "dialect": null, - "param": "division_type", - "option_value": "FLOOR", + "dialect": "ibis-polars", + "param": "unit", + "option_value": "month", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "division_type", - "option_value": "TRUNCATE", + "dialect": "ibis-polars", + "param": "unit", + "option_value": "month", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_division_by_zero", - "option_value": "ERROR", + "dialect": "ibis-polars", + "param": "unit", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_division_by_zero", - "option_value": "IEEE", + "dialect": "ibis-polars", + "param": "unit", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_division_by_zero", - "option_value": "LIMIT", + "dialect": "ibis-polars", + "param": "unit", + "option_value": "year", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_division_by_zero", - "option_value": "NULL", + "dialect": "ibis-polars", + "param": "unit", + "option_value": "year", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- round/ceil cannot compute the next calendar boundary (truncate/floor, which only need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1h", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1h", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1h", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1h", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1m", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1m", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1m", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1m", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1ms", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1ms", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1ms", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1ms", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1q", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1q", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NAN", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1q", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NULL", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1q", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "on_domain_error", - "option_value": "NULL", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1s", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1s", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait i64 power overflow mode", - "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1s", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1s", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1us", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1us", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1us", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "1us", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "ERROR", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait i64 power overflow mode", - "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "hour", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "microsecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "microsecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "microsecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "microsecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SATURATE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "millisecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "millisecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait i64 power overflow mode", - "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "millisecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "millisecond", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "minute", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "minute", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "minute", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "minute", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "overflow", - "option_value": "SILENT", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "quarter", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "second", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "second", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "second", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "second", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "ibis-sqlite has no TimestampTruncate support for units finer than DAY, and no TimestampBucket compilation rule (blocks multiple>1 bucketing, which quarter needs); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "mountainash", + "domain": "relation", + "evidence": { + "probe_date": "2026-07-05", + "library_versions": [], + "fixtures": [] + }, + "facts": [ { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "resource", + "option_value": null, "value_class": null, "level": "unsupported", - "enforcement": "gate", + "enforcement": "router_metadata", "boundary": "build", - "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "condition": "resource.dialect.escape_char is set", + "message": "CSV dialect field 'escape_char' is not native-safe on this backend's reader — routed to the CsvSpec fallback reader", + "workaround": "none needed — mountainash routes automatically", "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null + "probe_exempt": "router, not gate — fallback handles it; behaviour covered by relations resource tests" }, { - "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "dialect": "ibis-polars", + "param": "*", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", - "upstream_ref": null, - "since": "2026-07-21", + "message": "with_row_index lowers to a window function (row_number); the ibis Polars backend has no WindowFunction translation rule.", + "workaround": "Use ibis-duckdb/ibis-sqlite, or polars/narwhals backends.", + "upstream_ref": "IB-REL-01", + "since": "2026-08-01", "native_errors": [], - "probe_exempt": null - }, + "probe_exempt": "relation op-level gap; covered by relation with_row_index cross-backend tests" + } + ] + }, + { + "backend": "ibis", + "source": "mountainash", + "domain": "set", + "evidence": null, + "facts": [ { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "haystack", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "polymorphic", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "literal collections unwrap to raw values; expressions compile through (LIST-wrapper marker)", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null + "probe_exempt": "polymorphic — both paths supported by design" }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "haystack", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "polymorphic", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "literal collections unwrap to raw values; expressions compile through (LIST-wrapper marker)", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null - }, + "probe_exempt": "polymorphic — both paths supported by design" + } + ] + }, + { + "backend": "ibis", + "source": "mountainash", + "domain": "ternary", + "evidence": null, + "facts": [ { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "*", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "polymorphic", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "literal collections unwrap to raw values; expressions compile through (LIST-wrapper marker)", + "workaround": null, "upstream_ref": null, - "since": "2026-07-21", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null - }, + "probe_exempt": "polymorphic — both paths supported by design" + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "arithmetic", + "evidence": { + "probe_date": "2026-07-21", + "library_versions": [], + "fixtures": [ + "polars", + "ibis-duckdb", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "division_type", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49436,15 +46477,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "division_type", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49452,15 +46493,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49468,15 +46509,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "IEEE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49484,15 +46525,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "LIMIT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49500,15 +46541,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "NULL", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49516,15 +46557,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49532,15 +46573,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49548,15 +46589,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "CEILING", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49564,15 +46605,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49580,15 +46621,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49596,15 +46637,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49612,15 +46653,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49628,15 +46669,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49644,15 +46685,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49660,15 +46701,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49676,15 +46717,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49692,15 +46733,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49708,15 +46749,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49724,15 +46765,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49740,15 +46781,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49756,15 +46797,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NULL", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49772,15 +46813,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NULL", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49788,15 +46829,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait i64 power overflow mode", + "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49804,15 +46845,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49820,15 +46861,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49836,15 +46877,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49852,15 +46893,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49868,15 +46909,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49884,15 +46925,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49900,15 +46941,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49916,15 +46957,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait i64 power overflow mode", + "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49932,15 +46973,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49948,15 +46989,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49964,15 +47005,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49980,15 +47021,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -49996,15 +47037,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50012,15 +47053,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50028,15 +47069,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50044,15 +47085,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait i64 power overflow mode", + "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50060,15 +47101,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50076,15 +47117,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50092,15 +47133,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50108,15 +47149,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50124,15 +47165,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50140,15 +47181,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50156,15 +47197,15 @@ }, { "dialect": null, - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -50173,7 +47214,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50189,7 +47230,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50205,7 +47246,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50221,7 +47262,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50237,7 +47278,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50253,7 +47294,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50269,7 +47310,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50285,7 +47326,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50301,7 +47342,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50317,7 +47358,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50333,7 +47374,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50349,7 +47390,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50365,7 +47406,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50381,7 +47422,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50397,7 +47438,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50413,7 +47454,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50429,7 +47470,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50445,7 +47486,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50461,7 +47502,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50477,7 +47518,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50493,7 +47534,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50509,7 +47550,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50525,7 +47566,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50541,7 +47582,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50557,7 +47598,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50573,7 +47614,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50589,7 +47630,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50605,7 +47646,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50621,7 +47662,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50637,7 +47678,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50653,7 +47694,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50669,7 +47710,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50685,7 +47726,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50701,7 +47742,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50717,7 +47758,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50733,7 +47774,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50749,7 +47790,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50765,7 +47806,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50781,7 +47822,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50797,7 +47838,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50813,7 +47854,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50829,7 +47870,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50845,7 +47886,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50861,7 +47902,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50877,7 +47918,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50893,7 +47934,7 @@ { "dialect": null, "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -50907,761 +47948,745 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "division_type", - "option_value": "FLOOR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "division_type", - "option_value": "TRUNCATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_division_by_zero", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_division_by_zero", - "option_value": "IEEE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_division_by_zero", - "option_value": "LIMIT", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_division_by_zero", - "option_value": "NULL", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", - "value_class": null, - "level": "expr_capable", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", - "upstream_ref": null, - "since": "2026-07-21", - "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" - }, - { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NAN", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NULL", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "on_domain_error", - "option_value": "NULL", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait arithmetic option semantics", - "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait i64 power overflow mode", - "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "ERROR", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait i64 power overflow mode", - "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SATURATE", + "dialect": null, + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait i64 power overflow mode", - "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "overflow", - "option_value": "SILENT", + "dialect": null, + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait integer overflow mode", - "workaround": "Cast operands to a wider integer dtype before the operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51675,9 +48700,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51691,9 +48716,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51707,9 +48732,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51723,9 +48748,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51739,9 +48764,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51755,9 +48780,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51771,9 +48796,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51787,9 +48812,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51803,9 +48828,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51819,9 +48844,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51835,9 +48860,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51851,9 +48876,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "rounding", - "option_value": "CEILING", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -51868,15 +48893,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "division_type", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -51884,15 +48909,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "division_type", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -51900,15 +48925,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -51916,15 +48941,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "IEEE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -51932,15 +48957,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "LIMIT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -51948,15 +48973,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "on_division_by_zero", + "option_value": "NULL", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -51964,63 +48989,63 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "CEILING", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52028,15 +49053,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52044,15 +49069,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52060,15 +49085,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52076,15 +49101,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52092,15 +49117,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52108,15 +49133,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52124,15 +49149,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52140,15 +49165,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52156,15 +49181,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52172,15 +49197,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52188,15 +49213,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NAN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52204,15 +49229,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NULL", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52220,15 +49245,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "on_domain_error", + "option_value": "NULL", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait arithmetic option semantics", + "workaround": "Pre-handle invalid arithmetic inputs and select the requested result before evaluating the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52236,111 +49261,111 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "FLOOR", + "param": "overflow", + "option_value": "ERROR", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The explicit option selects the native backend's existing behavior, so it is observably equivalent to omission and cannot discriminate", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The DuckDB omission path raises the exact exception required by the requested ERROR semantics, so the explicit option is equivalent" }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait i64 power overflow mode", + "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52348,15 +49373,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52364,15 +49389,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait i64 power overflow mode", + "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52380,15 +49405,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52396,15 +49421,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52412,15 +49437,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52428,15 +49453,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52444,15 +49469,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52460,15 +49485,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52476,15 +49501,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SATURATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52492,15 +49517,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait i64 power overflow mode", + "workaround": "Pre-check the i64 base and exponent and handle out-of-range powers before calling power()", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52508,15 +49533,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52524,15 +49549,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52540,15 +49565,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52556,15 +49581,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52572,15 +49597,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52588,15 +49613,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52604,15 +49629,15 @@ }, { "dialect": "ibis-duckdb", - "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "param": "overflow", + "option_value": "SILENT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement the requested Substrait IEEE rounding mode", - "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", + "message": "The native backend does not implement the requested Substrait integer overflow mode", + "workaround": "Cast operands to a wider integer dtype before the operation", "upstream_ref": null, "since": "2026-07-21", "native_errors": [], @@ -52621,7 +49646,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52637,7 +49662,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52653,7 +49678,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_AWAY_FROM_ZERO", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52669,7 +49694,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52685,7 +49710,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52701,7 +49726,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52717,7 +49742,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52733,7 +49758,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52749,7 +49774,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52765,7 +49790,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52781,7 +49806,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52797,7 +49822,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52813,7 +49838,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52829,7 +49854,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52845,7 +49870,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52861,7 +49886,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52877,7 +49902,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52893,7 +49918,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52909,7 +49934,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52925,7 +49950,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52941,7 +49966,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "CEILING", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52957,7 +49982,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52973,7 +49998,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -52989,7 +50014,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TIE_TO_EVEN", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53005,7 +50030,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53021,7 +50046,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53037,7 +50062,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53053,7 +50078,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53069,7 +50094,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53085,7 +50110,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53101,7 +50126,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53117,7 +50142,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53133,7 +50158,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53149,7 +50174,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53165,7 +50190,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53181,7 +50206,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53197,7 +50222,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53213,7 +50238,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53229,7 +50254,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53245,7 +50270,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53261,7 +50286,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53277,7 +50302,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "FLOOR", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53293,7 +50318,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53309,7 +50334,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53325,7 +50350,7 @@ { "dialect": "ibis-duckdb", "param": "rounding", - "option_value": "TRUNCATE", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -53337,2041 +50362,2008 @@ "since": "2026-07-21", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-25", - "library_versions": [], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ - { - "dialect": null, - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "assume_timezone silently drops the timezone (returns a naive timestamp) — the tz argument is ignored; only polars attaches the timezone", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-25", - "native_errors": [], - "probe_exempt": null - }, - { - "dialect": null, - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "local_timestamp returns the UTC wall clock, not the target-zone wall clock -- ibis has no timezone method and the naive re-cast discards the conversion (verified 2026-07-29, ibis 12.0.0/duckdb: 12:00 instead of 17:30 for Asia/Kolkata)", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-29", - "native_errors": [], - "probe_exempt": null }, { - "dialect": null, - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "assume_timezone silently drops the timezone (returns a naive timestamp) — the tz argument is ignored; only polars attaches the timezone", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "local_timestamp returns the UTC wall clock, not the target-zone wall clock -- ibis has no timezone method and the naive re-cast discards the conversion (verified 2026-07-29, ibis 12.0.0/duckdb: 12:00 instead of 17:30 for Asia/Kolkata)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-29", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "timezone", - "option_value": null, - "value_class": "iana_timezone", - "level": "unsupported", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", - "workaround": null, - "upstream_ref": null, - "since": "2026-08-15", - "native_errors": [], - "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-30", - "library_versions": [ - [ - "ibis", - "12.0.0" - ], - [ - "narwhals", - "2.23.0" - ] - ], - "fixtures": [ - "polars", - "ibis-duckdb", - "ibis-polars", - "ibis-sqlite", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ - { - "dialect": "ibis-sqlite", - "param": "*", - "option_value": null, + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite has no compilation rule for StringToDate/StringToTimestamp (OperationNotDefinedError); format-driven parsing is unavailable on this dialect, so it is gated rather than left to fail natively", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-30", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" + "probe_exempt": null }, { - "dialect": "ibis-sqlite", - "param": "*", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite has no compilation rule for StringToDate/StringToTimestamp (OperationNotDefinedError); format-driven parsing is unavailable on this dialect, so it is gated rather than left to fail natively", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-30", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "datetime", - "evidence": { - "probe_date": "2026-08-15", - "library_versions": [ - [ - "polars", - "1.43.2" - ], - [ - "narwhals", - "2.24.0" - ], - [ - "ibis", - "12.0.0" - ] - ], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + "probe_exempt": null + }, { - "dialect": null, - "param": "component", - "option_value": "IS_DST", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "extract_boolean(IS_DST) is a placeholder (constant False) on all backends; deferred to backlog item 65 (is-dst-placeholder-implementation)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "MONDAY_WEEK", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "NANOSECOND", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "PICOSECOND", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "SUNDAY_WEEK", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "TIMEZONE_OFFSET", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "US_WEEK", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "component", - "option_value": "US_YEAR", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "IS_DST", + "param": "rounding", + "option_value": "TIE_AWAY_FROM_ZERO", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "extract_boolean(IS_DST) is a placeholder (constant False) on all backends; deferred to backlog item 65 (is-dst-placeholder-implementation)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "MONDAY_WEEK", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "NANOSECOND", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "PICOSECOND", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "SUNDAY_WEEK", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "TIMEZONE_OFFSET", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "US_WEEK", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "component", - "option_value": "US_YEAR", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-08-15", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-07-05", - "library_versions": [], - "fixtures": [] - }, - "facts": [ + }, { - "dialect": null, - "param": "character", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "dynamic arg silently miscompiles: str(Expr) bakes the unresolved expression's Python repr into the output as a literal string rather than raising — cannot be confirmed by an exception-based probe" + "probe_exempt": null }, { - "dialect": null, - "param": "characters", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "dynamic arg silently miscompiles via str(Expr) into a no-op char-class, returning the input unchanged rather than raising — cannot be confirmed by an exception-based probe" + "probe_exempt": null }, { - "dialect": null, - "param": "characters", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "dynamic arg silently miscompiles via str(Expr) into a no-op char-class, returning the input unchanged rather than raising — cannot be confirmed by an exception-based probe" + "probe_exempt": null }, { - "dialect": null, - "param": "characters", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "dynamic arg silently miscompiles via str(Expr) into a no-op char-class, returning the input unchanged rather than raising — cannot be confirmed by an exception-based probe" + "probe_exempt": null }, { - "dialect": null, - "param": "length", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "length", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "replacement", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "dynamic arg silently miscompiles: str(Expr) bakes the unresolved expression's Python repr into the output as a literal string rather than raising — cannot be confirmed by an exception-based probe" + "probe_exempt": null }, { - "dialect": null, - "param": "start", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", - "workaround": "Use a literal value, or the polars backend", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-05", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-07-23", - "library_versions": [], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + }, { - "dialect": null, - "param": "*", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "This string operation has no correct native implementation on this backend at the pinned floor; it is gated to fail loudly rather than return wrong data", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "whole-op gate; verified by the dedicated op-level probe suite (test_op_level_gate_probes.py), which cannot be keyed on an OpSpec param" + "probe_exempt": null }, { - "dialect": null, - "param": "*", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "This string operation has no correct native implementation on this backend at the pinned floor; it is gated to fail loudly rather than return wrong data", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "whole-op gate; verified by the dedicated op-level probe suite (test_op_level_gate_probes.py), which cannot be keyed on an OpSpec param" + "probe_exempt": null }, { - "dialect": null, - "param": "*", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "This string operation has no correct native implementation on this backend at the pinned floor; it is gated to fail loudly rather than return wrong data", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], - "probe_exempt": "whole-op gate; verified by the dedicated op-level probe suite (test_op_level_gate_probes.py), which cannot be keyed on an OpSpec param" + "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TIE_TO_EVEN", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, - { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + { + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "UTF8", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "UTF8", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "char_set", - "option_value": "UTF8", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "dotall", - "option_value": "DOTALL_DISABLED", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "dotall", - "option_value": "DOTALL_DISABLED", + "dialect": "ibis-duckdb", + "param": "rounding", + "option_value": "TRUNCATE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", - "workaround": null, + "message": "The native backend does not implement the requested Substrait IEEE rounding mode", + "workaround": "Evaluate with native rounding, then apply an explicit application-level numeric policy", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-21", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "datetime", + "evidence": { + "probe_date": "2026-07-25", + "library_versions": [], + "fixtures": [ + "polars", + "ibis-duckdb", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { "dialect": null, - "param": "dotall", - "option_value": "DOTALL_DISABLED", - "value_class": null, + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "assume_timezone silently drops the timezone (returns a naive timestamp) — the tz argument is ignored; only polars attaches the timezone", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-25", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "dotall", - "option_value": "DOTALL_ENABLED", - "value_class": null, + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "local_timestamp returns the UTC wall clock, not the target-zone wall clock -- ibis has no timezone method and the naive re-cast discards the conversion (verified 2026-07-29, ibis 12.0.0/duckdb: 12:00 instead of 17:30 for Asia/Kolkata)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-29", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "dotall", - "option_value": "DOTALL_ENABLED", - "value_class": null, + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "dotall", - "option_value": "DOTALL_ENABLED", - "value_class": null, + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "dotall", - "option_value": "DOTALL_ENABLED", - "value_class": null, + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "dotall", - "option_value": "DOTALL_ENABLED", - "value_class": null, + "dialect": "ibis-duckdb", + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "assume_timezone silently drops the timezone (returns a naive timestamp) — the tz argument is ignored; only polars attaches the timezone", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-25", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "dotall", - "option_value": "DOTALL_ENABLED", - "value_class": null, + "dialect": "ibis-duckdb", + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "local_timestamp returns the UTC wall clock, not the target-zone wall clock -- ibis has no timezone method and the naive re-cast discards the conversion (verified 2026-07-29, ibis 12.0.0/duckdb: 12:00 instead of 17:30 for Asia/Kolkata)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-29", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "group", + "dialect": "ibis-duckdb", + "param": "timezone", "option_value": null, - "value_class": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "group", - "option_value": "2", - "value_class": null, + "dialect": "ibis-duckdb", + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis has no timezone primitives; extract/extract_boolean's timezone option is silently ignored (the local component is read from the stored value, not the target zone) -- see capabilities/datetime/extract.py", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_DISABLED", - "value_class": null, + "dialect": "ibis-duckdb", + "param": "timezone", + "option_value": null, + "value_class": "iana_timezone", "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "strptime_timestamp silently drops the timezone (returns a naive timestamp) on ibis -- ibis has no timezone primitives, matching assume_timezone/to_timezone/local_timestamp/extract.timezone", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "datetime", + "evidence": { + "probe_date": "2026-07-30", + "library_versions": [ + [ + "ibis", + "12.0.0" + ], + [ + "narwhals", + "2.23.0" + ] + ], + "fixtures": [ + "polars", + "ibis-duckdb", + "ibis-polars", + "ibis-sqlite", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { - "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_DISABLED", + "dialect": "ibis-sqlite", + "param": "*", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite has no compilation rule for StringToDate/StringToTimestamp (OperationNotDefinedError); format-driven parsing is unavailable on this dialect, so it is gated rather than left to fail natively", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-30", "native_errors": [], - "probe_exempt": null + "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" }, { - "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_DISABLED", + "dialect": "ibis-sqlite", + "param": "*", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite has no compilation rule for StringToDate/StringToTimestamp (OperationNotDefinedError); format-driven parsing is unavailable on this dialect, so it is gated rather than left to fail natively", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-30", "native_errors": [], - "probe_exempt": null - }, + "probe_exempt": "whole-op gate on a WILDCARD_PARAM fact; cannot be keyed on an OpSpec param (OpSpecs are indexed by concrete argument name) — verified by the dedicated cross-backend gate tests in test_datetime_strptime_format.py" + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "datetime", + "evidence": { + "probe_date": "2026-08-15", + "library_versions": [ + [ + "polars", + "1.43.2" + ], + [ + "narwhals", + "2.24.0" + ], + [ + "ibis", + "12.0.0" + ] + ], + "fixtures": [ + "polars", + "ibis-duckdb", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_ENABLED", + "param": "component", + "option_value": "IS_DST", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "extract_boolean(IS_DST) is a placeholder (constant False) on all backends; deferred to backlog item 65 (is-dst-placeholder-implementation)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_ENABLED", + "param": "component", + "option_value": "MONDAY_WEEK", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_ENABLED", + "param": "component", + "option_value": "NANOSECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_ENABLED", + "param": "component", + "option_value": "PICOSECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_ENABLED", + "param": "component", + "option_value": "SUNDAY_WEEK", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "multiline", - "option_value": "MULTILINE_ENABLED", + "param": "component", + "option_value": "TIMEZONE_OFFSET", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "negative_start", - "option_value": "ERROR", + "param": "component", + "option_value": "US_WEEK", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement non-default negative_start semantics for substring", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { "dialect": null, - "param": "negative_start", - "option_value": "LEFT_OF_BEGINNING", + "param": "component", + "option_value": "US_YEAR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement non-default negative_start semantics for substring", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "occurrence", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "IS_DST", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "extract_boolean(IS_DST) is a placeholder (constant False) on all backends; deferred to backlog item 65 (is-dst-placeholder-implementation)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "occurrence", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "MONDAY_WEEK", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "occurrence", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "NANOSECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "occurrence", - "option_value": "2", + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "PICOSECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "occurrence", - "option_value": "2", + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "SUNDAY_WEEK", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "occurrence", - "option_value": "2", + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "TIMEZONE_OFFSET", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "padding", - "option_value": "LEFT", + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "US_WEEK", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement LEFT padding semantics for center", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "component", + "option_value": "US_YEAR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "the native backend has no primitive for this extract component (verified by semantic probe; see capabilities/datetime/extract.py)", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-15", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" - }, + "probe_exempt": null + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "datetime", + "evidence": { + "probe_date": "2026-08-16", + "library_versions": [], + "fixtures": [ + "ibis-sqlite", + "ibis-polars" + ] + }, + "facts": [ { - "dialect": null, - "param": "position", - "option_value": null, + "dialect": "ibis-polars", + "param": "unit", + "option_value": "MONTH", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- CEIL/ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": null, + "dialect": "ibis-polars", + "param": "unit", + "option_value": "YEAR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis's polars sub-backend translates interval addition via polars.duration(), which has no months/years kwarg -- CEIL/ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": null, + "dialect": "ibis-sqlite", + "param": "multiple", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is unsupported for every unit; verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": null, + "dialect": "ibis-sqlite", + "param": "multiple", + "option_value": "3", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is unsupported for every unit; verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], - "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": "2", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "HOUR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": "2", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "HOUR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": "2", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MICROSECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": "2", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MICROSECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "position", - "option_value": "2", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MILLISECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MILLISECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MINUTE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "MINUTE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "SECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", - "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", + "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": "ibis-sqlite", + "param": "unit", + "option_value": "SECOND", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "message": "ibis-sqlite TimestampTruncate has no support for units finer than DAY (HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, ibis 12.0.0", "workaround": null, "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-07-05", + "library_versions": [], + "fixtures": [] + }, + "facts": [ { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": null, + "param": "character", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null + "probe_exempt": "dynamic arg silently miscompiles: str(Expr) bakes the unresolved expression's Python repr into the output as a literal string rather than raising — cannot be confirmed by an exception-based probe" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": null, + "param": "characters", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null + "probe_exempt": "dynamic arg silently miscompiles via str(Expr) into a no-op char-class, returning the input unchanged rather than raising — cannot be confirmed by an exception-based probe" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": null, + "param": "characters", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null + "probe_exempt": "dynamic arg silently miscompiles via str(Expr) into a no-op char-class, returning the input unchanged rather than raising — cannot be confirmed by an exception-based probe" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": null, + "param": "characters", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": null + "probe_exempt": "dynamic arg silently miscompiles via str(Expr) into a no-op char-class, returning the input unchanged rather than raising — cannot be confirmed by an exception-based probe" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE", + "dialect": null, + "param": "length", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": null, + "param": "length", + "option_value": null, "value_class": null, - "level": "expr_capable", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": null, + "param": "replacement", + "option_value": null, "value_class": null, - "level": "expr_capable", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": "dynamic arg silently miscompiles: str(Expr) bakes the unresolved expression's Python repr into the output as a literal string rather than raising — cannot be confirmed by an exception-based probe" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": null, + "param": "start", + "option_value": null, "value_class": null, - "level": "expr_capable", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "Ibis has no native equivalent; mountainash composes this operation from literal parameters — dynamic column parameters are unsupported", + "workaround": "Use a literal value, or the polars backend", "upstream_ref": null, - "since": "2026-07-23", + "since": "2026-07-05", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" - }, + "probe_exempt": null + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-07-23", + "library_versions": [], + "fixtures": [ + "polars", + "ibis-duckdb", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": null, + "param": "*", + "option_value": null, "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "This string operation has no correct native implementation on this backend at the pinned floor; it is gated to fail loudly rather than return wrong data", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": "whole-op gate; verified by the dedicated op-level probe suite (test_op_level_gate_probes.py), which cannot be keyed on an OpSpec param" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": null, + "param": "*", + "option_value": null, "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "This string operation has no correct native implementation on this backend at the pinned floor; it is gated to fail loudly rather than return wrong data", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": "whole-op gate; verified by the dedicated op-level probe suite (test_op_level_gate_probes.py), which cannot be keyed on an OpSpec param" }, { - "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "dialect": null, + "param": "*", + "option_value": null, "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "This string operation has no correct native implementation on this backend at the pinned floor; it is gated to fail loudly rather than return wrong data", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": "whole-op gate; verified by the dedicated op-level probe suite (test_op_level_gate_probes.py), which cannot be keyed on an OpSpec param" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55379,15 +52371,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55395,15 +52387,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "case_sensitivity", - "option_value": "CASE_SENSITIVE", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55411,15 +52403,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55427,15 +52419,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55443,15 +52435,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55459,15 +52451,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55475,15 +52467,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55491,15 +52483,15 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "char_set", - "option_value": "ASCII_ONLY", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, "since": "2026-07-23", @@ -55507,57 +52499,57 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "char_set", - "option_value": "UTF8", + "option_value": "ASCII_ONLY", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "char_set", - "option_value": "UTF8", + "option_value": "ASCII_ONLY", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "char_set", - "option_value": "UTF8", + "option_value": "ASCII_ONLY", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "char_set", - "option_value": "UTF8", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -55571,9 +52563,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "char_set", - "option_value": "UTF8", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -55587,9 +52579,9 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "char_set", - "option_value": "UTF8", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", @@ -55603,55 +52595,55 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "dotall", - "option_value": "DOTALL_DISABLED", + "dialect": null, + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "dotall", - "option_value": "DOTALL_DISABLED", + "dialect": null, + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "dotall", - "option_value": "DOTALL_DISABLED", + "dialect": null, + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "expr_capable", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, "since": "2026-07-23", "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_DISABLED", "value_class": null, @@ -55667,7 +52659,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_DISABLED", "value_class": null, @@ -55683,7 +52675,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_DISABLED", "value_class": null, @@ -55699,7 +52691,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_ENABLED", "value_class": null, @@ -55715,7 +52707,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_ENABLED", "value_class": null, @@ -55731,7 +52723,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_ENABLED", "value_class": null, @@ -55747,7 +52739,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_ENABLED", "value_class": null, @@ -55763,7 +52755,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_ENABLED", "value_class": null, @@ -55779,7 +52771,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "dotall", "option_value": "DOTALL_ENABLED", "value_class": null, @@ -55795,7 +52787,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "group", "option_value": null, "value_class": null, @@ -55811,7 +52803,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "group", "option_value": "2", "value_class": null, @@ -55827,55 +52819,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "multiline", - "option_value": "MULTILINE_DISABLED", - "value_class": null, - "level": "expr_capable", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-23", - "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" - }, - { - "dialect": "ibis-duckdb", - "param": "multiline", - "option_value": "MULTILINE_DISABLED", - "value_class": null, - "level": "expr_capable", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-23", - "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" - }, - { - "dialect": "ibis-duckdb", - "param": "multiline", - "option_value": "MULTILINE_DISABLED", - "value_class": null, - "level": "expr_capable", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-23", - "native_errors": [], - "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" - }, - { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_DISABLED", "value_class": null, @@ -55891,7 +52835,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_DISABLED", "value_class": null, @@ -55907,7 +52851,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_DISABLED", "value_class": null, @@ -55923,7 +52867,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_ENABLED", "value_class": null, @@ -55939,7 +52883,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_ENABLED", "value_class": null, @@ -55955,7 +52899,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_ENABLED", "value_class": null, @@ -55971,7 +52915,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_ENABLED", "value_class": null, @@ -55987,7 +52931,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_ENABLED", "value_class": null, @@ -56003,7 +52947,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "multiline", "option_value": "MULTILINE_ENABLED", "value_class": null, @@ -56019,7 +52963,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "negative_start", "option_value": "ERROR", "value_class": null, @@ -56035,7 +52979,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "negative_start", "option_value": "LEFT_OF_BEGINNING", "value_class": null, @@ -56051,23 +52995,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "negative_start", - "option_value": "WRAP_FROM_END", - "value_class": null, - "level": "expr_capable", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "The builder default emits WRAP_FROM_END, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-23", - "native_errors": [], - "probe_exempt": "The builder default emits WRAP_FROM_END, so the explicit option is observably equivalent to omission and cannot discriminate" - }, - { - "dialect": "ibis-duckdb", + "dialect": null, "param": "occurrence", "option_value": null, "value_class": null, @@ -56083,7 +53011,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "occurrence", "option_value": null, "value_class": null, @@ -56099,7 +53027,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "occurrence", "option_value": null, "value_class": null, @@ -56115,7 +53043,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "occurrence", "option_value": "2", "value_class": null, @@ -56131,7 +53059,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "occurrence", "option_value": "2", "value_class": null, @@ -56147,7 +53075,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "occurrence", "option_value": "2", "value_class": null, @@ -56163,7 +53091,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "padding", "option_value": "LEFT", "value_class": null, @@ -56179,23 +53107,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", - "param": "padding", - "option_value": "RIGHT", - "value_class": null, - "level": "expr_capable", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "RIGHT is the builder default, so the explicit option is observably equivalent to omission and cannot discriminate", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-23", - "native_errors": [], - "probe_exempt": "RIGHT is the builder default, so the explicit option is observably equivalent to omission and cannot discriminate" - }, - { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": null, "value_class": null, @@ -56211,7 +53123,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": null, "value_class": null, @@ -56227,7 +53139,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": null, "value_class": null, @@ -56243,7 +53155,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": null, "value_class": null, @@ -56259,7 +53171,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": null, "value_class": null, @@ -56275,7 +53187,7 @@ "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": "2", "value_class": null, @@ -56291,7 +53203,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": "2", "value_class": null, @@ -56307,7 +53219,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": "2", "value_class": null, @@ -56323,7 +53235,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": "2", "value_class": null, @@ -56339,7 +53251,7 @@ "probe_exempt": null }, { - "dialect": "ibis-duckdb", + "dialect": null, "param": "position", "option_value": "2", "value_class": null, @@ -56353,29 +53265,9 @@ "since": "2026-07-23", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-08-12", - "library_versions": [ - [ - "ibis", - "12.0.0" - ] - ], - "fixtures": [ - "ibis-sqlite", - "ibis-duckdb" - ] - }, - "facts": [ + }, { - "dialect": "ibis-sqlite", + "dialect": "ibis-duckdb", "param": "case_sensitivity", "option_value": "CASE_INSENSITIVE", "value_class": null, @@ -56383,15 +53275,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite's native LOWER()/UPPER() are ASCII-only (no ICU extension loaded); CASE_INSENSITIVE's Unicode-aware-lowercasing contract (e.g. Kelvin Sign U+212A -> 'k') is unavailable on this dialect alone in the Ibis family — gated unconditionally for every ibis-sqlite connection and every input (including purely-ASCII input, which SQLite's native LOWER() handles correctly, and any caller-supplied connection with a custom Unicode-aware LOWER()/UPPER() override loaded onto it) because the capability fact is keyed on (backend, dialect), a static identity, with no visibility into a specific connection's actual loaded extensions or a specific call's runtime string content", - "workaround": "Use CASE_INSENSITIVE_ASCII instead if ASCII-only folding is sufficient (genuinely honored on ibis-sqlite via native translate()); otherwise Unicode-normalize both operands in Python (e.g. str.lower()) and reissue the comparison as CASE_SENSITIVE (NOT CASE_INSENSITIVE — this dialect-scoped gate is unconditional and still rejects CASE_INSENSITIVE even after preprocessing), or run this expression against a different Ibis dialect (ibis-duckdb) instead of ibis-sqlite", + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-sqlite", + "dialect": "ibis-duckdb", "param": "case_sensitivity", "option_value": "CASE_INSENSITIVE", "value_class": null, @@ -56399,15 +53291,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite's native LOWER()/UPPER() are ASCII-only (no ICU extension loaded); CASE_INSENSITIVE's Unicode-aware-lowercasing contract (e.g. Kelvin Sign U+212A -> 'k') is unavailable on this dialect alone in the Ibis family — gated unconditionally for every ibis-sqlite connection and every input (including purely-ASCII input, which SQLite's native LOWER() handles correctly, and any caller-supplied connection with a custom Unicode-aware LOWER()/UPPER() override loaded onto it) because the capability fact is keyed on (backend, dialect), a static identity, with no visibility into a specific connection's actual loaded extensions or a specific call's runtime string content", - "workaround": "Use CASE_INSENSITIVE_ASCII instead if ASCII-only folding is sufficient (genuinely honored on ibis-sqlite via native translate()); otherwise Unicode-normalize both operands in Python (e.g. str.lower()) and reissue the comparison as CASE_SENSITIVE (NOT CASE_INSENSITIVE — this dialect-scoped gate is unconditional and still rejects CASE_INSENSITIVE even after preprocessing), or run this expression against a different Ibis dialect (ibis-duckdb) instead of ibis-sqlite", + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-sqlite", + "dialect": "ibis-duckdb", "param": "case_sensitivity", "option_value": "CASE_INSENSITIVE", "value_class": null, @@ -56415,2087 +53307,2203 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite's native LOWER()/UPPER() are ASCII-only (no ICU extension loaded); CASE_INSENSITIVE's Unicode-aware-lowercasing contract (e.g. Kelvin Sign U+212A -> 'k') is unavailable on this dialect alone in the Ibis family — gated unconditionally for every ibis-sqlite connection and every input (including purely-ASCII input, which SQLite's native LOWER() handles correctly, and any caller-supplied connection with a custom Unicode-aware LOWER()/UPPER() override loaded onto it) because the capability fact is keyed on (backend, dialect), a static identity, with no visibility into a specific connection's actual loaded extensions or a specific call's runtime string content", - "workaround": "Use CASE_INSENSITIVE_ASCII instead if ASCII-only folding is sufficient (genuinely honored on ibis-sqlite via native translate()); otherwise Unicode-normalize both operands in Python (e.g. str.lower()) and reissue the comparison as CASE_SENSITIVE (NOT CASE_INSENSITIVE — this dialect-scoped gate is unconditional and still rejects CASE_INSENSITIVE even after preprocessing), or run this expression against a different Ibis dialect (ibis-duckdb) instead of ibis-sqlite", + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-08-12", - "library_versions": [ - [ - "ibis", - "12.0.0" - ], - [ - "narwhals", - "2.24.0" - ] - ], - "fixtures": [ - "polars", - "ibis-duckdb", - "ibis-polars", - "ibis-sqlite", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement CASE_INSENSITIVE semantics for this Substrait string operation", + "workaround": "Lowercase the input and search operand explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_SENSITIVE", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_SENSITIVE", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": null, + "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits CASE_SENSITIVE, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", + "value_class": null, + "level": "expr_capable", + "enforcement": "gate", + "boundary": "build", + "condition": null, + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", + "native_errors": [], + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + }, + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_SENSITIVE", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" }, { "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_SENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_SENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "option_value": "CASE_SENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", - "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", + "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", + "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The native backend does not implement ASCII_ONLY char_set semantics for this Substrait case operation", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "ASCII_ONLY", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { "dialect": "ibis-duckdb", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", + "message": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "ibis-polars", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "dialect": "ibis-duckdb", + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars has no compilation rule for StringTranslate (OperationNotDefinedError); the ASCII-only fold CASE_INSENSITIVE_ASCII needs for contains/starts_with/ends_with is unavailable on this dialect, unlike ibis-duckdb/ibis-sqlite which both support .translate()", + "message": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "ibis-polars", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "dialect": "ibis-duckdb", + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars has no compilation rule for StringTranslate (OperationNotDefinedError); the ASCII-only fold CASE_INSENSITIVE_ASCII needs for contains/starts_with/ends_with is unavailable on this dialect, unlike ibis-duckdb/ibis-sqlite which both support .translate()", + "message": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits UTF8, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "ibis-polars", - "param": "case_sensitivity", - "option_value": "CASE_INSENSITIVE_ASCII", + "dialect": "ibis-duckdb", + "param": "char_set", + "option_value": "UTF8", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars has no compilation rule for StringTranslate (OperationNotDefinedError); the ASCII-only fold CASE_INSENSITIVE_ASCII needs for contains/starts_with/ends_with is unavailable on this dialect, unlike ibis-duckdb/ibis-sqlite which both support .translate()", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-08-12", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-08-12", - "library_versions": [ - [ - "ibis", - "12.0.0" - ], - [ - "polars", - "1.43.2" - ] - ], - "fixtures": [ - "ibis-polars" - ] - }, - "facts": [ + }, { - "dialect": "ibis-polars", - "param": "pattern", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars compiles this to Polars' native str.replace()/str.replace_all(), which does not support a dynamic (column-valued) pattern argument (tracked upstream as PL-STR-01/PL-STR-02 for the raw polars backend; see backlog item 81)", - "workaround": "Use a literal string pattern instead of a column reference", - "upstream_ref": "PL-STR-02", - "since": "2026-08-12", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-polars", - "param": "substring", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "char_set", + "option_value": "UTF8", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars compiles this to Polars' native str.replace()/str.replace_all(), which does not support a dynamic (column-valued) pattern argument (tracked upstream as PL-STR-01/PL-STR-02 for the raw polars backend; see backlog item 81)", - "workaround": "Use a literal string pattern instead of a column reference", - "upstream_ref": "PL-STR-01", - "since": "2026-08-12", + "message": "The underlying case operation is unimplemented/incorrect on this backend (no-op or missing method), so char_set cannot be honored", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-polars", - "param": "substring", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_DISABLED", "value_class": null, - "level": "literal_only", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars compiles this to Polars' native str.replace()/str.replace_all(), which does not support a dynamic (column-valued) pattern argument (tracked upstream as PL-STR-01/PL-STR-02 for the raw polars backend; see backlog item 81)", - "workaround": "Use a literal string pattern instead of a column reference", - "upstream_ref": "PL-STR-02", - "since": "2026-08-12", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-08-12", - "library_versions": [ - [ - "ibis", - "12.0.0" - ], - [ - "polars", - "1.43.2" - ] - ], - "fixtures": [ - "ibis-polars", - "ibis-duckdb", - "ibis-sqlite" - ] - }, - "facts": [ + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" + }, { - "dialect": "ibis-polars", - "param": "*", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_DISABLED", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars has no compilation rule for StringSQLLike (OperationNotDefinedError) for any pattern, literal or dynamic; ibis-duckdb/ibis-sqlite both translate LIKE to native SQL correctly", - "workaround": "Use ibis-duckdb/ibis-sqlite or a polars/narwhals backend for LIKE patterns", - "upstream_ref": "IB-STR-06", - "since": "2026-08-12", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], - "probe_exempt": "whole-op gate on a dialect-scoped WILDCARD_PARAM fact; cannot be keyed on an OpSpec param — verified by the dedicated cross-backend gate test in test_pattern.py (TestLikeIbisPolarsGate) and the native-bypass self-healing probe in test_op_level_gate_probes.py (test_like_ibis_polars_native_still_broken)" + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "ibis-polars", - "param": "pattern", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_DISABLED", "value_class": null, - "level": "literal_only", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars compiles this to Polars' native columnar-argument path, which raises Ibis's own UnsupportedArgumentError for a dynamic (column-valued) argument; a literal value works fine", - "workaround": "Use a literal string pattern/separator instead of a column reference", - "upstream_ref": "IB-STR-09", - "since": "2026-08-12", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "ibis-polars", - "param": "separator", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_DISABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars compiles this to Polars' native columnar-argument path, which raises Ibis's own UnsupportedArgumentError for a dynamic (column-valued) argument; a literal value works fine", - "workaround": "Use a literal string pattern/separator instead of a column reference", - "upstream_ref": "IB-STR-10", - "since": "2026-08-12", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "ibis", - "source": "substrait", - "domain": "string", - "evidence": { - "probe_date": "2026-08-13", - "library_versions": [ - [ - "ibis", - "12.0.0" - ], - [ - "polars", - "1.43.2" - ], - [ - "narwhals", - "2.24.0" - ] - ], - "fixtures": [ - "ibis-duckdb", - "ibis-polars", - "ibis-sqlite", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + }, { - "dialect": "ibis-polars", - "param": "pattern", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_DISABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-polars compiles regexp_string_split to Polars' native re_split, which raises Ibis's own IbisError for a dynamic (column-valued) pattern; a literal pattern works fine", - "workaround": "Use a literal string pattern instead of a column reference", - "upstream_ref": "IB-STR-13", - "since": "2026-08-13", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "ibis-sqlite", - "param": "*", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_DISABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "ibis-sqlite has no compilation rule for RegexSplit (OperationNotDefinedError) for any pattern, literal or dynamic; ibis-duckdb translates it to native SQL correctly and ibis-polars supports a literal pattern", - "workaround": "Use ibis-duckdb, ibis-polars with a literal pattern, or a Polars backend for regex split", - "upstream_ref": "IB-STR-12", - "since": "2026-08-13", - "native_errors": [], - "probe_exempt": "whole-op gate on a dialect-scoped WILDCARD_PARAM fact; cannot be keyed on an OpSpec param -- verified by a dedicated cross-backend gate test plus the native-bypass self-healing probe in test_op_level_gate_probes.py, mirroring item 83's TestLikeIbisPolarsGate / test_like_ibis_polars_native_still_broken" - } - ] - }, - { - "backend": "narwhals", - "source": "mountainash", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-05", - "library_versions": [], - "fixtures": [] - }, - "facts": [ - { - "dialect": null, - "param": "days", - "option_value": null, - "value_class": null, - "level": "literal_only", - "enforcement": "gate", - "boundary": "build", - "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "hours", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_ENABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "microseconds", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_ENABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "milliseconds", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_ENABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "minutes", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_ENABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "months", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_ENABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "seconds", - "option_value": null, + "dialect": "ibis-duckdb", + "param": "dotall", + "option_value": "DOTALL_ENABLED", "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": null, - "param": "years", + "dialect": "ibis-duckdb", + "param": "group", "option_value": null, "value_class": null, - "level": "literal_only", + "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "Narwhals datetime offset operations require literal integer values", - "workaround": "Use a literal integer for the offset amount", - "upstream_ref": "NW-DT-01", - "since": "2026-07-05", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", + "workaround": null, + "upstream_ref": null, + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null - } - ] - }, - { - "backend": "narwhals", - "source": "mountainash", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-24", - "library_versions": [], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" + }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1d", + "dialect": "ibis-duckdb", + "param": "group", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1d", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_DISABLED", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1h", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_DISABLED", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1h", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_DISABLED", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits this regexp flag value, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1m", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_DISABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1m", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_DISABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1mo", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_DISABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1mo", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_ENABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1ms", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_ENABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1ms", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_ENABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1q", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_ENABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1q", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_ENABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1s", + "dialect": "ibis-duckdb", + "param": "multiline", + "option_value": "MULTILINE_ENABLED", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's non-default Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1s", + "dialect": "ibis-duckdb", + "param": "negative_start", + "option_value": "ERROR", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement non-default negative_start semantics for substring", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1us", + "dialect": "ibis-duckdb", + "param": "negative_start", + "option_value": "LEFT_OF_BEGINNING", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement non-default negative_start semantics for substring", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1us", + "dialect": "ibis-duckdb", + "param": "negative_start", + "option_value": "WRAP_FROM_END", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The builder default emits WRAP_FROM_END, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "The builder default emits WRAP_FROM_END, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-duckdb", + "param": "occurrence", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-duckdb", + "param": "occurrence", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-duckdb", + "param": "occurrence", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-duckdb", + "param": "occurrence", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1y", + "dialect": "ibis-duckdb", + "param": "occurrence", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "1y", + "dialect": "ibis-duckdb", + "param": "occurrence", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "day", + "dialect": "ibis-duckdb", + "param": "padding", + "option_value": "LEFT", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement LEFT padding semantics for center", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "day", + "dialect": "ibis-duckdb", + "param": "padding", + "option_value": "RIGHT", "value_class": null, - "level": "unsupported", + "level": "expr_capable", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "RIGHT is the builder default, so the explicit option is observably equivalent to omission and cannot discriminate", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "RIGHT is the builder default, so the explicit option is observably equivalent to omission and cannot discriminate" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "hour", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "hour", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "microsecond", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "microsecond", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "millisecond", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], - "probe_exempt": null + "probe_exempt": "value-agnostic companion to the representative-value positional fact; the value-scoped disposition probe drives the native-path check" }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "millisecond", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "minute", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not honor the regexp position/occurrence/group option; it is silently ignored rather than applied", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "minute", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "month", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "month", + "dialect": "ibis-duckdb", + "param": "position", + "option_value": "2", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The underlying regexp operation is unavailable on this dialect, so its option value cannot be honored", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-07-23", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-08-12", + "library_versions": [ + [ + "ibis", + "12.0.0" + ] + ], + "fixtures": [ + "ibis-sqlite", + "ibis-duckdb" + ] + }, + "facts": [ { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "quarter", + "dialect": "ibis-sqlite", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "ibis-sqlite's native LOWER()/UPPER() are ASCII-only (no ICU extension loaded); CASE_INSENSITIVE's Unicode-aware-lowercasing contract (e.g. Kelvin Sign U+212A -> 'k') is unavailable on this dialect alone in the Ibis family — gated unconditionally for every ibis-sqlite connection and every input (including purely-ASCII input, which SQLite's native LOWER() handles correctly, and any caller-supplied connection with a custom Unicode-aware LOWER()/UPPER() override loaded onto it) because the capability fact is keyed on (backend, dialect), a static identity, with no visibility into a specific connection's actual loaded extensions or a specific call's runtime string content", + "workaround": "Use CASE_INSENSITIVE_ASCII instead if ASCII-only folding is sufficient (genuinely honored on ibis-sqlite via native translate()); otherwise Unicode-normalize both operands in Python (e.g. str.lower()) and reissue the comparison as CASE_SENSITIVE (NOT CASE_INSENSITIVE — this dialect-scoped gate is unconditional and still rejects CASE_INSENSITIVE even after preprocessing), or run this expression against a different Ibis dialect (ibis-duckdb) instead of ibis-sqlite", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "quarter", + "dialect": "ibis-sqlite", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "ibis-sqlite's native LOWER()/UPPER() are ASCII-only (no ICU extension loaded); CASE_INSENSITIVE's Unicode-aware-lowercasing contract (e.g. Kelvin Sign U+212A -> 'k') is unavailable on this dialect alone in the Ibis family — gated unconditionally for every ibis-sqlite connection and every input (including purely-ASCII input, which SQLite's native LOWER() handles correctly, and any caller-supplied connection with a custom Unicode-aware LOWER()/UPPER() override loaded onto it) because the capability fact is keyed on (backend, dialect), a static identity, with no visibility into a specific connection's actual loaded extensions or a specific call's runtime string content", + "workaround": "Use CASE_INSENSITIVE_ASCII instead if ASCII-only folding is sufficient (genuinely honored on ibis-sqlite via native translate()); otherwise Unicode-normalize both operands in Python (e.g. str.lower()) and reissue the comparison as CASE_SENSITIVE (NOT CASE_INSENSITIVE — this dialect-scoped gate is unconditional and still rejects CASE_INSENSITIVE even after preprocessing), or run this expression against a different Ibis dialect (ibis-duckdb) instead of ibis-sqlite", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "second", + "dialect": "ibis-sqlite", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "ibis-sqlite's native LOWER()/UPPER() are ASCII-only (no ICU extension loaded); CASE_INSENSITIVE's Unicode-aware-lowercasing contract (e.g. Kelvin Sign U+212A -> 'k') is unavailable on this dialect alone in the Ibis family — gated unconditionally for every ibis-sqlite connection and every input (including purely-ASCII input, which SQLite's native LOWER() handles correctly, and any caller-supplied connection with a custom Unicode-aware LOWER()/UPPER() override loaded onto it) because the capability fact is keyed on (backend, dialect), a static identity, with no visibility into a specific connection's actual loaded extensions or a specific call's runtime string content", + "workaround": "Use CASE_INSENSITIVE_ASCII instead if ASCII-only folding is sufficient (genuinely honored on ibis-sqlite via native translate()); otherwise Unicode-normalize both operands in Python (e.g. str.lower()) and reissue the comparison as CASE_SENSITIVE (NOT CASE_INSENSITIVE — this dialect-scoped gate is unconditional and still rejects CASE_INSENSITIVE even after preprocessing), or run this expression against a different Ibis dialect (ibis-duckdb) instead of ibis-sqlite", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-08-12", + "library_versions": [ + [ + "ibis", + "12.0.0" + ], + [ + "narwhals", + "2.24.0" + ] + ], + "fixtures": [ + "polars", + "ibis-duckdb", + "ibis-polars", + "ibis-sqlite", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "second", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "week", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "week", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "week", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "week", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "year", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", - "param": "unit", - "option_value": "year", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1d", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1d", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1h", + "dialect": null, + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1h", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1m", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1m", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1mo", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, + "message": "The native backend does not implement CASE_INSENSITIVE_ASCII semantics for this Substrait string operation (same disposition as CASE_INSENSITIVE — neither case-fold value is wired here)", + "workaround": "Fold the input and search operand to ASCII lowercase explicitly before applying the case-sensitive operation", "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, - { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1mo", + { + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1ms", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1ms", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1q", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1q", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1s", + "dialect": "ibis-duckdb", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "The native backend does not implement this regexp flag's CASE_INSENSITIVE_ASCII Substrait semantics", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1s", + "dialect": "ibis-polars", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-polars has no compilation rule for StringTranslate (OperationNotDefinedError); the ASCII-only fold CASE_INSENSITIVE_ASCII needs for contains/starts_with/ends_with is unavailable on this dialect, unlike ibis-duckdb/ibis-sqlite which both support .translate()", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1us", + "dialect": "ibis-polars", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-polars has no compilation rule for StringTranslate (OperationNotDefinedError); the ASCII-only fold CASE_INSENSITIVE_ASCII needs for contains/starts_with/ends_with is unavailable on this dialect, unlike ibis-duckdb/ibis-sqlite which both support .translate()", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1us", + "dialect": "ibis-polars", + "param": "case_sensitivity", + "option_value": "CASE_INSENSITIVE_ASCII", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "ibis-polars has no compilation rule for StringTranslate (OperationNotDefinedError); the ASCII-only fold CASE_INSENSITIVE_ASCII needs for contains/starts_with/ends_with is unavailable on this dialect, unlike ibis-duckdb/ibis-sqlite which both support .translate()", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-08-12", + "library_versions": [ + [ + "ibis", + "12.0.0" + ], + [ + "polars", + "1.43.2" + ] + ], + "fixtures": [ + "ibis-polars" + ] + }, + "facts": [ { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-polars", + "param": "pattern", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars compiles this to Polars' native str.replace()/str.replace_all(), which does not support a dynamic (column-valued) pattern argument (tracked upstream as PL-STR-01/PL-STR-02 for the raw polars backend; see backlog item 81)", + "workaround": "Use a literal string pattern instead of a column reference", + "upstream_ref": "PL-STR-02", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-polars", + "param": "substring", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars compiles this to Polars' native str.replace()/str.replace_all(), which does not support a dynamic (column-valued) pattern argument (tracked upstream as PL-STR-01/PL-STR-02 for the raw polars backend; see backlog item 81)", + "workaround": "Use a literal string pattern instead of a column reference", + "upstream_ref": "PL-STR-01", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-polars", + "param": "substring", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars compiles this to Polars' native str.replace()/str.replace_all(), which does not support a dynamic (column-valued) pattern argument (tracked upstream as PL-STR-01/PL-STR-02 for the raw polars backend; see backlog item 81)", + "workaround": "Use a literal string pattern instead of a column reference", + "upstream_ref": "PL-STR-02", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-08-12", + "library_versions": [ + [ + "ibis", + "12.0.0" + ], + [ + "polars", + "1.43.2" + ] + ], + "fixtures": [ + "ibis-polars", + "ibis-duckdb", + "ibis-sqlite" + ] + }, + "facts": [ { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1w", + "dialect": "ibis-polars", + "param": "*", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars has no compilation rule for StringSQLLike (OperationNotDefinedError) for any pattern, literal or dynamic; ibis-duckdb/ibis-sqlite both translate LIKE to native SQL correctly", + "workaround": "Use ibis-duckdb/ibis-sqlite or a polars/narwhals backend for LIKE patterns", + "upstream_ref": "IB-STR-06", + "since": "2026-08-12", "native_errors": [], - "probe_exempt": null + "probe_exempt": "whole-op gate on a dialect-scoped WILDCARD_PARAM fact; cannot be keyed on an OpSpec param — verified by the dedicated cross-backend gate test in test_pattern.py (TestLikeIbisPolarsGate) and the native-bypass self-healing probe in test_op_level_gate_probes.py (test_like_ibis_polars_native_still_broken)" }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1y", + "dialect": "ibis-polars", + "param": "pattern", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars compiles this to Polars' native columnar-argument path, which raises Ibis's own UnsupportedArgumentError for a dynamic (column-valued) argument; a literal value works fine", + "workaround": "Use a literal string pattern/separator instead of a column reference", + "upstream_ref": "IB-STR-09", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "1y", + "dialect": "ibis-polars", + "param": "separator", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars compiles this to Polars' native columnar-argument path, which raises Ibis's own UnsupportedArgumentError for a dynamic (column-valued) argument; a literal value works fine", + "workaround": "Use a literal string pattern/separator instead of a column reference", + "upstream_ref": "IB-STR-10", + "since": "2026-08-12", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "ibis", + "source": "substrait", + "domain": "string", + "evidence": { + "probe_date": "2026-08-13", + "library_versions": [ + [ + "ibis", + "12.0.0" + ], + [ + "polars", + "1.43.2" + ], + [ + "narwhals", + "2.24.0" + ] + ], + "fixtures": [ + "ibis-duckdb", + "ibis-polars", + "ibis-sqlite", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "day", + "dialect": "ibis-polars", + "param": "pattern", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-polars compiles regexp_string_split to Polars' native re_split, which raises Ibis's own IbisError for a dynamic (column-valued) pattern; a literal pattern works fine", + "workaround": "Use a literal string pattern instead of a column reference", + "upstream_ref": "IB-STR-13", + "since": "2026-08-13", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "day", + "dialect": "ibis-sqlite", + "param": "*", + "option_value": null, "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "ibis-sqlite has no compilation rule for RegexSplit (OperationNotDefinedError) for any pattern, literal or dynamic; ibis-duckdb translates it to native SQL correctly and ibis-polars supports a literal pattern", + "workaround": "Use ibis-duckdb, ibis-polars with a literal pattern, or a Polars backend for regex split", + "upstream_ref": "IB-STR-12", + "since": "2026-08-13", "native_errors": [], - "probe_exempt": null - }, + "probe_exempt": "whole-op gate on a dialect-scoped WILDCARD_PARAM fact; cannot be keyed on an OpSpec param -- verified by a dedicated cross-backend gate test plus the native-bypass self-healing probe in test_op_level_gate_probes.py, mirroring item 83's TestLikeIbisPolarsGate / test_like_ibis_polars_native_still_broken" + } + ] + }, + { + "backend": "narwhals", + "source": "mountainash", + "domain": "datetime", + "evidence": { + "probe_date": "2026-07-05", + "library_versions": [], + "fixtures": [] + }, + "facts": [ { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "hour", + "dialect": null, + "param": "days", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "hour", + "dialect": null, + "param": "hours", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "microsecond", + "dialect": null, + "param": "microseconds", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "microsecond", + "dialect": null, + "param": "milliseconds", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "millisecond", + "dialect": null, + "param": "minutes", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "millisecond", + "dialect": null, + "param": "months", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "minute", + "dialect": null, + "param": "seconds", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", - "param": "unit", - "option_value": "minute", + "dialect": null, + "param": "years", + "option_value": null, "value_class": null, - "level": "unsupported", + "level": "literal_only", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", - "workaround": null, - "upstream_ref": null, - "since": "2026-07-24", + "message": "Narwhals datetime offset operations require literal integer values", + "workaround": "Use a literal integer for the offset amount", + "upstream_ref": "NW-DT-01", + "since": "2026-07-05", "native_errors": [], "probe_exempt": null - }, + } + ] + }, + { + "backend": "narwhals", + "source": "mountainash", + "domain": "datetime", + "evidence": { + "probe_date": "2026-08-16", + "library_versions": [], + "fixtures": [ + "ibis-sqlite", + "ibis-polars", + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [ { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", - "option_value": "month", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", - "option_value": "month", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", - "option_value": "quarter", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", - "option_value": "quarter", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", - "option_value": "second", + "option_value": "week", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", - "option_value": "second", + "option_value": "week", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", "option_value": "week", "value_class": null, @@ -58503,15 +55511,15 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-polars", + "dialect": "narwhals-pandas", "param": "unit", "option_value": "week", "value_class": null, @@ -58519,160 +55527,157 @@ "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-polars", "param": "unit", - "option_value": "week", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-polars", "param": "unit", - "option_value": "week", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-polars", "param": "unit", - "option_value": "year", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-polars", "param": "unit", - "option_value": "year", + "option_value": "1w", "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-24", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null - } - ] - }, - { - "backend": "narwhals", - "source": "mountainash", - "domain": "datetime", - "evidence": { - "probe_date": "2026-07-25", - "library_versions": [], - "fixtures": [ - "polars", - "ibis-duckdb", - "narwhals-polars", - "narwhals-pandas" - ] - }, - "facts": [ + }, { - "dialect": "narwhals-pandas", + "dialect": "narwhals-polars", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "week", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { - "dialect": "narwhals-pandas", + "dialect": "narwhals-polars", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "week", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-polars", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "week", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null }, { "dialect": "narwhals-polars", "param": "unit", - "option_value": null, - "value_class": "duration_multiplier", + "option_value": "week", + "value_class": null, "level": "unsupported", "enforcement": "gate", "boundary": "build", "condition": null, - "message": "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result", + "message": "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects", "workaround": null, "upstream_ref": null, - "since": "2026-07-25", + "since": "2026-08-16", "native_errors": [], "probe_exempt": null } ] }, + { + "backend": "narwhals", + "source": "mountainash", + "domain": "datetime", + "evidence": { + "probe_date": "2026-08-16", + "library_versions": [], + "fixtures": [ + "narwhals-polars", + "narwhals-pandas" + ] + }, + "facts": [] + }, { "backend": "narwhals", "source": "mountainash", diff --git a/docs/reference/expression-coverage.md b/docs/reference/expression-coverage.md index 4021ff87..779f2694 100644 --- a/docs/reference/expression-coverage.md +++ b/docs/reference/expression-coverage.md @@ -3,7 +3,7 @@ -Declarations: 42 · Facts: 1560 · Registered operations: 324 · Implementation records: 972 +Declarations: 43 · Facts: 1462 · Registered operations: 326 · Implementation records: 978 Scoped deviations (dialect/param/option/value-class) live in [`expression-coverage-scoped.md`](expression-coverage-scoped.md). @@ -50,9 +50,9 @@ Legend — cell states (by exception): | Backend | default_capable | audited_clean | constrained | NOT_IMPLEMENTED | UNKNOWN | ops_total | | --- | --- | --- | --- | --- | --- | --- | -| polars | 191 | 81 | 52 | 0 | 0 | 324 | -| narwhals | 97 | 149 | 78 | 0 | 0 | 324 | -| ibis | 138 | 111 | 75 | 0 | 0 | 324 | +| polars | 191 | 83 | 52 | 0 | 0 | 326 | +| narwhals | 97 | 151 | 78 | 0 | 0 | 326 | +| ibis | 138 | 111 | 77 | 0 | 0 | 326 | contradictions: 0 audited_unknown: 0 @@ -61,9 +61,9 @@ audited_unknown: 0 | Axis | Breakdown | | --- | --- | -| Level | expr_capable 149, literal_only 65, polymorphic 9, unsupported 1337 | -| Enforcement | gate 1553, router_metadata 3, materialize_residue 4 | -| Backend | polars 265, narwhals 662, ibis 633 | +| Level | expr_capable 149, literal_only 65, polymorphic 9, unsupported 1239 | +| Enforcement | gate 1455, router_metadata 3, materialize_residue 4 | +| Backend | polars 265, narwhals 586, ibis 611 | `pandas` / `pyarrow` are routed input types (they execute via the narwhals path) and are not independent coverage columns. @@ -72,8 +72,8 @@ audited_unknown: 0 | Backend | Source | Domain | Probe date | Library versions | Fixtures | | --- | --- | --- | --- | --- | --- | | ibis | mountainash | datetime | 2026-07-05 | | | -| ibis | mountainash | datetime | 2026-07-24 | | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | -| ibis | mountainash | datetime | 2026-07-25 | | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | +| ibis | mountainash | datetime | 2026-08-16 | | ibis-duckdb | +| ibis | mountainash | datetime | 2026-08-16 | | ibis-sqlite, ibis-polars, narwhals-polars, narwhals-pandas | | ibis | mountainash | relation | 2026-07-05 | | | | ibis | mountainash | set | — | — | — | | ibis | mountainash | ternary | — | — | — | @@ -81,6 +81,7 @@ audited_unknown: 0 | ibis | substrait | datetime | 2026-07-25 | | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | | ibis | substrait | datetime | 2026-07-30 | ibis 12.0.0, narwhals 2.23.0 | polars, ibis-duckdb, ibis-polars, ibis-sqlite, narwhals-polars, narwhals-pandas | | ibis | substrait | datetime | 2026-08-15 | polars 1.43.2, narwhals 2.24.0, ibis 12.0.0 | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | +| ibis | substrait | datetime | 2026-08-16 | | ibis-sqlite, ibis-polars | | ibis | substrait | string | 2026-07-05 | | | | ibis | substrait | string | 2026-07-23 | | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | | ibis | substrait | string | 2026-08-12 | ibis 12.0.0 | ibis-sqlite, ibis-duckdb | @@ -89,8 +90,8 @@ audited_unknown: 0 | ibis | substrait | string | 2026-08-12 | ibis 12.0.0, polars 1.43.2 | ibis-polars, ibis-duckdb, ibis-sqlite | | ibis | substrait | string | 2026-08-13 | ibis 12.0.0, polars 1.43.2, narwhals 2.24.0 | ibis-duckdb, ibis-polars, ibis-sqlite, narwhals-polars, narwhals-pandas | | narwhals | mountainash | datetime | 2026-07-05 | | | -| narwhals | mountainash | datetime | 2026-07-24 | | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | -| narwhals | mountainash | datetime | 2026-07-25 | | polars, ibis-duckdb, narwhals-polars, narwhals-pandas | +| narwhals | mountainash | datetime | 2026-08-16 | | ibis-sqlite, ibis-polars, narwhals-polars, narwhals-pandas | +| narwhals | mountainash | datetime | 2026-08-16 | | narwhals-polars, narwhals-pandas | | narwhals | mountainash | list | 2026-07-05 | | | | narwhals | mountainash | relation | 2026-07-05 | | | | narwhals | mountainash | set | — | — | — | @@ -134,7 +135,7 @@ audited_unknown: 0 | `ADD_MONTHS` | ✓ | ◐ partial (1 params, 0 option-selectors, 0 value-classes, 0 dialects) | ◐ partial (1 params, 0 option-selectors, 0 value-classes, 0 dialects) | | `ADD_SECONDS` | ✓ | ◐ partial (1 params, 0 option-selectors, 0 value-classes, 0 dialects) | ◐ partial (1 params, 0 option-selectors, 0 value-classes, 0 dialects) | | `ADD_YEARS` | ✓ | ◐ partial (1 params, 0 option-selectors, 0 value-classes, 0 dialects) | ◐ partial (1 params, 0 option-selectors, 0 value-classes, 0 dialects) | -| `CEIL` | ✓ | ◐ partial (1 params, 20 option-selectors, 1 value-classes, 2 dialects) | ◐ partial (1 params, 20 option-selectors, 1 value-classes, 1 dialects) | +| `CEIL` | ✓ | ◐ partial (1 params, 2 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (1 params, 16 option-selectors, 0 value-classes, 2 dialects) | | `DATE` | ✓ | ✓ audited | ✓ audited | | `DAYS_IN_MONTH` | ✓ | ✓ audited | ✓ audited | | `DIFF_DAYS` | ✓ | ✓ audited | ✓ audited | @@ -160,14 +161,14 @@ audited_unknown: 0 | `EXTRACT_WEEK` | ✓ | ✓ audited | ✓ audited | | `EXTRACT_WEEKDAY` | ✓ | ✓ audited | ✓ audited | | `EXTRACT_YEAR` | ✓ | ✓ audited | ✓ audited | -| `FLOOR` | ✓ | ◐ partial (1 params, 2 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (1 params, 2 option-selectors, 1 value-classes, 1 dialects) | +| `FLOOR` | ✓ | ◐ partial (1 params, 2 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (1 params, 12 option-selectors, 0 value-classes, 1 dialects) | | `IS_DST` | ✓ | ✓ audited | ◐ partial (1 params, 0 option-selectors, 1 value-classes, 1 dialects) | | `IS_LEAP_YEAR` | ✓ | ✓ audited | ✓ audited | | `MONTH_END` | ✓ | ✓ audited | ✓ audited | | `MONTH_START` | ✓ | ✓ audited | ✓ audited | | `NOW` | ✓ | ✓ audited | ✓ audited | | `OFFSET_BY` | ✓ | ✓ audited | ✓ audited | -| `ROUND` | ✓ | ◐ partial (1 params, 20 option-selectors, 1 value-classes, 2 dialects) | ◐ partial (1 params, 20 option-selectors, 1 value-classes, 1 dialects) | +| `ROUND` | ✓ | ◐ partial (1 params, 2 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (1 params, 16 option-selectors, 0 value-classes, 2 dialects) | | `TIME` | ✓ | ✓ audited | ✓ audited | | `TODAY` | ✓ | ✓ audited | ✓ audited | | `TOTAL_DAYS` | ✓ | ✓ audited | ✓ audited | @@ -178,7 +179,7 @@ audited_unknown: 0 | `TOTAL_NANOSECONDS` | ✓ | ✓ audited | ✓ audited | | `TOTAL_SECONDS` | ✓ | ✓ audited | ✓ audited | | `TO_TIMEZONE` | ✓ | ✓ audited | ◐ partial (1 params, 0 option-selectors, 1 value-classes, 1 dialects) | -| `TRUNCATE` | ✓ | ◐ partial (1 params, 2 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (1 params, 2 option-selectors, 1 value-classes, 1 dialects) | +| `TRUNCATE` | ✓ | ◐ partial (1 params, 2 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (1 params, 12 option-selectors, 0 value-classes, 1 dialects) | ### `FKEY_MOUNTAINASH_SCALAR_LIST` (mountainash / list) @@ -323,6 +324,8 @@ audited_unknown: 0 | `EXTRACT` | ◐ partial (1 params, 6 option-selectors, 0 value-classes, 1 dialects) | ◐ partial (1 params, 9 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (2 params, 7 option-selectors, 1 value-classes, 1 dialects) | | `EXTRACT_BOOLEAN` | ◐ partial (1 params, 1 option-selectors, 0 value-classes, 1 dialects) | ◐ partial (1 params, 1 option-selectors, 0 value-classes, 2 dialects) | ◐ partial (2 params, 1 option-selectors, 1 value-classes, 1 dialects) | | `LOCAL_TIMESTAMP` | ✓ audited | ✓ audited | ◐ partial (1 params, 0 option-selectors, 1 value-classes, 1 dialects) | +| `ROUND_CALENDAR` | ✓ audited | ✓ audited | ◐ partial (2 params, 8 option-selectors, 0 value-classes, 2 dialects) | +| `ROUND_TEMPORAL` | ✓ audited | ✓ audited | ◐ partial (2 params, 6 option-selectors, 0 value-classes, 1 dialects) | | `STRFTIME` | ✓ audited | ✓ audited | ✓ audited | | `STRPTIME_DATE` | ✓ audited | ◐ partial (0 params, 0 option-selectors, 0 value-classes, 1 dialects) · unsupported on narwhals-pandas | ◐ partial (0 params, 0 option-selectors, 0 value-classes, 1 dialects) · unsupported on ibis-sqlite | | `STRPTIME_TIMESTAMP` | ✓ audited | ✓ audited | ◐ partial (1 params, 0 option-selectors, 1 value-classes, 2 dialects) · unsupported on ibis-sqlite | diff --git a/src/mountainash/expressions/backends/capabilities/datetime/options.py b/src/mountainash/expressions/backends/capabilities/datetime/options.py index fe6ef392..656da6be 100644 --- a/src/mountainash/expressions/backends/capabilities/datetime/options.py +++ b/src/mountainash/expressions/backends/capabilities/datetime/options.py @@ -1,14 +1,31 @@ """Import-safe datetime option capability declarations. -Disposition matrix (verified by the controller Step-0 probe of all four -fixtures, post-Task-3a — authoritative): - -| op | polars | ibis (ibis-duckdb) | narwhals (each dialect) | -|-------------|--------|----------------------------|----------------------------| -| truncate | ALL | honor core+1w; declare 1q | honor core+1q; declare 1w | -| floor_dt | ALL | honor core+1w; declare 1q | honor core+1q; declare 1w | -| round_dt | ALL | declare EVERY value | declare EVERY value | -| ceil_dt | ALL | declare EVERY value | declare EVERY value | +Disposition matrix (item 74: truncate/round_dt/ceil_dt/floor_dt now redirect +through the real round_temporal/round_calendar implementation instead of a +silent-wrong truncate-fallback; re-verified 2026-08-16 against the pinned +libraries -- authoritative): + +| op | polars | ibis-duckdb | ibis-sqlite | ibis-polars | narwhals (each dialect) | +|-------------|--------|-------------|-------------------------|------------------|--------------------------| +| truncate | ALL | ALL | declare sub-day+quarter | ALL | declare 1w | +| floor_dt | ALL | ALL | declare sub-day+quarter | ALL | declare 1w | +| round_dt | ALL | ALL | declare sub-day+quarter | declare cal+qtr | declare 1w | +| ceil_dt | ALL | ALL | declare sub-day+quarter | declare cal+qtr | declare 1w | + +"declare sub-day+quarter" = {1h, 1m, 1s, 1ms, 1us, 1q} declared UNSUPPORTED +on ibis-sqlite for every op: sqlite's TimestampTruncate has no support for +units finer than DAY (blocks FLOOR itself, hence every op), and its +TimestampBucket has no compilation rule at all (blocks the multiple=3 +bucketing 1q needs, regardless of rounding mode). + +"declare cal+qtr" = {1y, 1mo, 1q} declared UNSUPPORTED on ibis-polars, but +ONLY for round_dt/ceil_dt: those need `floor + ibis.interval(months=..)`/ +`interval(years=..)` to compute the next boundary, and ibis's polars +sub-backend translates intervals via `polars.duration()`, which has no +months/years kwarg. truncate/floor_dt only ever call FLOOR (no interval +needed), so they honor 1y/1mo/1q on ibis-polars -- unlike ibis-sqlite's gap, +this one is genuinely rounding-mode-scoped, verified empirically (both +dialects' full op x value matrix probed directly, not inferred). Portable core = {1y, 1mo, 1d, 1h, 1m, 1s, 1ms, 1us}. 1ns was dropped in Task 3a (divisor-by-zero panic in polars). Honored cells carry NO fact — the cell @@ -16,8 +33,7 @@ fact; the visitor raises ``BackendCapabilityError`` BEFORE calling the backend (enforce_capabilities=True by default), so the silent narwhals-truncate fallback and the raw ibis error are both replaced by a -clean error path. Backend round/ceil/floor impls are NOT edited — the -capability facts are the only honesty mechanism. +clean error path. Friendly aliases (year, quarter, month, week, day, hour, minute, second, millisecond, microsecond) are normalized to their canonical duration form @@ -31,14 +47,17 @@ because the api builder already normalized it — but the integrity guard counts them as separate cells, so they must be separately declared. -Family / dialect separation (mirrors the string ``padding`` slice): - - ibis declared: family-default (dialect=None) fact AND ibis-duckdb fact; - ibis-duckdb-specific, but a dialect=None family default protects every - other ibis dialect (ibis-sqlite, ibis-bigquery, ...) from silently - re-accepting a value the family cannot honor. - - narwhals declared: per-dialect facts only (narwhals-polars AND - narwhals-pandas) — design-review I-1; NEVER a single dialect=None - narwhals family fact, which would conflate the two dialects. +Dialect scoping (item 74 revision): NO ibis family default (dialect=None). +ibis-duckdb honors every value; ibis-sqlite and ibis-polars each have real, +independent gaps (different units, different op subsets) discovered by +direct probing, not inference from one dialect. A shared family-default +baseline would either wrongly restrict duckdb or wrongly permit +sqlite/polars — concrete per-dialect facts for the two known-divergent +dialects is the honest choice (mirrors capabilities/datetime/rounding.py's +identical policy for the underlying Substrait round_temporal/round_calendar +ops in this same PR). narwhals declared facts remain per-dialect only +(narwhals-polars AND narwhals-pandas) — design-review I-1; NEVER a single +dialect=None narwhals family fact, which would conflate the two dialects. Migrated from mountainash.expressions.backends.expression_systems.datetime_option_capabilities (2026-08 capability-architecture PR). """ @@ -54,10 +73,10 @@ ) -_SINCE = "2026-07-24" +_SINCE = "2026-08-16" # Domain spelling must match MA_OPTION_DOMAINS — the test-side guard cross-references -# them. Post-Task-3a: 1ns/nanosecond were dropped; 1q (quarter) and 1w (week) remain +# them. 1ns/nanosecond were dropped (Task 3a); 1q (quarter) and 1w (week) remain # in the friendly input set but are declared per-backend by capability facts. _ALL_UNIT_VALUES = ("1y", "1mo", "1d", "1h", "1m", "1s", "1ms", "1us", "1w", "1q") _FRIENDLY_ALIASES: dict[str, str] = { @@ -65,43 +84,35 @@ "day": "1d", "hour": "1h", "minute": "1m", "second": "1s", "millisecond": "1ms", "microsecond": "1us", } -# Every value the disposition matrix enumerates: duration forms + friendly -# aliases. Both forms share the same per-backend disposition (the api -# builder normalizes aliases to the canonical form, so the backend only -# sees one or the other). -_ALL_VALUES_WITH_ALIASES: tuple[str, ...] = ( - _ALL_UNIT_VALUES + tuple(_FRIENDLY_ALIASES) -) -# Each (op, fkey) maps to the unit value set the visitor must gate. truncate -# and floor_dt share semantics (floor == truncate) per Task 3a; both honor -# core+1w on ibis (1q is not in ibis TimestampTruncate) and core+1q on -# narwhals (1w is not a supported narwhals truncate unit). round_dt and -# ceil_dt have NO native datetime impl on ibis/narwhals (silent -# truncate-fallback is an anti-pattern) — declared UNSUPPORTED for EVERY -# unit value on ibis and both narwhals dialects. +# Each op maps to the FKEY the visitor gates on. _UNIT_OP_FKEYS: dict[str, object] = { "truncate": FK_DT.TRUNCATE, "round_dt": FK_DT.ROUND, "ceil_dt": FK_DT.CEIL, "floor_dt": FK_DT.FLOOR, } +_ALL_FOUR_OPS = tuple(_UNIT_OP_FKEYS) + +# ibis-sqlite: every op declares the same set (TimestampTruncate has no +# sub-day support at all, which blocks FLOOR itself; TimestampBucket has no +# sqlite compilation rule, which blocks 1q's multiple=3 bucketing). +_IBIS_SQLITE_DECLARED: dict[str, tuple[str, ...]] = { + op: ("1h", "1m", "1s", "1ms", "1us", "1q") for op in _ALL_FOUR_OPS +} -# (op, value) pairs ibis-duckdb DECLARES UNSUPPORTED. (truncate and floor_dt: -# only 1q is undeclared on ibis; 1w is honored. round_dt and ceil_dt: ALL -# values are undeclared.) Keyed by duration form; the friendly-alias form -# is added at declaration time so the integrity guard sees both. -_IBIS_DUCKDB_DECLARED: dict[str, tuple[str, ...]] = { - "truncate": ("1q",), - "floor_dt": ("1q",), - "round_dt": _ALL_UNIT_VALUES, - "ceil_dt": _ALL_UNIT_VALUES, +# ibis-polars: ONLY round_dt/ceil_dt declare 1y/1mo/1q -- truncate/floor_dt +# (FLOOR-only, no interval addition) honor them. +_IBIS_POLARS_DECLARED: dict[str, tuple[str, ...]] = { + "round_dt": ("1y", "1mo", "1q"), + "ceil_dt": ("1y", "1mo", "1q"), } + +# narwhals: every op declares only 1w (dt.truncate rejects the '1w' duration +# on both dialects; round_dt/ceil_dt redirect through the same truncate-based +# implementation as truncate/floor_dt, so they inherit the identical gap). _NARWHALS_DECLARED: dict[str, tuple[str, ...]] = { - "truncate": ("1w",), - "floor_dt": ("1w",), - "round_dt": _ALL_UNIT_VALUES, - "ceil_dt": _ALL_UNIT_VALUES, + op: ("1w",) for op in _ALL_FOUR_OPS } @@ -125,40 +136,25 @@ def _declared_with_aliases( return out -# Per-(op, value) human-readable limitation messages, named after the real -# backend behavior the controller probe observed. -_IBIS_QUARTER_UNSUPPORTED = ( - "ibis TimestampTruncate rejects the quarter unit '1q' (and its " - "friendly alias 'quarter')" +_IBIS_SQLITE_MSG = ( + "ibis-sqlite has no TimestampTruncate support for units finer than DAY, " + "and no TimestampBucket compilation rule (blocks multiple>1 bucketing, " + "which quarter needs); verified 2026-08-16, ibis 12.0.0" ) -_IBIS_NO_NATIVE_ROUND_CEIL = ( - "ibis has no native datetime round/ceil; silently falling back to " - "truncate would return a wrong value" +_IBIS_POLARS_MSG = ( + "ibis's polars sub-backend translates interval addition via " + "polars.duration(), which has no months/years kwarg -- round/ceil " + "cannot compute the next calendar boundary (truncate/floor, which only " + "need FLOOR, are unaffected); verified 2026-08-16, ibis 12.0.0" ) _NARWHALS_TRUNCATE_WEEK_UNSUPPORTED = ( - "narwhals truncate rejects the week unit '1w' (and its friendly " - "alias 'week')" -) -_NARWHALS_NO_NATIVE_ROUND_CEIL = ( - "narwhals has no native datetime round/ceil; silently falling back to " - "truncate would return a wrong value" + "narwhals dt.truncate rejects the week unit '1w' (and its friendly " + "alias 'week') on both dialects" ) -def _ibis_duckdb_message(op: str, value: str) -> str: - if op in {"round_dt", "ceil_dt"}: - return _IBIS_NO_NATIVE_ROUND_CEIL - return _IBIS_QUARTER_UNSUPPORTED - - -def _narwhals_message(op: str, value: str) -> str: - if op in {"round_dt", "ceil_dt"}: - return _NARWHALS_NO_NATIVE_ROUND_CEIL - return _NARWHALS_TRUNCATE_WEEK_UNSUPPORTED - - -def _build_ibis_duckdb_facts() -> tuple[CapabilityFact, ...]: - declared = _declared_with_aliases(_IBIS_DUCKDB_DECLARED) +def _build_ibis_sqlite_facts() -> tuple[CapabilityFact, ...]: + declared = _declared_with_aliases(_IBIS_SQLITE_DECLARED) return tuple( CapabilityFact( operation_key=_UNIT_OP_FKEYS[op], @@ -166,8 +162,8 @@ def _build_ibis_duckdb_facts() -> tuple[CapabilityFact, ...]: option_value=value, level=CapabilityLevel.UNSUPPORTED, backend=CONST_BACKEND.IBIS, - dialect="ibis-duckdb", - message=_ibis_duckdb_message(op, value), + dialect="ibis-sqlite", + message=_IBIS_SQLITE_MSG, since=_SINCE, ) for op, declared_values in declared.items() @@ -175,12 +171,8 @@ def _build_ibis_duckdb_facts() -> tuple[CapabilityFact, ...]: ) -def _build_ibis_family_defaults() -> tuple[CapabilityFact, ...]: - """ibis dialect=None family-default facts — protect every other ibis - dialect (ibis-sqlite, ibis-bigquery, …) from silently re-accepting a - value the family cannot honor. Mirrors _IBIS_FAMILY_DEFAULTS in the - string padding slice.""" - declared = _declared_with_aliases(_IBIS_DUCKDB_DECLARED) +def _build_ibis_polars_facts() -> tuple[CapabilityFact, ...]: + declared = _declared_with_aliases(_IBIS_POLARS_DECLARED) return tuple( CapabilityFact( operation_key=_UNIT_OP_FKEYS[op], @@ -188,8 +180,8 @@ def _build_ibis_family_defaults() -> tuple[CapabilityFact, ...]: option_value=value, level=CapabilityLevel.UNSUPPORTED, backend=CONST_BACKEND.IBIS, - dialect=None, - message=_ibis_duckdb_message(op, value), + dialect="ibis-polars", + message=_IBIS_POLARS_MSG, since=_SINCE, ) for op, declared_values in declared.items() @@ -207,7 +199,7 @@ def _build_narwhals_dialect_facts(dialect: str) -> tuple[CapabilityFact, ...]: level=CapabilityLevel.UNSUPPORTED, backend=CONST_BACKEND.NARWHALS, dialect=dialect, - message=_narwhals_message(op, value), + message=_NARWHALS_TRUNCATE_WEEK_UNSUPPORTED, since=_SINCE, ) for op, declared_values in declared.items() @@ -215,14 +207,13 @@ def _build_narwhals_dialect_facts(dialect: str) -> tuple[CapabilityFact, ...]: ) -_IBIS_DUCKDB_FACTS = _build_ibis_duckdb_facts() -_IBIS_FAMILY_DEFAULTS = _build_ibis_family_defaults() +_IBIS_FACTS = _build_ibis_sqlite_facts() + _build_ibis_polars_facts() _NARWHALS_POLARS_FACTS = _build_narwhals_dialect_facts("narwhals-polars") _NARWHALS_PANDAS_FACTS = _build_narwhals_dialect_facts("narwhals-pandas") -# polars honors EVERY value in the MA unit domain — no facts. The portable -# core + the divergent members (1w, 1q) all reach a real polars method. -# (1ns was dropped in Task 3a — the validator rejects it before the visitor.) +# polars honors EVERY value in the MA unit domain — no facts. +# ibis-duckdb honors EVERY value now that round_dt/ceil_dt redirect through +# the real round_temporal/round_calendar implementation — no facts. from mountainash.core.capabilities.declarations import ( # noqa: E402 @@ -233,18 +224,16 @@ def _build_narwhals_dialect_facts(dialect: str) -> tuple[CapabilityFact, ...]: ) _EVIDENCE = ProbeEvidence( - probe_date=_SINCE, # 2026-07-24 - library_versions=(), # not recorded in the original docstring - fixtures=( - "polars", "ibis-duckdb", "narwhals-polars", "narwhals-pandas", - ), + probe_date=_SINCE, + library_versions=(), + fixtures=("ibis-sqlite", "ibis-polars", "narwhals-polars", "narwhals-pandas"), ) DECLARATIONS = ( CapabilityDeclaration( backend=CONST_BACKEND.IBIS, domain=Domain.DATETIME, source=FactSource.MOUNTAINASH, - facts=_IBIS_FAMILY_DEFAULTS + _IBIS_DUCKDB_FACTS, + facts=_IBIS_FACTS, evidence=_EVIDENCE, ), CapabilityDeclaration( diff --git a/src/mountainash/expressions/backends/capabilities/datetime/rounding.py b/src/mountainash/expressions/backends/capabilities/datetime/rounding.py new file mode 100644 index 00000000..b8623e51 --- /dev/null +++ b/src/mountainash/expressions/backends/capabilities/datetime/rounding.py @@ -0,0 +1,147 @@ +"""Capability declarations for round_temporal / round_calendar (item 74). + +Both ops share the real Substrait 9-unit closed domain (YEAR..MICROSECOND). +Every backend implements the shared algorithm in its Python body; the +per-dialect gaps below were discovered empirically (2026-08-16 probe against +ibis 12.0.0's duckdb/sqlite/polars sub-backends) and are NOT modeled in the +Python bodies — a single shared implementation covers duckdb natively, and +these facts block the dialects where it does not translate, rather than the +body special-casing dialects it cannot itself distinguish. + +ibis-sqlite: + - ``TimestampTruncate`` has no HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND + support (only YEAR/MONTH/WEEK/DAY) -- FLOOR itself fails for those units + on round_temporal (whose whole unit domain is a subset of them) and on + round_calendar's sub-day units. + - ``TimestampBucket`` (used for multiple > 1) has no sqlite compilation + rule at all -- declared per the single representative multiplier value + this repo's tests actually exercise (mirrors the OPTION_VALUE_DOMAINS + "representative value" convention for open-domain int options). + +ibis-polars: + - CEIL/tie modes need `ibis.interval(months=..)`/`ibis.interval(years=..)` + to compute the next boundary; ibis's polars sub-backend translates + intervals via `polars.duration()`, which has no months/years kwarg + (calendar-length intervals are not fixed-duration). FLOOR alone (which + only calls `.truncate()`, no interval) would still work for MONTH/YEAR, + but declaring the whole unit UNSUPPORTED is the closed-by-default + choice: partial per-rounding-mode support within one unit is exactly + the "silently inconsistent" shape this repo's capability facts exist + to prevent (see round_dt/ceil_dt in options.py for the same policy). +""" +from __future__ import annotations + +from mountainash.core.capabilities import CapabilityFact, CapabilityLevel +from mountainash.core.constants import CONST_BACKEND +from mountainash.expressions.core.expression_system.function_keys.enums import ( + FKEY_SUBSTRAIT_SCALAR_DATETIME as FK_DT, +) + +_SINCE = "2026-08-16" + +_SQLITE_UNIT_MSG = ( + "ibis-sqlite TimestampTruncate has no support for units finer than DAY " + "(HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND); verified 2026-08-16, " + "ibis 12.0.0" +) +_SQLITE_MULTIPLE_MSG = ( + "ibis-sqlite has no TimestampBucket compilation rule -- multiple > 1 is " + "unsupported for every unit; verified 2026-08-16, ibis 12.0.0" +) +_POLARS_CALENDAR_MSG = ( + "ibis's polars sub-backend translates interval addition via " + "polars.duration(), which has no months/years kwarg -- CEIL/" + "ROUND_TIE_DOWN/ROUND_TIE_UP cannot compute the next calendar boundary; " + "verified 2026-08-16, ibis 12.0.0" +) + +_SQLITE_SUB_DAY_UNITS = ("HOUR", "MINUTE", "SECOND", "MILLISECOND", "MICROSECOND") +_ROUNDING_OPS = (FK_DT.ROUND_TEMPORAL, FK_DT.ROUND_CALENDAR) + + +def _sqlite_unit_facts() -> tuple[CapabilityFact, ...]: + return tuple( + CapabilityFact( + operation_key=op, + param="unit", + option_value=unit, + level=CapabilityLevel.UNSUPPORTED, + backend=CONST_BACKEND.IBIS, + dialect="ibis-sqlite", + message=_SQLITE_UNIT_MSG, + since=_SINCE, + ) + for op in _ROUNDING_OPS + for unit in _SQLITE_SUB_DAY_UNITS + ) + + +def _sqlite_multiple_facts() -> tuple[CapabilityFact, ...]: + # Representative multiplier values this repo's tests exercise (item 74's + # cross-backend test file): round_temporal HOUR multiple=2, round_calendar + # MONTH multiple=3. HOUR is already blocked by _sqlite_unit_facts above; + # the multiple=2 fact is retained for completeness/symmetry. + return ( + CapabilityFact( + operation_key=FK_DT.ROUND_TEMPORAL, + param="multiple", + option_value="2", + level=CapabilityLevel.UNSUPPORTED, + backend=CONST_BACKEND.IBIS, + dialect="ibis-sqlite", + message=_SQLITE_MULTIPLE_MSG, + since=_SINCE, + ), + CapabilityFact( + operation_key=FK_DT.ROUND_CALENDAR, + param="multiple", + option_value="3", + level=CapabilityLevel.UNSUPPORTED, + backend=CONST_BACKEND.IBIS, + dialect="ibis-sqlite", + message=_SQLITE_MULTIPLE_MSG, + since=_SINCE, + ), + ) + + +def _polars_calendar_unit_facts() -> tuple[CapabilityFact, ...]: + return tuple( + CapabilityFact( + operation_key=FK_DT.ROUND_CALENDAR, + param="unit", + option_value=unit, + level=CapabilityLevel.UNSUPPORTED, + backend=CONST_BACKEND.IBIS, + dialect="ibis-polars", + message=_POLARS_CALENDAR_MSG, + since=_SINCE, + ) + for unit in ("MONTH", "YEAR") + ) + + +_IBIS_FACTS = _sqlite_unit_facts() + _sqlite_multiple_facts() + _polars_calendar_unit_facts() + + +from mountainash.core.capabilities.declarations import ( # noqa: E402 + CapabilityDeclaration, + Domain, + FactSource, + ProbeEvidence, +) + +_EVIDENCE = ProbeEvidence( + probe_date=_SINCE, + library_versions=(), + fixtures=("ibis-sqlite", "ibis-polars"), +) + +DECLARATIONS = ( + CapabilityDeclaration( + backend=CONST_BACKEND.IBIS, domain=Domain.DATETIME, + source=FactSource.SUBSTRAIT, + facts=_IBIS_FACTS, + evidence=_EVIDENCE, + ), +) diff --git a/src/mountainash/expressions/backends/capabilities/datetime/value_classes_ma.py b/src/mountainash/expressions/backends/capabilities/datetime/value_classes_ma.py index 511cccc3..6801c239 100644 --- a/src/mountainash/expressions/backends/capabilities/datetime/value_classes_ma.py +++ b/src/mountainash/expressions/backends/capabilities/datetime/value_classes_ma.py @@ -1,41 +1,54 @@ """Import-safe value-class capability declarations (MA ops). -Reinstates integer unit multipliers >= 2 (e.g. "2d", "3h", "12mo") on the four -Mountainash datetime rounding ops (truncate / round_dt / ceil_dt / floor_dt), -and declares to_timezone unsupported on ibis. - -Probe matrix — DURATION_MULTIPLIER and IANA_TIMEZONE, all-fixtures: - -| op | polars | ibis (ibis-duckdb) | narwhals-polars | narwhals-pandas | -|-------------|---------|--------------------|-----------------|-----------------| -| truncate | honored | RAISED | honored | honored | -| floor_dt | honored | RAISED | honored | honored | -| round_dt | honored | RAISED | SILENTLY-WRONG | SILENTLY-WRONG | -| ceil_dt | honored | RAISED | SILENTLY-WRONG | SILENTLY-WRONG | -| to_timezone | honored | UNCOMPOSABLE | honored | honored | - -- ibis raises for EVERY multiplier on ALL four rounding ops: `TimestampTruncate` rejects - the Polars-style "" duration form (SignatureValidationError) — the - ibis impls pass the raw duration to `x.truncate(...)`. -- narwhals HONORS multipliers on truncate/floor_dt (native `dt.truncate` accepts - the duration) but SILENTLY TRUNCATES on round_dt/ceil_dt (no native datetime - round/ceil -> falls back to truncate, so "2d" rounds DOWN instead of to the - nearest 2-day boundary — a wrong value). -- polars honors every multiplier on all four ops -> NO fact. +item 74 revision: truncate/round_dt/ceil_dt/floor_dt now redirect through the +real round_temporal/round_calendar implementation instead of calling +`x.truncate("")`/silently falling back to truncate. This retires +the DURATION_MULTIPLIER-class facts that used to declare ibis-duckdb +UNSUPPORTED for every multiplied unit ("2d", "3h", "12mo", ...) on all four +ops, and narwhals UNSUPPORTED for round_dt/ceil_dt specifically -- BOTH +claims are now false (verified 2026-08-16, re-probed through the live +redirect, not source-reading): + +| op | polars | ibis-duckdb | ibis-sqlite | ibis-polars | narwhals (each dialect) | +|-------------|---------|-------------|-------------|-------------|--------------------------| +| truncate | honored | honored | RAISED | honored | honored | +| floor_dt | honored | honored | RAISED | honored | honored | +| round_dt | honored | honored | RAISED | honored | honored | +| ceil_dt | honored | honored | RAISED | honored | honored | +| to_timezone | honored | UNCOMPOSABLE| honored | honored | honored | + +- ibis-duckdb honors every multiplied unit on all four rounding ops now: + round_temporal/round_calendar's TimestampValue.bucket() (multiple > 1) + works for every unit on duckdb. +- ibis-sqlite has no TimestampBucket compilation rule at all -- every + multiplied unit on all four ops raises there (this is the SAME real gap + capabilities/datetime/rounding.py declares for the direct Substrait + round_temporal/round_calendar ops; this module declares it again for the + four MA-wrapper FKEYs the visitor actually gates the outer call on). +- ibis-polars honors every multiplied fixed-duration unit (days/hours/etc); + its genuine gap is calendar-unit (MONTH/YEAR) round/ceil, which is a + closed, exact-value gap already declared in capabilities/datetime/options.py + -- not a DURATION_MULTIPLIER-class (open-value) concern. +- narwhals HONORS every multiplied unit on all four ops now: round_dt/ceil_dt + redirect through the same real hand-rolled round_temporal/round_calendar + body as truncate/floor_dt (no more silent truncate-fallback). +- polars honors every multiplier on all four ops -> NO fact (unchanged). - to_timezone on ibis is correct ONLY at the result-materialization boundary (the target zone lives in the ibis output dtype, but SQL is a bare CAST AS TIMESTAMPTZ), so any expression composed on the result raises UnsupportedOperationError (UNCOMPOSABLE). Declared UNSUPPORTED so the capability gate raises BackendCapabilityError. + (Unchanged by item 74 -- unrelated to rounding.) A value-class gates soundly here because the api-builder validates parameters to their respective value-class domains (spec Section 3.2). -Family / dialect discipline (mirrors PR-C `capabilities/datetime/options.py`): - - ibis: family-default (dialect=None) fact AND ibis-duckdb fact — the - dialect=None default protects every other ibis dialect from silently - re-accepting an operation/multiplier the family cannot honor. - - narwhals: per-dialect facts ONLY (narwhals-polars AND narwhals-pandas) — - never a dialect=None narwhals family default. +Dialect discipline (item 74 revision): NO ibis family default (dialect=None) +for the rounding facts -- ibis-duckdb and ibis-polars both honor every +multiplier now; only ibis-sqlite has a real gap, so it gets its own concrete +fact (mirrors capabilities/datetime/options.py's identical policy change in +this same PR). to_timezone's family default is unchanged (still a genuine +ibis-wide limitation). narwhals: per-dialect facts remain the convention +where needed, but round_dt/ceil_dt no longer need any narwhals fact at all. Migrated from mountainash.expressions.backends.expression_systems.datetime_value_class_capabilities_ma (2026-08 capability-architecture PR). """ @@ -51,29 +64,19 @@ FKEY_MOUNTAINASH_SCALAR_DATETIME as FK_DT, ) -_SINCE = "2026-07-25" +_SINCE = "2026-08-16" -# op-name -> FKEY, for the four unit-rounding ops. -_ALL_ROUNDING = { - "truncate": FK_DT.TRUNCATE, - "round_dt": FK_DT.ROUND, - "ceil_dt": FK_DT.CEIL, - "floor_dt": FK_DT.FLOOR, -} +# Known residual gap (documented, not enforced by a fact -- see module +# docstring): ibis-sqlite's TimestampBucket has no compilation rule, so a +# multi-digit MA-wrapper duration string (e.g. dt.truncate("2d")) on +# ibis-sqlite raises a raw native OperationNotDefinedError rather than a +# clean BackendCapabilityError. A DURATION_MULTIPLIER-class fact for this +# would need a corresponding class-backed OptionCell, which the 4-fixture +# argument-type matrix cannot instantiate for ibis-sqlite (same structural +# limit documented in test_option_fact_integrity.py's +# _MATRIX_UNREACHABLE_DIALECT_FACTS) -- tracked as a backlog follow-up +# rather than adding an untested, unexercised fact here. -# ibis raises on multipliers for ALL four rounding ops. -_IBIS_MULTIPLIER_OPS = ("truncate", "round_dt", "ceil_dt", "floor_dt") -# narwhals only diverges (silent truncate) on round/ceil; truncate/floor honor. -_NARWHALS_MULTIPLIER_OPS = ("round_dt", "ceil_dt") - -_IBIS_MSG = ( - "ibis TimestampTruncate rejects Polars-style multiplier duration units " - "(e.g. '2d', '3h', '12mo'); only single bare units are accepted" -) -_NARWHALS_ROUND_CEIL_MSG = ( - "narwhals has no native datetime round/ceil; a multiplier value silently " - "falls back to truncate and returns a wrong (down-rounded) result" -) _TO_TIMEZONE_MSG = ( "to_timezone is correct only at the materialization boundary -- the " "target zone lives in the ibis output dtype, not in the engine (SQL is a " @@ -86,17 +89,6 @@ ) -def _mult_fact(op: str, backend, dialect: str | None, message: str) -> CapabilityFact: - return CapabilityFact( - operation_key=_ALL_ROUNDING[op], - param="unit", - value_class=ValueClass.DURATION_MULTIPLIER, - level=CapabilityLevel.UNSUPPORTED, - backend=backend, - dialect=dialect, - message=message, - since=_SINCE, - ) def _tz_fact(backend, dialect: str | None, message: str) -> CapabilityFact: @@ -126,21 +118,14 @@ def _is_dst_fact(backend, dialect: str | None, message: str) -> CapabilityFact: _IBIS_FACTS = tuple( - _mult_fact(op, CONST_BACKEND.IBIS, dialect, _IBIS_MSG) - for op in _IBIS_MULTIPLIER_OPS - for dialect in (None, "ibis-duckdb") # family default + duckdb -) + tuple( _tz_fact(CONST_BACKEND.IBIS, dialect, _TO_TIMEZONE_MSG) for dialect in (None, "ibis-duckdb") ) + tuple( _is_dst_fact(CONST_BACKEND.IBIS, dialect, _IS_DST_MSG) for dialect in (None, "ibis-duckdb") ) -_NARWHALS_FACTS = tuple( - _mult_fact(op, CONST_BACKEND.NARWHALS, dialect, _NARWHALS_ROUND_CEIL_MSG) - for op in _NARWHALS_MULTIPLIER_OPS - for dialect in ("narwhals-polars", "narwhals-pandas") # per-dialect only -) +# narwhals honors every multiplied unit on all four ops now -- no facts. +_NARWHALS_FACTS: tuple[CapabilityFact, ...] = () from mountainash.core.capabilities.declarations import ( # noqa: E402 @@ -151,11 +136,14 @@ def _is_dst_fact(backend, dialect: str | None, message: str) -> CapabilityFact: ) _EVIDENCE = ProbeEvidence( - probe_date=_SINCE, # 2026-07-25 - library_versions=(), # not recorded in the original docstring - fixtures=( - "polars", "ibis-duckdb", "narwhals-polars", "narwhals-pandas", - ), + probe_date=_SINCE, + library_versions=(), + fixtures=("ibis-duckdb",), +) +_NARWHALS_EVIDENCE = ProbeEvidence( + probe_date=_SINCE, + library_versions=(), + fixtures=("narwhals-polars", "narwhals-pandas"), ) DECLARATIONS = ( @@ -169,6 +157,6 @@ def _is_dst_fact(backend, dialect: str | None, message: str) -> CapabilityFact: backend=CONST_BACKEND.NARWHALS, domain=Domain.DATETIME, source=FactSource.MOUNTAINASH, facts=_NARWHALS_FACTS, - evidence=_EVIDENCE, + evidence=_NARWHALS_EVIDENCE, ), ) diff --git a/src/mountainash/expressions/backends/expression_systems/ibis/extensions_mountainash/expsys_ib_ext_ma_scalar_datetime.py b/src/mountainash/expressions/backends/expression_systems/ibis/extensions_mountainash/expsys_ib_ext_ma_scalar_datetime.py index 498b39f9..0d3518ad 100644 --- a/src/mountainash/expressions/backends/expression_systems/ibis/extensions_mountainash/expsys_ib_ext_ma_scalar_datetime.py +++ b/src/mountainash/expressions/backends/expression_systems/ibis/extensions_mountainash/expsys_ib_ext_ma_scalar_datetime.py @@ -30,21 +30,6 @@ ) -# Ibis .truncate() expects a bare unit letter, not the Polars-style "" duration. -# Shared by truncate() and floor_dt() (floor == truncate for datetime). Units with no -# entry here (e.g. "1q") fall through unmapped and raise a native ibis error — declared -# UNSUPPORTED on ibis via capability facts. -_IBIS_TRUNCATE_UNIT_MAPPING = { - "1y": "Y", - "1mo": "M", - "1w": "W", - "1d": "D", - "1h": "h", - "1m": "m", - "1s": "s", - "1ms": "ms", - "1us": "us", -} class MountainAshIbisScalarDatetimeExpressionSystem(IbisBaseExpressionSystem, MountainAshScalarDatetimeExpressionSystemProtocol["IbisValueExpr"]): @@ -440,15 +425,12 @@ def truncate( Args: x: Datetime expression. - unit: Unit string (1d, 1h, Y, M, D, h, m, s, etc.). + unit: Unit string (1d, 1h, 1mo, 1y, etc.). Returns: Truncated datetime. """ - # Ibis truncate expects just the unit letter, not "1d" format - # Convert "1d" -> "D", "1h" -> "h", etc. - unit_mapped = _IBIS_TRUNCATE_UNIT_MAPPING.get(unit, unit) - return x.truncate(unit_mapped) + return self._round(x, "FLOOR", unit) def round_dt( self, @@ -460,16 +442,12 @@ def round_dt( Args: x: Datetime expression. - unit: Unit string. + unit: Unit string (1d, 1h, 1mo, 1y, etc.). Returns: Rounded datetime. - - Note: - Ibis may not have round. Falls back to truncate. """ - # Ibis doesn't have round - fallback to truncate - return x.truncate(unit) + return self._round(x, "ROUND_TIE_UP", unit) def ceil_dt( self, @@ -481,16 +459,12 @@ def ceil_dt( Args: x: Datetime expression. - unit: Unit string. + unit: Unit string (1d, 1h, 1mo, 1y, etc.). Returns: Ceiling datetime. - - Note: - Ibis doesn't have ceil. Falls back to truncate. """ - # Ibis doesn't have ceil - fallback to truncate - return x.truncate(unit) + return self._round(x, "CEIL", unit) def floor_dt( self, @@ -502,19 +476,28 @@ def floor_dt( Args: x: Datetime expression. - unit: Unit string. + unit: Unit string (1d, 1h, 1mo, 1y, etc.). Returns: Floor datetime. - - Note: - floor == truncate for datetime (both drop the sub-unit remainder), so - ibis floor is honored wherever truncate is. Applies the same Polars-style - duration -> ibis unit-letter mapping as truncate (round_dt/ceil_dt have no - native ibis impl and are declared UNSUPPORTED via capability facts instead). """ - unit_mapped = _IBIS_TRUNCATE_UNIT_MAPPING.get(unit, unit) - return x.truncate(unit_mapped) + # Floor is the same as truncate. + return self._round(x, "FLOOR", unit) + + def _round(self, x: IbisTemporalExpr, rounding: str, unit: str) -> IbisValueExpr: + """Redirect through the real round_temporal/round_calendar + implementation (item 74). `unit` is already normalize_unit()'d and + validate_ma_option()'d by the builder before it reaches here.""" + from mountainash.expressions.core.expression_api.api_builders.extensions_mountainash._ma_option_domains import parse_ma_unit + + multiple, canonical_unit, family = parse_ma_unit(unit) + if family == "calendar": + return self.round_calendar( + x, rounding=rounding, unit=canonical_unit, multiple=multiple + ) + return self.round_temporal( + x, rounding=rounding, unit=canonical_unit, multiple=multiple + ) # ========================================================================= # Timezone Methods diff --git a/src/mountainash/expressions/backends/expression_systems/ibis/substrait/expsys_ib_scalar_datetime.py b/src/mountainash/expressions/backends/expression_systems/ibis/substrait/expsys_ib_scalar_datetime.py index fed3bddf..1f291cbe 100644 --- a/src/mountainash/expressions/backends/expression_systems/ibis/substrait/expsys_ib_scalar_datetime.py +++ b/src/mountainash/expressions/backends/expression_systems/ibis/substrait/expsys_ib_scalar_datetime.py @@ -10,7 +10,7 @@ CALENDAR_COMPONENTS, DatetimeComponent, ) -from typing import TYPE_CHECKING, Optional +from typing import Any, TYPE_CHECKING import ibis @@ -29,6 +29,48 @@ "not the target zone wall clock; see capabilities/datetime/value_classes_substrait.py" ) +# round_temporal's in-scope units (v1): YEAR/MONTH/WEEK are declared +# UNSUPPORTED there (ambiguous fixed-duration length) -- round_calendar +# covers all nine. +_ROUND_TEMPORAL_UNITS = frozenset( + {"DAY", "HOUR", "MINUTE", "SECOND", "MILLISECOND", "MICROSECOND"} +) + +# Substrait canonical unit name -> ibis.interval()/TimestampValue.bucket() +# plural kwarg. x.truncate(unit) accepts the canonical uppercase name +# directly (verified against ibis 12.0.0/duckdb) so no translation is +# needed there. +_IBIS_INTERVAL_KWARGS = { + "YEAR": "years", "MONTH": "months", "WEEK": "weeks", "DAY": "days", + "HOUR": "hours", "MINUTE": "minutes", "SECOND": "seconds", + "MILLISECOND": "milliseconds", "MICROSECOND": "microseconds", +} + + +def _round_datetime(x: IbisValueExpr, rounding: str, unit: str, multiple: int) -> IbisValueExpr: + """Shared round_temporal/round_calendar implementation. + + x.truncate(unit) gives FLOOR at multiple=1. For multiple>1, + TimestampValue.bucket(**{kwarg: multiple}) buckets from the UNIX epoch + (ibis has no per-op origin parameter honored here; v1 never supplies a + custom origin). CEIL/tie modes are hand-rolled: ibis rejects Polars-style + combined multiplier truncate strings (SignatureValidationError, verified + 2026-08-16) and has no native round/ceil primitive at all. + """ + kwarg = _IBIS_INTERVAL_KWARGS[unit] + floor = x.truncate(unit) if multiple == 1 else x.bucket(**{kwarg: multiple}) + if rounding == "FLOOR": + return floor + ceiling = (floor == x).ifelse(x, floor + ibis.interval(**{kwarg: multiple})) + if rounding == "CEIL": + return ceiling + diff_down = x.epoch_seconds().cast("int64") - floor.epoch_seconds().cast("int64") + diff_up = ceiling.epoch_seconds().cast("int64") - x.epoch_seconds().cast("int64") + if rounding == "ROUND_TIE_UP": + return (diff_up <= diff_down).ifelse(ceiling, floor) + # ROUND_TIE_DOWN: nearest, tying to the earlier point on equidistance. + return (diff_down <= diff_up).ifelse(floor, ceiling) + class SubstraitIbisScalarDatetimeExpressionSystem(IbisBaseExpressionSystem, SubstraitScalarDatetimeExpressionSystemProtocol["IbisValueExpr"]): """Ibis implementation of ScalarDatetimeExpressionProtocol. @@ -404,53 +446,60 @@ def round_temporal( self, x: IbisValueExpr, /, - rounding: Optional[str] = None, - unit: str = "1d", + rounding: str, + unit: str, multiple: int = 1, - origin: Optional[str] = None, + origin: Any = None, ) -> IbisValueExpr: - """Round datetime to a multiple of a time unit. + """Round datetime to a multiple of a fixed-duration time unit. Args: x: Datetime expression. rounding: FLOOR, CEIL, ROUND_TIE_DOWN, or ROUND_TIE_UP. - unit: Time unit string. - multiple: Multiple of unit (default 1). - origin: Origin timestamp for rounding. + unit: One of DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND. + YEAR/MONTH/WEEK are declared UNSUPPORTED here (ambiguous + fixed-duration length; see capabilities/datetime/rounding.py) + -- the raise below is defence in depth. + multiple: Positive multiplier on unit. Defaults to 1. + origin: Never non-None here -- the API builder rejects it at + build time (v1 scope). Returns: Rounded datetime. - - Note: - Ibis only supports truncate. Falls back to truncate for all modes. """ - # Ibis only has truncate - use for all rounding modes - return x.truncate(unit) + if unit not in _ROUND_TEMPORAL_UNITS: + raise BackendCapabilityError( + f"round_temporal unit={unit!r} is not supported -- fixed-duration " + "rounding is ambiguous for YEAR/MONTH/WEEK; use round_calendar", + backend="ibis", + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_TEMPORAL, + ) + return _round_datetime(x, rounding, unit, multiple) def round_calendar( self, x: IbisValueExpr, /, - rounding: Optional[str] = None, - unit: str = "1d", - origin: Optional[str] = None, + rounding: str, + unit: str, multiple: int = 1, + origin: Any = None, ) -> IbisValueExpr: - """Round datetime to a calendar unit. + """Round datetime to a multiple of a calendar time unit. - Similar to round_temporal but for calendar-aware rounding. + All nine Substrait units are in scope (calendar rounding is + unambiguous for every one, unlike round_temporal). Args: x: Datetime expression. rounding: FLOOR, CEIL, ROUND_TIE_DOWN, or ROUND_TIE_UP. - unit: Calendar unit string. - origin: Origin timestamp. - multiple: Multiple of unit. + unit: YEAR, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MILLISECOND, + or MICROSECOND. + multiple: Positive multiplier on unit. Defaults to 1. + origin: Never non-None here -- the API builder rejects it at + build time (v1 scope). Returns: Rounded datetime. - - Note: - Ibis only supports truncate. Falls back to truncate. """ - return self.round_temporal(x, rounding, unit, multiple, origin) + return _round_datetime(x, rounding, unit, multiple) diff --git a/src/mountainash/expressions/backends/expression_systems/narwhals/extensions_mountainash/expsys_nw_ext_ma_scalar_datetime.py b/src/mountainash/expressions/backends/expression_systems/narwhals/extensions_mountainash/expsys_nw_ext_ma_scalar_datetime.py index d7242812..16ebc195 100644 --- a/src/mountainash/expressions/backends/expression_systems/narwhals/extensions_mountainash/expsys_nw_ext_ma_scalar_datetime.py +++ b/src/mountainash/expressions/backends/expression_systems/narwhals/extensions_mountainash/expsys_nw_ext_ma_scalar_datetime.py @@ -454,7 +454,7 @@ def truncate( Returns: Truncated datetime. """ - return x.dt.truncate(unit) + return self._round(x, "FLOOR", unit) def round_dt( self, @@ -470,12 +470,8 @@ def round_dt( Returns: Rounded datetime. - - Note: - Narwhals may not have round. Falls back to truncate. """ - # Narwhals doesn't have round - fallback to truncate - return x.dt.truncate(unit) + return self._round(x, "ROUND_TIE_UP", unit) def ceil_dt( self, @@ -491,12 +487,8 @@ def ceil_dt( Returns: Ceiling datetime. - - Note: - Narwhals doesn't have ceil. Falls back to truncate. """ - # Narwhals doesn't have ceil - fallback to truncate - return x.dt.truncate(unit) + return self._round(x, "CEIL", unit) def floor_dt( self, @@ -513,7 +505,23 @@ def floor_dt( Returns: Floor datetime. """ - return x.dt.truncate(unit) + # Floor is the same as truncate. + return self._round(x, "FLOOR", unit) + + def _round(self, x: NarwhalsExpr, rounding: str, unit: str) -> NarwhalsExpr: + """Redirect through the real round_temporal/round_calendar + implementation (item 74). `unit` is already normalize_unit()'d and + validate_ma_option()'d by the builder before it reaches here.""" + from mountainash.expressions.core.expression_api.api_builders.extensions_mountainash._ma_option_domains import parse_ma_unit + + multiple, canonical_unit, family = parse_ma_unit(unit) + if family == "calendar": + return self.round_calendar( + x, rounding=rounding, unit=canonical_unit, multiple=multiple + ) + return self.round_temporal( + x, rounding=rounding, unit=canonical_unit, multiple=multiple + ) # ========================================================================= # Timezone Methods diff --git a/src/mountainash/expressions/backends/expression_systems/narwhals/substrait/expsys_nw_scalar_datetime.py b/src/mountainash/expressions/backends/expression_systems/narwhals/substrait/expsys_nw_scalar_datetime.py index 20e8afb6..f7a38ef6 100644 --- a/src/mountainash/expressions/backends/expression_systems/narwhals/substrait/expsys_nw_scalar_datetime.py +++ b/src/mountainash/expressions/backends/expression_systems/narwhals/substrait/expsys_nw_scalar_datetime.py @@ -10,7 +10,7 @@ CALENDAR_COMPONENTS, DatetimeComponent, ) -from typing import TYPE_CHECKING, Optional +from typing import Any, TYPE_CHECKING import narwhals as nw @@ -22,6 +22,48 @@ from mountainash.expressions.types import NarwhalsExpr +# round_temporal's in-scope units (v1): YEAR/MONTH/WEEK are declared +# UNSUPPORTED there (ambiguous fixed-duration length) -- round_calendar +# covers YEAR/MONTH but also declares WEEK unsupported (narwhals dt.truncate +# rejects "1w" on both dialects). +_ROUND_TEMPORAL_UNITS = frozenset( + {"DAY", "HOUR", "MINUTE", "SECOND", "MILLISECOND", "MICROSECOND"} +) + +# Substrait canonical unit name -> Polars-style duration-string suffix. +# Narwhals dt.truncate/dt.offset_by use the same combined "" +# format as Polars (verified against narwhals 2.24.0 on both dialects) -- +# bare Substrait names ("YEAR") are NOT accepted, unlike ibis. +_NARWHALS_UNIT_SUFFIX = { + "YEAR": "y", "MONTH": "mo", "DAY": "d", + "HOUR": "h", "MINUTE": "m", "SECOND": "s", + "MILLISECOND": "ms", "MICROSECOND": "us", +} + + +def _round_datetime(x: NarwhalsExpr, rounding: str, unit: str, multiple: int) -> NarwhalsExpr: + """Shared round_temporal/round_calendar implementation (unit != WEEK). + + Narwhals has no native round/ceil/tie primitive at all -- every mode + but FLOOR is hand-rolled from dt.truncate + dt.offset_by + duration + comparison via total_seconds() (verified against narwhals 2.24.0 on + both narwhals-polars and narwhals-pandas, including calendar units and + multiple > 1, e.g. "3mo" for a quarter). + """ + every = f"{multiple}{_NARWHALS_UNIT_SUFFIX[unit]}" + floor = x.dt.truncate(every) + if rounding == "FLOOR": + return floor + ceiling = nw.when(floor == x).then(x).otherwise(floor.dt.offset_by(every)) + if rounding == "CEIL": + return ceiling + diff_down = (x - floor).dt.total_seconds() + diff_up = (ceiling - x).dt.total_seconds() + if rounding == "ROUND_TIE_UP": + return nw.when(diff_up <= diff_down).then(ceiling).otherwise(floor) + # ROUND_TIE_DOWN: nearest, tying to the earlier point on equidistance. + return nw.when(diff_down <= diff_up).then(floor).otherwise(ceiling) + class SubstraitNarwhalsScalarDatetimeExpressionSystem(NarwhalsBaseExpressionSystem, SubstraitScalarDatetimeExpressionSystemProtocol[nw.Expr]): """Narwhals implementation of ScalarDatetimeExpressionProtocol. @@ -391,53 +433,78 @@ def round_temporal( self, x: NarwhalsExpr, /, - rounding: Optional[str] = None, - unit: str = "1d", + rounding: str, + unit: str, multiple: int = 1, - origin: Optional[str] = None, + origin: Any = None, ) -> NarwhalsExpr: - """Round datetime to a multiple of a time unit. + """Round datetime to a multiple of a fixed-duration time unit. Args: x: Datetime expression. rounding: FLOOR, CEIL, ROUND_TIE_DOWN, or ROUND_TIE_UP. - unit: Time unit string. - multiple: Multiple of unit (default 1). - origin: Origin timestamp for rounding. + unit: One of DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND. + YEAR/MONTH/WEEK are declared UNSUPPORTED here (ambiguous + fixed-duration length; see capabilities/datetime/rounding.py) + -- the raise below is defence in depth. + multiple: Positive multiplier on unit. Defaults to 1. + origin: Never non-None here -- the API builder rejects it at + build time (v1 scope). Returns: Rounded datetime. - - Note: - Narwhals only supports truncate. Falls back to truncate for all modes. """ - # Narwhals only has truncate - use for all rounding modes - return x.dt.truncate(unit) + if unit not in _ROUND_TEMPORAL_UNITS: + from mountainash.core.types import BackendCapabilityError + from mountainash.expressions.core.expression_system.function_keys.enums import ( + FKEY_SUBSTRAIT_SCALAR_DATETIME, + ) + + raise BackendCapabilityError( + f"round_temporal unit={unit!r} is not supported -- fixed-duration " + "rounding is ambiguous for YEAR/MONTH/WEEK; use round_calendar", + backend="narwhals", + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_TEMPORAL, + ) + return _round_datetime(x, rounding, unit, multiple) def round_calendar( self, x: NarwhalsExpr, /, - rounding: Optional[str] = None, - unit: str = "1d", - origin: Optional[str] = None, + rounding: str, + unit: str, multiple: int = 1, + origin: Any = None, ) -> NarwhalsExpr: - """Round datetime to a calendar unit. - - Similar to round_temporal but for calendar-aware rounding. + """Round datetime to a multiple of a calendar time unit. Args: x: Datetime expression. rounding: FLOOR, CEIL, ROUND_TIE_DOWN, or ROUND_TIE_UP. - unit: Calendar unit string. - origin: Origin timestamp. - multiple: Multiple of unit. + unit: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, or + MICROSECOND. WEEK is declared UNSUPPORTED (narwhals' + ``dt.truncate`` rejects the "1w" duration on both dialects, + verified 2026-08-16 -- matches the existing MA + truncate/floor_dt "1w" gap in capabilities/datetime/options.py) + -- the raise below is defence in depth. + multiple: Positive multiplier on unit. Defaults to 1. + origin: Never non-None here -- the API builder rejects it at + build time (v1 scope). Returns: Rounded datetime. - - Note: - Narwhals only supports truncate. Falls back to truncate. """ - return self.round_temporal(x, rounding, unit, multiple, origin) + if unit == "WEEK": + from mountainash.core.types import BackendCapabilityError + from mountainash.expressions.core.expression_system.function_keys.enums import ( + FKEY_SUBSTRAIT_SCALAR_DATETIME, + ) + + raise BackendCapabilityError( + "round_calendar unit='WEEK' is not supported on narwhals -- " + "dt.truncate rejects the '1w' duration on both dialects", + backend="narwhals", + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_CALENDAR, + ) + return _round_datetime(x, rounding, unit, multiple) diff --git a/src/mountainash/expressions/backends/expression_systems/polars/extensions_mountainash/expsys_pl_ext_ma_scalar_datetime.py b/src/mountainash/expressions/backends/expression_systems/polars/extensions_mountainash/expsys_pl_ext_ma_scalar_datetime.py index c962c667..54a23edb 100644 --- a/src/mountainash/expressions/backends/expression_systems/polars/extensions_mountainash/expsys_pl_ext_ma_scalar_datetime.py +++ b/src/mountainash/expressions/backends/expression_systems/polars/extensions_mountainash/expsys_pl_ext_ma_scalar_datetime.py @@ -420,7 +420,7 @@ def truncate( Returns: Truncated datetime. """ - return x.dt.truncate(unit) + return self._round(x, "FLOOR", unit) def round_dt( self, @@ -437,7 +437,7 @@ def round_dt( Returns: Rounded datetime. """ - return x.dt.round(unit) + return self._round(x, "ROUND_TIE_UP", unit) def ceil_dt( self, @@ -454,10 +454,7 @@ def ceil_dt( Returns: Ceiling datetime. """ - # Polars doesn't have ceil for datetime, use truncate + add - truncated = x.dt.truncate(unit) - # If truncated != original, add one unit - return pl.when(truncated == x).then(x).otherwise(truncated.dt.offset_by(unit)) + return self._round(x, "CEIL", unit) def floor_dt( self, @@ -474,8 +471,23 @@ def floor_dt( Returns: Floor datetime. """ - # Floor is the same as truncate - return x.dt.truncate(unit) + # Floor is the same as truncate. + return self._round(x, "FLOOR", unit) + + def _round(self, x: PolarsExpr, rounding: str, unit: str) -> PolarsExpr: + """Redirect through the real round_temporal/round_calendar + implementation (item 74). `unit` is already normalize_unit()'d and + validate_ma_option()'d by the builder before it reaches here.""" + from mountainash.expressions.core.expression_api.api_builders.extensions_mountainash._ma_option_domains import parse_ma_unit + + multiple, canonical_unit, family = parse_ma_unit(unit) + if family == "calendar": + return self.round_calendar( + x, rounding=rounding, unit=canonical_unit, multiple=multiple + ) + return self.round_temporal( + x, rounding=rounding, unit=canonical_unit, multiple=multiple + ) # ========================================================================= # Timezone Methods diff --git a/src/mountainash/expressions/backends/expression_systems/polars/substrait/expsys_pl_scalar_datetime.py b/src/mountainash/expressions/backends/expression_systems/polars/substrait/expsys_pl_scalar_datetime.py index ee21b515..4cf4ccc0 100644 --- a/src/mountainash/expressions/backends/expression_systems/polars/substrait/expsys_pl_scalar_datetime.py +++ b/src/mountainash/expressions/backends/expression_systems/polars/substrait/expsys_pl_scalar_datetime.py @@ -10,17 +10,57 @@ CALENDAR_COMPONENTS, DatetimeComponent, ) -from typing import TYPE_CHECKING, Optional +from typing import Any, TYPE_CHECKING, Optional import polars as pl from ..base import PolarsBaseExpressionSystem from mountainash.expressions.core.expression_protocols.expression_systems.substrait import SubstraitScalarDatetimeExpressionSystemProtocol - if TYPE_CHECKING: from mountainash.expressions.types import PolarsExpr +# Substrait canonical unit name -> Polars duration-string suffix. Combined +# with an integer multiplier (e.g. "2d", "3h", "1mo") this is accepted +# natively by Polars' dt.truncate/dt.round/dt.offset_by -- verified against +# polars 1.43.2 (item 74). +_POLARS_UNIT_SUFFIX = { + "YEAR": "y", "MONTH": "mo", "WEEK": "w", "DAY": "d", + "HOUR": "h", "MINUTE": "m", "SECOND": "s", + "MILLISECOND": "ms", "MICROSECOND": "us", +} + +# round_temporal's in-scope units (v1): YEAR/MONTH/WEEK are declared +# UNSUPPORTED there (ambiguous fixed-duration length) -- round_calendar +# covers all nine. +_ROUND_TEMPORAL_UNITS = frozenset( + {"DAY", "HOUR", "MINUTE", "SECOND", "MILLISECOND", "MICROSECOND"} +) + + +def _round_datetime(x: PolarsExpr, rounding: str, unit: str, multiple: int) -> PolarsExpr: + """Shared round_temporal/round_calendar implementation. + + FLOOR/CEIL/ROUND_TIE_DOWN are hand-rolled from dt.truncate + dt.offset_by + (Polars has no native CEIL or tie-down primitive). ROUND_TIE_UP uses + Polars' native dt.round -- verified empirically (2026-08-16) that its + tie rule IS tie-up (10:30 -> 11:00, not 10:00) and that it accepts every + combined multiplier/unit string used here, including calendar units. + """ + every = f"{multiple}{_POLARS_UNIT_SUFFIX[unit]}" + floor = x.dt.truncate(every) + if rounding == "FLOOR": + return floor + if rounding == "ROUND_TIE_UP": + return x.dt.round(every) + ceiling = pl.when(floor == x).then(x).otherwise(floor.dt.offset_by(every)) + if rounding == "CEIL": + return ceiling + # ROUND_TIE_DOWN: nearest, tying to the earlier point on equidistance. + diff_down = x - floor + diff_up = ceiling - x + return pl.when(diff_down <= diff_up).then(floor).otherwise(ceiling) + class SubstraitPolarsScalarDatetimeExpressionSystem(PolarsBaseExpressionSystem, SubstraitScalarDatetimeExpressionSystemProtocol[pl.Expr]): """Polars implementation of ScalarDatetimeExpressionProtocol. @@ -396,56 +436,67 @@ def round_temporal( self, x: PolarsExpr, /, - rounding: Optional[str] = None, - unit: str = "1d", + rounding: str, + unit: str, multiple: int = 1, - origin: Optional[str] = None, + origin: Any = None, ) -> PolarsExpr: - """Round datetime to a multiple of a time unit. + """Round datetime to a multiple of a fixed-duration time unit. Args: x: Datetime expression. rounding: FLOOR, CEIL, ROUND_TIE_DOWN, or ROUND_TIE_UP. - unit: Time unit string. - multiple: Multiple of unit (default 1). - origin: Origin timestamp for rounding. + unit: One of DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND. + YEAR/MONTH/WEEK are declared UNSUPPORTED here (ambiguous + fixed-duration length; see capabilities/datetime/rounding.py) + -- the raise below is defence in depth, the real gate is the + capability fact. + multiple: Positive multiplier on unit. Defaults to 1. + origin: Never non-None here -- the API builder rejects it at + build time (v1 scope; real Substrait origin is an + arguments-channel value, not a string option). Returns: Rounded datetime. """ - rounding = rounding if rounding else "FLOOR" + if unit not in _ROUND_TEMPORAL_UNITS: + from mountainash.core.types import BackendCapabilityError + from mountainash.expressions.core.expression_system.function_keys.enums import ( + FKEY_SUBSTRAIT_SCALAR_DATETIME, + ) - if rounding == "FLOOR": - return x.dt.truncate(unit) - elif rounding == "CEIL": - truncated = x.dt.truncate(unit) - return pl.when(truncated == x).then(x).otherwise(truncated.dt.offset_by(unit)) - else: - # ROUND_TIE_DOWN, ROUND_TIE_UP - use round - return x.dt.round(unit) + raise BackendCapabilityError( + f"round_temporal unit={unit!r} is not supported -- fixed-duration " + "rounding is ambiguous for YEAR/MONTH/WEEK; use round_calendar", + backend="polars", + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_TEMPORAL, + ) + return _round_datetime(x, rounding, unit, multiple) def round_calendar( self, x: PolarsExpr, /, - rounding: Optional[str] = None, - unit: str = "1d", - origin: Optional[str] = None, + rounding: str, + unit: str, multiple: int = 1, + origin: Any = None, ) -> PolarsExpr: - """Round datetime to a calendar unit. + """Round datetime to a multiple of a calendar time unit. - Similar to round_temporal but for calendar-aware rounding. + All nine Substrait units are in scope (calendar rounding is + unambiguous for every one, unlike round_temporal). Args: x: Datetime expression. rounding: FLOOR, CEIL, ROUND_TIE_DOWN, or ROUND_TIE_UP. - unit: Calendar unit string. - origin: Origin timestamp. - multiple: Multiple of unit. + unit: YEAR, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MILLISECOND, + or MICROSECOND. + multiple: Positive multiplier on unit. Defaults to 1. + origin: Never non-None here -- the API builder rejects it at + build time (v1 scope). Returns: Rounded datetime. """ - # For Polars, calendar rounding uses the same approach - return self.round_temporal(x, rounding, unit, multiple, origin) + return _round_datetime(x, rounding, unit, multiple) diff --git a/src/mountainash/expressions/core/expression_api/api_builders/extensions_mountainash/_ma_option_domains.py b/src/mountainash/expressions/core/expression_api/api_builders/extensions_mountainash/_ma_option_domains.py index 82af0e26..f964b36d 100644 --- a/src/mountainash/expressions/core/expression_api/api_builders/extensions_mountainash/_ma_option_domains.py +++ b/src/mountainash/expressions/core/expression_api/api_builders/extensions_mountainash/_ma_option_domains.py @@ -99,3 +99,41 @@ def validate_open_value(value_class: Any, param: str, value: Any, op: str) -> An ) return value + + +import re as _re # noqa: E402 -- module-local, avoids widening the top-level import block + +# Canonical Substrait unit each MA duration suffix maps to. "q" (quarter) +# maps to MONTH -- its multiplier is folded to a multiple-of-3 by +# parse_ma_unit below (real Substrait has no QUARTER unit; item 74 spec §3.2). +_MA_SUFFIX_TO_CANONICAL = { + "y": "YEAR", "mo": "MONTH", "q": "MONTH", "w": "WEEK", "d": "DAY", + "h": "HOUR", "m": "MINUTE", "s": "SECOND", "ms": "MILLISECOND", "us": "MICROSECOND", +} +_MA_CALENDAR_UNITS = frozenset({"YEAR", "MONTH", "WEEK"}) +_MA_UNIT_RE = _re.compile(r"^(\d+)([a-z]+)$") + + +def parse_ma_unit(value: str) -> tuple[int, str, str]: + """Parse an already-validated, alias-normalized MA duration string (e.g. + "2d" -> (2, "DAY", "temporal") or "1mo" -> (1, "MONTH", "calendar")) for + the round_temporal/round_calendar redirect (item 74). `value` must + already be normalize_unit()-normalized (friendly words resolved to their + duration form) and validate_ma_option()-validated (multiplier + suffix + known-legal) -- this function does not itself validate. + + "1q" (quarter) folds to (3, "MONTH", "calendar") -- multiplier composes + for multi-digit quarter input too, e.g. "2q" -> (6, "MONTH", "calendar"). + """ + match = _MA_UNIT_RE.match(value) + if match is None: + raise InvalidOptionValueError(f"cannot parse MA duration unit {value!r}") + multiplier = int(match.group(1)) + suffix = match.group(2) + canonical = _MA_SUFFIX_TO_CANONICAL.get(suffix) + if canonical is None: + raise InvalidOptionValueError(f"unknown MA duration suffix {suffix!r} in {value!r}") + if suffix == "q": + multiplier *= 3 + family = "calendar" if canonical in _MA_CALENDAR_UNITS else "temporal" + return multiplier, canonical, family diff --git a/src/mountainash/expressions/core/expression_api/api_builders/substrait/_option_domains.py b/src/mountainash/expressions/core/expression_api/api_builders/substrait/_option_domains.py index 176aaf09..b1872936 100644 --- a/src/mountainash/expressions/core/expression_api/api_builders/substrait/_option_domains.py +++ b/src/mountainash/expressions/core/expression_api/api_builders/substrait/_option_domains.py @@ -25,6 +25,16 @@ _MULTILINE = frozenset({"MULTILINE_DISABLED", "MULTILINE_ENABLED"}) _DOTALL = frozenset({"DOTALL_DISABLED", "DOTALL_ENABLED"}) +# Temporal-rounding option domains (round_temporal/round_calendar, item 74). +# Distinct from _ROUNDING (arithmetic tie-breaking) -- these are the four +# Substrait rounding directions for datetime bucket rounding. _ROUND_UNITS is +# the single shared 9-unit closed domain both ops accept at build time (real +# Substrait gives them the identical domain -- there is no per-op split). +_TEMPORAL_ROUNDING_MODES = frozenset({"FLOOR", "CEIL", "ROUND_TIE_DOWN", "ROUND_TIE_UP"}) +_ROUND_UNITS = frozenset({ + "YEAR", "MONTH", "WEEK", "DAY", "HOUR", "MINUTE", "SECOND", "MILLISECOND", "MICROSECOND", +}) + # Generated from Substrait v0.98.0, commit # b322d463804660674e43c9d2b659730375e3026e. The pinned-fixture guard owns # drift detection; runtime code must never read from tests/. @@ -110,6 +120,13 @@ ("extract", "component"): frozenset(c.value for c in DatetimeComponent), ("extract", "indexing"): frozenset({"ONE", "ZERO"}), ("extract_boolean", "component"): frozenset(c.value for c in BooleanComponent), + # Temporal rounding (item 74) -- real Substrait shared 9-unit domain, + # verified against functions_datetime.yaml (no per-op split; origin is + # excluded here entirely, it is an arguments-channel parameter in v1). + ("round_temporal", "rounding"): _TEMPORAL_ROUNDING_MODES, + ("round_temporal", "unit"): _ROUND_UNITS, + ("round_calendar", "rounding"): _TEMPORAL_ROUNDING_MODES, + ("round_calendar", "unit"): _ROUND_UNITS, } diff --git a/src/mountainash/expressions/core/expression_api/api_builders/substrait/api_bldr_scalar_datetime.py b/src/mountainash/expressions/core/expression_api/api_builders/substrait/api_bldr_scalar_datetime.py index eb80c39a..3773ce88 100644 --- a/src/mountainash/expressions/core/expression_api/api_builders/substrait/api_bldr_scalar_datetime.py +++ b/src/mountainash/expressions/core/expression_api/api_builders/substrait/api_bldr_scalar_datetime.py @@ -214,3 +214,88 @@ def add_intervals( arguments=[self._node, y_node], ) return self._build(node) + + def round_temporal( + self, + rounding: str, + unit: str, + multiple: int = 1, + origin: Any = None, + ) -> BaseExpressionAPI: + """Round to a multiple of a fixed-duration time unit (Substrait: round_temporal). + + Args: + rounding: One of ``"FLOOR"``, ``"CEIL"``, ``"ROUND_TIE_DOWN"``, + ``"ROUND_TIE_UP"``. + unit: Closed Substrait unit domain (``YEAR``..``MICROSECOND``, + shared with ``round_calendar``). ``YEAR``/``MONTH``/``WEEK`` + build here but are ``declared_unsupported`` at the capability + layer in v1 (fixed-duration rounding is ambiguous for them). + multiple: Positive multiplier on ``unit``. Defaults to 1. + origin: Not supported in v1 -- real Substrait types this as an + ``arguments``-channel value (same type as the receiver), not + a string option; a non-``None`` value always raises. + """ + from mountainash.core.errors import InvalidOptionValueError + from ._option_domains import validate_option + + _reject_expression("rounding", rounding, "round_temporal") + _reject_expression("unit", unit, "round_temporal") + rounding = validate_option("round_temporal", "rounding", rounding) + unit = validate_option("round_temporal", "unit", unit) + if not isinstance(multiple, int) or isinstance(multiple, bool) or multiple < 1: + raise InvalidOptionValueError( + "round_temporal multiple must be a positive int (>= 1)" + ) + if origin is not None: + raise InvalidOptionValueError( + "round_temporal origin is not supported in this implementation" + ) + node = ScalarFunctionNode( + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_TEMPORAL, + arguments=[self._node], + options={"rounding": rounding, "unit": unit, "multiple": multiple}, + ) + return self._build(node) + + def round_calendar( + self, + rounding: str, + unit: str, + multiple: int = 1, + origin: Any = None, + ) -> BaseExpressionAPI: + """Round to a multiple of a calendar time unit (Substrait: round_calendar). + + Args: + rounding: One of ``"FLOOR"``, ``"CEIL"``, ``"ROUND_TIE_DOWN"``, + ``"ROUND_TIE_UP"``. + unit: Closed Substrait unit domain (``YEAR``..``MICROSECOND``, + shared with ``round_temporal``). All nine units are in scope + here (calendar rounding is unambiguous for every one). + multiple: Positive multiplier on ``unit``. Defaults to 1. + origin: Not supported in v1 -- real Substrait types this as an + ``arguments``-channel value (same type as the receiver), not + a string option; a non-``None`` value always raises. + """ + from mountainash.core.errors import InvalidOptionValueError + from ._option_domains import validate_option + + _reject_expression("rounding", rounding, "round_calendar") + _reject_expression("unit", unit, "round_calendar") + rounding = validate_option("round_calendar", "rounding", rounding) + unit = validate_option("round_calendar", "unit", unit) + if not isinstance(multiple, int) or isinstance(multiple, bool) or multiple < 1: + raise InvalidOptionValueError( + "round_calendar multiple must be a positive int (>= 1)" + ) + if origin is not None: + raise InvalidOptionValueError( + "round_calendar origin is not supported in this implementation" + ) + node = ScalarFunctionNode( + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_CALENDAR, + arguments=[self._node], + options={"rounding": rounding, "unit": unit, "multiple": multiple}, + ) + return self._build(node) diff --git a/src/mountainash/expressions/core/expression_protocols/api_builders/substrait/prtcl_api_bldr_scalar_datetime.py b/src/mountainash/expressions/core/expression_protocols/api_builders/substrait/prtcl_api_bldr_scalar_datetime.py index 0d2fd448..6af9bc7f 100644 --- a/src/mountainash/expressions/core/expression_protocols/api_builders/substrait/prtcl_api_bldr_scalar_datetime.py +++ b/src/mountainash/expressions/core/expression_protocols/api_builders/substrait/prtcl_api_bldr_scalar_datetime.py @@ -101,3 +101,35 @@ def add_intervals( URI: https://raw.githubusercontent.com/substrait-io/substrait/main/extensions/functions_datetime.yaml """ ... + + # ============================================================ + # Rounding (Direct Substrait functions) + # ============================================================ + + def round_temporal( + self, + rounding: str, + unit: str, + multiple: int = 1, + origin: object = None, + ) -> BaseExpressionAPI: + """Round a timestamp/date/time to a multiple of a fixed-duration unit. + + Substrait: round_temporal + URI: https://raw.githubusercontent.com/substrait-io/substrait/main/extensions/functions_datetime.yaml + """ + ... + + def round_calendar( + self, + rounding: str, + unit: str, + multiple: int = 1, + origin: object = None, + ) -> BaseExpressionAPI: + """Round a timestamp/date/time to a multiple of a calendar unit. + + Substrait: round_calendar + URI: https://raw.githubusercontent.com/substrait-io/substrait/main/extensions/functions_datetime.yaml + """ + ... diff --git a/src/mountainash/expressions/core/expression_protocols/expression_systems/substrait/prtcl_expsys_scalar_datetime.py b/src/mountainash/expressions/core/expression_protocols/expression_systems/substrait/prtcl_expsys_scalar_datetime.py index fa4a3af4..b99bea90 100644 --- a/src/mountainash/expressions/core/expression_protocols/expression_systems/substrait/prtcl_expsys_scalar_datetime.py +++ b/src/mountainash/expressions/core/expression_protocols/expression_systems/substrait/prtcl_expsys_scalar_datetime.py @@ -8,7 +8,7 @@ from __future__ import annotations -from typing import Optional, Protocol +from typing import Any, Optional, Protocol from mountainash.core.types import ExpressionT @@ -182,7 +182,15 @@ def strftime(self, x: ExpressionT, /, format: str) -> ExpressionT: """ ... - def round_temporal(self, x: ExpressionT, /, rounding: Optional[str] = None, unit: str = "1d", multiple: int = 1, origin: Optional[str] = None) -> ExpressionT: + def round_temporal( + self, + x: ExpressionT, + /, + rounding: str, + unit: str, + multiple: int = 1, + origin: Any = None, + ) -> ExpressionT: """Round a given timestamp/date/time to a multiple of a time unit. If the given timestamp is not already an exact multiple from the origin in the given timezone, the resulting point is chosen as one of the two nearest multiples. Which of these is chosen is governed by rounding: FLOOR means to use the earlier one, CEIL means to use the later one, ROUND_TIE_DOWN means to choose the nearest and tie to the earlier one if equidistant, ROUND_TIE_UP means to choose the nearest and tie to the later one if equidistant. Timezone strings must be as defined by IANA timezone database (https://www.iana.org/time-zones). Examples: "Pacific/Marquesas", "Etc/GMT+1". If timezone is invalid an error is thrown. @@ -191,7 +199,15 @@ def round_temporal(self, x: ExpressionT, /, rounding: Optional[str] = None, unit """ ... - def round_calendar(self, x: ExpressionT, /, rounding: Optional[str] = None, unit: str = "1d", origin: Optional[str] = None, multiple: int = 1) -> ExpressionT: + def round_calendar( + self, + x: ExpressionT, + /, + rounding: str, + unit: str, + multiple: int = 1, + origin: Any = None, + ) -> ExpressionT: """Round a given timestamp/date/time to a multiple of a time unit. If the given timestamp is not already an exact multiple from the last origin unit in the given timezone, the resulting point is chosen as one of the two nearest multiples. Which of these is chosen is governed by rounding: FLOOR means to use the earlier one, CEIL means to use the later one, ROUND_TIE_DOWN means to choose the nearest and tie to the earlier one if equidistant, ROUND_TIE_UP means to choose the nearest and tie to the later one if equidistant. Timezone strings must be as defined by IANA timezone database (https://www.iana.org/time-zones). Examples: "Pacific/Marquesas", "Etc/GMT+1". If timezone is invalid an error is thrown. @@ -199,3 +215,4 @@ def round_calendar(self, x: ExpressionT, /, rounding: Optional[str] = None, unit URI: https://raw.githubusercontent.com/substrait-io/substrait/main/extensions/functions_datetime.yaml """ ... + diff --git a/src/mountainash/expressions/core/expression_system/function_keys/enums.py b/src/mountainash/expressions/core/expression_system/function_keys/enums.py index d080aabb..5cac0450 100644 --- a/src/mountainash/expressions/core/expression_system/function_keys/enums.py +++ b/src/mountainash/expressions/core/expression_system/function_keys/enums.py @@ -456,6 +456,10 @@ class FKEY_SUBSTRAIT_SCALAR_DATETIME(Enum): # Arithmetic ADD_INTERVALS = auto() + # Rounding + ROUND_TEMPORAL = auto() + ROUND_CALENDAR = auto() + # Migrated from mountainash namespace — catalog functions_datetime.yaml ops ASSUME_TIMEZONE = auto() STRFTIME = auto() diff --git a/src/mountainash/expressions/core/expression_system/function_mapping/definitions.py b/src/mountainash/expressions/core/expression_system/function_mapping/definitions.py index ae30e1b9..5a2710ed 100644 --- a/src/mountainash/expressions/core/expression_system/function_mapping/definitions.py +++ b/src/mountainash/expressions/core/expression_system/function_mapping/definitions.py @@ -887,6 +887,20 @@ def register_all_functions() -> None: substrait_name="add_intervals", protocol_method=SubstraitScalarDatetimeExpressionSystemProtocol.add_intervals, ), + ExpressionFunctionDef( + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_TEMPORAL, + substrait_uri=SubstraitExtension.SCALAR_DATETIME, + substrait_name="round_temporal", + options=("rounding", "unit", "multiple"), + protocol_method=SubstraitScalarDatetimeExpressionSystemProtocol.round_temporal, + ), + ExpressionFunctionDef( + function_key=FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_CALENDAR, + substrait_uri=SubstraitExtension.SCALAR_DATETIME, + substrait_name="round_calendar", + options=("rounding", "unit", "multiple"), + protocol_method=SubstraitScalarDatetimeExpressionSystemProtocol.round_calendar, + ), ] # ======================================== diff --git a/tests/core/_smoke_helpers.py b/tests/core/_smoke_helpers.py index 0d6032bb..9b2e01a3 100644 --- a/tests/core/_smoke_helpers.py +++ b/tests/core/_smoke_helpers.py @@ -46,6 +46,14 @@ def _init_smoke_overrides() -> dict[Enum, tuple[list[Any], dict[str, Any]]]: FKEY_MOUNTAINASH_SCALAR_DATETIME.TO_TIMEZONE: ([ma.col("a"), "UTC"], {}), FKEY_MOUNTAINASH_SCALAR_DATETIME.IS_DST: ([ma.col("a"), "UTC"], {}), FKEY_SUBSTRAIT_SCALAR_DATETIME.LOCAL_TIMESTAMP: ([ma.col("a"), "UTC"], {}), + FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_TEMPORAL: ( + [ma.col("a")], + {"rounding": "FLOOR", "unit": "DAY"}, + ), + FKEY_SUBSTRAIT_SCALAR_DATETIME.ROUND_CALENDAR: ( + [ma.col("a")], + {"rounding": "FLOOR", "unit": "MONTH"}, + ), } diff --git a/tests/core/test_capability_protocol_guard.py b/tests/core/test_capability_protocol_guard.py index 3491ffd5..f9a967f6 100644 --- a/tests/core/test_capability_protocol_guard.py +++ b/tests/core/test_capability_protocol_guard.py @@ -30,6 +30,7 @@ "mountainash.expressions.backends.capabilities.arithmetic", "mountainash.expressions.backends.capabilities.datetime.extract", "mountainash.expressions.backends.capabilities.datetime.options", + "mountainash.expressions.backends.capabilities.datetime.rounding", "mountainash.expressions.backends.capabilities.datetime.strptime", "mountainash.expressions.backends.capabilities.datetime.value_classes_ma", "mountainash.expressions.backends.capabilities.datetime.value_classes_substrait", @@ -125,7 +126,7 @@ def _domain_predicate(leaf: str): domains = { "string": Domain.STRING, "arithmetic": Domain.ARITHMETIC, "options": Domain.DATETIME, "strptime": Domain.DATETIME, - "extract": Domain.DATETIME, + "extract": Domain.DATETIME, "rounding": Domain.DATETIME, } want = domains[leaf] return lambda f: ( diff --git a/tests/core/test_protocol_alignment.py b/tests/core/test_protocol_alignment.py index eaabbbb3..f5d7dc00 100644 --- a/tests/core/test_protocol_alignment.py +++ b/tests/core/test_protocol_alignment.py @@ -723,8 +723,6 @@ def _alignment_category(registry_category: str, prefix: str) -> str: (SubstraitScalarDatetimeExpressionSystemProtocol, "gt"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="Datetime comparisons handled by scalar_comparison", since="2026-05-12"), (SubstraitScalarDatetimeExpressionSystemProtocol, "gte"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="Datetime comparisons handled by scalar_comparison", since="2026-05-12"), (SubstraitScalarDatetimeExpressionSystemProtocol, "strptime_time"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="No function mapping registered", since="2026-05-12"), - (SubstraitScalarDatetimeExpressionSystemProtocol, "round_temporal"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="No function mapping registered", since="2026-05-12"), - (SubstraitScalarDatetimeExpressionSystemProtocol, "round_calendar"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="No function mapping registered", since="2026-05-12"), # Substrait Scalar Geometry — not yet in function registry (SubstraitScalarGeometryExpressionSystemProtocol, "buffer"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="No function mapping registered yet", since="2026-05-12"), (SubstraitScalarGeometryExpressionSystemProtocol, "centroid"): KnownGap(gap_kind=GapKind.ASPIRATIONAL, reason="No function mapping registered yet", since="2026-05-12"), diff --git a/tests/expressions/argument_types/option_disposition.py b/tests/expressions/argument_types/option_disposition.py index 15ffb649..f050cdeb 100644 --- a/tests/expressions/argument_types/option_disposition.py +++ b/tests/expressions/argument_types/option_disposition.py @@ -277,6 +277,12 @@ class InvalidOptionRejection(NamedTuple): ("round_dt", "unit"): ("datetime",), ("ceil_dt", "unit"): ("datetime",), ("floor_dt", "unit"): ("datetime",), + # Substrait round_temporal/round_calendar (item 74) — shared 9-unit + # closed domain lives in OPTION_DOMAINS. + ("round_temporal", "unit"): ("datetime",), + ("round_temporal", "rounding"): ("float64",), + ("round_calendar", "unit"): ("datetime",), + ("round_calendar", "rounding"): ("float64",), # Datetime open-value options. ("assume_timezone", "timezone"): ("datetime",), ("to_timezone", "timezone"): ("datetime",), diff --git a/tests/expressions/argument_types/test_arg_types_datetime.py b/tests/expressions/argument_types/test_arg_types_datetime.py index e4c9c70f..934cebf3 100644 --- a/tests/expressions/argument_types/test_arg_types_datetime.py +++ b/tests/expressions/argument_types/test_arg_types_datetime.py @@ -414,6 +414,32 @@ matrix_arg_is_input=True, complex_builder=lambda cn: ma.col(cn).dt.offset_by("1d"), ), + # round_temporal.x / round_calendar.x (item 74): rounding/unit/multiple are + # fixed options (rounding/unit reclassified as options, not expression args) + # so first_scalar_build_gate() sees the same ScalarFunctionNode shape as + # to_timezone/local_timestamp above regardless of input_type. + OpSpec( + function_key=FK_DT.ROUND_TEMPORAL, + op_name="round_temporal", + build=lambda receiver, _arg: receiver.dt.round_temporal(rounding="FLOOR", unit="DAY"), + raw_arg=datetime(2026, 7, 21, 13, 37, 45, tzinfo=timezone.utc), + arg_col_name="ts", + param_name="x", + data=_TZ_MATRIX_DATA, + matrix_arg_is_input=True, + complex_builder=lambda cn: ma.col(cn).dt.offset_by("1d"), + ), + OpSpec( + function_key=FK_DT.ROUND_CALENDAR, + op_name="round_calendar", + build=lambda receiver, _arg: receiver.dt.round_calendar(rounding="FLOOR", unit="MONTH"), + raw_arg=datetime(2026, 7, 21, 13, 37, 45, tzinfo=timezone.utc), + arg_col_name="ts", + param_name="x", + data=_TZ_MATRIX_DATA, + matrix_arg_is_input=True, + complex_builder=lambda cn: ma.col(cn).dt.offset_by("1d"), + ), ] @@ -557,31 +583,24 @@ def _unit_reference_expr(op: str, build_value: str): return _unit_expr(op, _REFERENCE_VALUE_BY_BUILD[build_value]) -# (op, value) pairs HELD OUT of the ibis-duckdb honor set; declared on ibis. -# Friendly aliases inherit the same disposition as their canonical duration -# form ("quarter" -> "1q", "week" -> "1w"), per the api-builder's friendly -# normalization at validate_ma_option. -_IBIS_DUCKDB_DECLARED_DURATION = { - "truncate": {"1q", "2d", "3h"}, - "floor_dt": {"1q", "2d", "3h"}, - "round_dt": {"1y", "1mo", "1d", "1h", "1m", "1s", "1ms", "1us", "1w", "1q", "2d", "3h"}, - "ceil_dt": {"1y", "1mo", "1d", "1h", "1m", "1s", "1ms", "1us", "1w", "1q", "2d", "3h"}, -} +# ibis-duckdb (this generic "ibis" test fixture) now honors EVERY value — +# round_dt/ceil_dt redirect through the real round_temporal/round_calendar +# implementation instead of a silent-wrong truncate fallback (item 74). +# narwhals still declares only "1w" (dt.truncate rejects the week duration +# on both dialects) — now uniformly across all 4 ops, not just +# truncate/floor_dt (round_dt/ceil_dt redirect through the same +# truncate-based body and inherit the identical gap). _NARWHALS_DECLARED_DURATION = { "truncate": {"1w"}, "floor_dt": {"1w"}, - "round_dt": {"1y", "1mo", "1d", "1h", "1m", "1s", "1ms", "1us", "1w", "1q", "2d", "3h"}, - "ceil_dt": {"1y", "1mo", "1d", "1h", "1m", "1s", "1ms", "1us", "1w", "1q", "2d", "3h"}, + "round_dt": {"1w"}, + "ceil_dt": {"1w"}, } _FRIENDLY_TO_DURATION = { "year": "1y", "quarter": "1q", "month": "1mo", "week": "1w", "day": "1d", "hour": "1h", "minute": "1m", "second": "1s", "millisecond": "1ms", "microsecond": "1us", } -_IBIS_DUCKDB_DECLARED = { - op: declared | {friendly for friendly, dur in _FRIENDLY_TO_DURATION.items() if dur in declared} - for op, declared in _IBIS_DUCKDB_DECLARED_DURATION.items() -} _NARWHALS_DECLARED = { op: declared | {friendly for friendly, dur in _FRIENDLY_TO_DURATION.items() if dur in declared} for op, declared in _NARWHALS_DECLARED_DURATION.items() @@ -590,38 +609,21 @@ def _unit_reference_expr(op: str, build_value: str): def _unit_disposition(op: str, value: str, backend: str) -> str: """Mirror the verified matrix: honored or declared_unsupported per cell.""" - if backend == "polars": - return "honored" # polars honors ALL values; the matrix column - if backend == "ibis": - return "declared_unsupported" if value in _IBIS_DUCKDB_DECLARED[op] else "honored" + if backend in ("polars", "ibis"): + return "honored" # both fully honor every value now (item 74). # narwhals-polars and narwhals-pandas share the same per-dialect fact sets. return "declared_unsupported" if value in _NARWHALS_DECLARED[op] else "honored" def _unit_backing_mode(op: str, value: str, backend: str) -> str: - disp = _unit_disposition(op, value, backend) - if disp != "declared_unsupported": - return "absence" - if value in {"2d", "3h"}: - return "class" - return "exact-fallback" + return "absence" if _unit_disposition(op, value, backend) != "declared_unsupported" else "exact-fallback" def _unit_reason(op: str, value: str, backend: str) -> str: if _unit_disposition(op, value, backend) == "honored": return "native backend honors the unit on this op" - if backend == "ibis": - if value in {"2d", "3h"}: - return "ibis TimestampTruncate rejects Polars-style multiplier duration units (e.g. '2d', '3h', '12mo'); only single bare units are accepted" - if op in {"round_dt", "ceil_dt"}: - return "ibis has no native datetime round/ceil; silently falling back to truncate would return a wrong value" - return "ibis TimestampTruncate rejects the quarter unit '1q' (and its friendly alias 'quarter')" - # narwhals - if value in {"2d", "3h"}: - return "narwhals has no native datetime round/ceil; a multiplier value silently falls back to truncate and returns a wrong (down-rounded) result" - if op in {"round_dt", "ceil_dt"}: - return "narwhals has no native datetime round/ceil; silently falling back to truncate would return a wrong value" - return "narwhals truncate rejects the week unit '1w' (and its friendly alias 'week')" + # narwhals -- the only remaining declared cell (week). + return "narwhals dt.truncate rejects the week unit '1w' (and its friendly alias 'week') on both dialects" def _unit_probe(op: str, value: str, backend: str) -> OptionSpec: @@ -637,52 +639,24 @@ def _unit_probe(op: str, value: str, backend: str) -> OptionSpec: _DATETIME_UNIT_DATA, expected_discriminates=True, ) - # declared_unsupported - if backend == "ibis": - return OptionSpec( - _UNIT_OP_FKEYS[op], - "unit", - value, - "datetime", - lambda v=value: _unit_expr(op, v), - lambda v=value: _unit_reference_expr(op, v), - _DATETIME_UNIT_DATA, - expected_discriminates=True, - ) - # narwhals - canonical = _FRIENDLY_TO_DURATION.get(value, value) - if canonical == "1w": - return OptionSpec( - _UNIT_OP_FKEYS[op], - "unit", - value, - "datetime", - lambda v=value: _unit_expr(op, v), - lambda v=value: _unit_reference_expr(op, v), - _DATETIME_UNIT_DATA, - expected_discriminates=True, - ) + # declared_unsupported (narwhals, week only) return OptionSpec( _UNIT_OP_FKEYS[op], "unit", value, "datetime", lambda v=value: _unit_expr(op, v), - lambda v=value: _unit_expr(op, v), # same value → always equal + lambda v=value: _unit_reference_expr(op, v), _DATETIME_UNIT_DATA, - expected_discriminates=True, # mismatch: probe raises sentinel + expected_discriminates=True, ) def _unit_native_failure(op: str, value: str, backend: str): - if backend == "ibis": - from ibis.common.annotations import SignatureValidationError - return SignatureValidationError - # narwhals - canonical = _FRIENDLY_TO_DURATION.get(value, value) - if canonical == "1w": - return ValueError - return OptionProbeDidNotDiscriminateError + # Only reachable for narwhals' declared "1w" cell -- the MA wrapper + # redirects through round_calendar, whose own defence-in-depth raise + # (BackendCapabilityError) pre-empts narwhals' underlying raw ValueError. + return BackendCapabilityError # Per-op, per-unit HONORED result (verified by the controller Step-0 probe). @@ -797,13 +771,6 @@ def test_datetime_unit_option_honored_or_declared( for value in _ALL_UNIT_VALUES ) -OPTION_FAMILY_DEFAULT_FACT_KEYS.update( - (_UNIT_OP_FKEYS[op], "unit", value, CONST_BACKEND.IBIS, None) - for op in sorted(_UNIT_OP_FKEYS) - for value in _ALL_UNIT_VALUES - if value in _IBIS_DUCKDB_DECLARED[op] and value not in {"2d", "3h"} -) - def _datetime_unit_invalid_expr(op: str, value: str): return _unit_expr(op, value) diff --git a/tests/expressions/argument_types/test_coverage_guard.py b/tests/expressions/argument_types/test_coverage_guard.py index e18df9f3..921134a1 100644 --- a/tests/expressions/argument_types/test_coverage_guard.py +++ b/tests/expressions/argument_types/test_coverage_guard.py @@ -94,6 +94,49 @@ def _is_dst_returns_constant_false() -> bool: return all(v is False for v in out["d"].to_list()) +def _round_temporal_calendar_still_works() -> bool: + """round_temporal/round_calendar are real, cross-backend-tested + implementations (item 74) covered by a dedicated plain pytest file + rather than this module's disposition matrix. Build a column and + confirm the call still succeeds on Polars (the reference backend). + Returns False if this op ever regresses back to broken -- the parked + reason claiming coverage exists elsewhere would then need re-examining.""" + from datetime import datetime + + import polars as pl + + import mountainash as ma + + df = pl.DataFrame({"ts": [datetime(2026, 7, 21, 13, 37, 45)]}) + try: + ma.relation(df).with_columns( + ma.col("ts").dt.round_temporal(rounding="FLOOR", unit="DAY").name.alias("d") + ).to_polars() + return True + except Exception: + return False + + +def _round_origin_always_rejected() -> bool: + """origin is permanently excluded from round_temporal/round_calendar in v1 + -- any non-None value must always raise InvalidOptionValueError at build + time, on every backend, forever. Returns False if this is ever no longer + true (origin becomes wired to a real value channel).""" + import mountainash as ma + from mountainash.core.errors import InvalidOptionValueError + + for build in ( + lambda: ma.col("ts").dt.round_temporal(rounding="FLOOR", unit="DAY", origin="2026-01-01"), + lambda: ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="MONTH", origin="2026-01-01"), + ): + try: + build() + return False + except InvalidOptionValueError: + continue + return True + + def _collect_tested_params() -> set[tuple[str, str]]: return {(ref.op_name, ref.param_name) for ref in _collect_tested_param_refs()} @@ -546,8 +589,6 @@ def test_collect_option_param_taxonomy_rejects_conflicting_duplicates(monkeypatc ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'lte', 'y'), ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'multiply', 'x'), ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'multiply', 'y'), - ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'round_calendar', 'x'), - ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'round_temporal', 'x'), ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'strftime', 'x'), ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'strptime_date', 'x'), ('test_arg_types_datetime', 'SubstraitScalarDatetimeExpressionSystemProtocol', 'strptime_time', 'x'), @@ -805,12 +846,7 @@ def test_collect_option_param_taxonomy_rejects_conflicting_duplicates(monkeypatc } # Datetime option params — retagged with precise, backlog-linked reasons (PR-C). -# Missing-op params: the operation is not exposed by the API builder, so the option -# cannot be wired until the op exists. Ops in scope: extract, round_calendar, -# round_temporal, strptime_time. (strptime_date and strptime_timestamp are -# drained by the disposition matrix in test_arg_types_datetime.py; their -# respective parks are removed below and their timezone park is re-keyed with -# its real reason rather than the shared "operation not implemented" lie.) +# strptime_time is still genuinely unimplemented in the API builder. _KNOWN_UNTESTED_OPTION_PARAMS.update( { key: KnownGap( @@ -822,18 +858,100 @@ def test_collect_option_param_taxonomy_rejects_conflicting_duplicates(monkeypatc since="2026-07-25", ) for key in { - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "multiple"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "origin"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "rounding"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "unit"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "multiple"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "origin"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "rounding"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "unit"), ("SubstraitScalarDatetimeExpressionSystemProtocol", "strptime_time", "format"), } } ) +# round_temporal/round_calendar (item 74): rounding/unit/multiple ARE real, +# fully implemented, and cross-backend tested -- but via a dedicated plain +# pytest file (tests/expressions/cross_backend/test_datetime_rounding.py), +# not via this module's OPTION_DISPOSITIONS/param_taxonomy machinery (that +# would require building a full per-value disposition matrix mirroring +# truncate/round_dt/ceil_dt/floor_dt's _unit_* helpers above, out of scope +# for this PR). origin is permanently excluded from v1 (real Substrait +# types it as an arguments-channel value, not a string option; any +# non-None value always raises InvalidOptionValueError at build time +# regardless of backend) -- it has no legal value to ever test. +_KNOWN_UNTESTED_OPTION_PARAMS.update( + { + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "multiple"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "tested via a dedicated cross-backend test file, not this " + "module's disposition matrix — see backlog: " + "round-temporal-calendar-real-implementation" + ), + since="2026-08-16", + ), + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "rounding"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "tested via a dedicated cross-backend test file, not this " + "module's disposition matrix — see backlog: " + "round-temporal-calendar-real-implementation" + ), + since="2026-08-16", + ), + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "unit"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "tested via a dedicated cross-backend test file, not this " + "module's disposition matrix — see backlog: " + "round-temporal-calendar-real-implementation" + ), + since="2026-08-16", + ), + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "multiple"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "tested via a dedicated cross-backend test file, not this " + "module's disposition matrix — see backlog: " + "round-temporal-calendar-real-implementation" + ), + since="2026-08-16", + ), + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "rounding"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "tested via a dedicated cross-backend test file, not this " + "module's disposition matrix — see backlog: " + "round-temporal-calendar-real-implementation" + ), + since="2026-08-16", + ), + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "unit"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "tested via a dedicated cross-backend test file, not this " + "module's disposition matrix — see backlog: " + "round-temporal-calendar-real-implementation" + ), + since="2026-08-16", + ), + } +) +_KNOWN_UNTESTED_OPTION_PARAMS.update( + { + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar", "origin"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "origin is permanently excluded from v1 — real Substrait types it " + "as an arguments-channel value, not a string option; any non-None " + "value always raises InvalidOptionValueError at build time" + ), + since="2026-08-16", + ), + ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal", "origin"): KnownGap( + gap_kind=GapKind.UNTESTED_OPTION, + reason=( + "origin is permanently excluded from v1 — real Substrait types it " + "as an arguments-channel value, not a string option; any non-None " + "value always raises InvalidOptionValueError at build time" + ), + since="2026-08-16", + ), + } +) for _case_sensitivity_op in ( "contains", @@ -1010,8 +1128,6 @@ def test_collect_option_param_taxonomy_rejects_conflicting_duplicates(monkeypatc ("SubstraitScalarDatetimeExpressionSystemProtocol", "lt"), ("SubstraitScalarDatetimeExpressionSystemProtocol", "lte"), ("SubstraitScalarDatetimeExpressionSystemProtocol", "multiply"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_calendar"), - ("SubstraitScalarDatetimeExpressionSystemProtocol", "round_temporal"), ("SubstraitScalarDatetimeExpressionSystemProtocol", "strptime_time"), ("SubstraitScalarDatetimeExpressionSystemProtocol", "subtract"), ("SubstraitScalarLogarithmicExpressionSystemProtocol", "ln"), @@ -1037,6 +1153,19 @@ def test_collect_option_param_taxonomy_rejects_conflicting_duplicates(monkeypatc ), since="2026-07-30", ) +for _wired_round_op in ("round_temporal", "round_calendar"): + _KNOWN_UNWIRED_TESTED_OPS[ + ("SubstraitScalarDatetimeExpressionSystemProtocol", _wired_round_op) + ] = KnownGap( + gap_kind=GapKind.OTHER, + reason=( + "protocol_method IS registered and the op IS API-reachable (item 74, " + "Task 1-3); the entry is retained only because the legacy plain-string " + "TESTED_PARAMS key (predating the real OP_SPEC entry) forces " + "registry_wired=False" + ), + since="2026-08-16", + ) _KNOWN_UNRESOLVED_TESTED_PARAMS: dict[tuple[str, str], KnownGap] = { @@ -1716,6 +1845,12 @@ def test_untested_option_param_custom_reasons_still_hold(): elif "placeholder stub" in r: if not _is_dst_returns_constant_false(): reason_false.append(((proto, op, param), "is_dst no longer returns constant False")) + elif "tested via a dedicated cross-backend test file" in r: + if not _round_temporal_calendar_still_works(): + reason_false.append(((proto, op, param), "round_temporal/round_calendar no longer works — its dedicated test file coverage claim needs re-examining")) + elif "origin is permanently excluded from v1" in r: + if not _round_origin_always_rejected(): + reason_false.append(((proto, op, param), "round_temporal/round_calendar origin no longer always raises")) else: unclassified.append(((proto, op, param), r)) diff --git a/tests/expressions/argument_types/test_option_fact_integrity.py b/tests/expressions/argument_types/test_option_fact_integrity.py index 9f93d191..44efa6fa 100644 --- a/tests/expressions/argument_types/test_option_fact_integrity.py +++ b/tests/expressions/argument_types/test_option_fact_integrity.py @@ -51,7 +51,9 @@ ) from mountainash.core.constants import CONST_BACKEND from mountainash.expressions.core.expression_system.function_keys.enums import ( + FKEY_MOUNTAINASH_SCALAR_DATETIME as FK_MA_DT, FKEY_SUBSTRAIT_SCALAR_ARITHMETIC as FK_ARITH, + FKEY_SUBSTRAIT_SCALAR_DATETIME as FK_SUB_DT, FKEY_SUBSTRAIT_SCALAR_STRING as FK_STR, ) from mountainash.expressions.core.expression_system.function_mapping.registry import ( @@ -234,6 +236,40 @@ def test_no_op_level_fact_is_left_unbacked() -> None: } | { (fkey, "case_sensitivity", "CASE_INSENSITIVE", CONST_BACKEND.IBIS, "ibis-sqlite") for fkey in (FK_STR.CONTAINS, FK_STR.STARTS_WITH, FK_STR.ENDS_WITH) +} | { + # item 74: truncate/round_dt/ceil_dt/floor_dt redirect through the real + # round_temporal/round_calendar implementation, which has genuine + # ibis-sqlite (sub-day units + quarter) and ibis-polars (calendar-unit + # round/ceil) gaps -- verified directly by + # TestDatetimeUnitIbisSqliteGate / TestDatetimeUnitIbisPolarsGate in + # test_arg_types_datetime.py (this matrix's "ibis" fixture is hardcoded + # to ibis-duckdb, which honors every value). + (fkey, "unit", value, CONST_BACKEND.IBIS, "ibis-sqlite") + for fkey in (FK_MA_DT.TRUNCATE, FK_MA_DT.ROUND, FK_MA_DT.CEIL, FK_MA_DT.FLOOR) + for value in ( + "1h", "1m", "1s", "1ms", "1us", "1q", + "hour", "minute", "second", "millisecond", "microsecond", "quarter", + ) +} | { + (fkey, "unit", value, CONST_BACKEND.IBIS, "ibis-polars") + for fkey in (FK_MA_DT.ROUND, FK_MA_DT.CEIL) + for value in ("1y", "1mo", "1q", "year", "month", "quarter") +} | { + # item 74: capabilities/datetime/rounding.py's direct Substrait + # round_temporal/round_calendar facts for the same two dialect gaps -- + # verified directly by test_datetime_rounding.py's + # TestRoundTemporalSqliteSubDayUnsupported / + # TestRoundCalendarPolarsMonthYearUnsupported / + # TestRoundCalendarSqliteMultipleUnsupported. + (fkey, "unit", value, CONST_BACKEND.IBIS, "ibis-sqlite") + for fkey in (FK_SUB_DT.ROUND_TEMPORAL, FK_SUB_DT.ROUND_CALENDAR) + for value in ("HOUR", "MINUTE", "SECOND", "MILLISECOND", "MICROSECOND") +} | { + (FK_SUB_DT.ROUND_TEMPORAL, "multiple", "2", CONST_BACKEND.IBIS, "ibis-sqlite"), + (FK_SUB_DT.ROUND_CALENDAR, "multiple", "3", CONST_BACKEND.IBIS, "ibis-sqlite"), +} | { + (FK_SUB_DT.ROUND_CALENDAR, "unit", value, CONST_BACKEND.IBIS, "ibis-polars") + for value in ("MONTH", "YEAR") } diff --git a/tests/expressions/cross_backend/test_datetime_rounding.py b/tests/expressions/cross_backend/test_datetime_rounding.py new file mode 100644 index 00000000..3416becc --- /dev/null +++ b/tests/expressions/cross_backend/test_datetime_rounding.py @@ -0,0 +1,283 @@ +"""Cross-backend results for dt.round_temporal / dt.round_calendar (item 74). + +Both ops share the real Substrait 9-unit domain (YEAR..MICROSECOND, no per-op +split). round_temporal declares YEAR/MONTH/WEEK UNSUPPORTED (ambiguous +fixed-duration length in v1); round_calendar covers all nine. See +2026-08-15-round-temporal-calendar-real-implementation-design.md. + +Known per-dialect gaps (2026-08-16 probe, capabilities/datetime/rounding.py): +- ibis-sqlite: TimestampTruncate has no HOUR/MINUTE/SECOND/MILLISECOND/ + MICROSECOND support, and TimestampBucket (multiple > 1) has no + compilation rule at all. +- ibis-polars: CEIL/tie modes on MONTH/YEAR need interval addition, which + ibis's polars sub-backend cannot translate (polars.duration() has no + months/years kwarg) -- the whole unit is declared UNSUPPORTED there. +""" + +from __future__ import annotations + +from datetime import datetime + +import pytest + +import mountainash as ma +from mountainash.core.capabilities import load_all_capability_declarations +from mountainash.core.types import BackendCapabilityError + +load_all_capability_declarations() + +TEMPORAL_BACKENDS = [ + "polars", + "polars-lazy", + "narwhals-polars", + "narwhals-pandas", + "ibis-duckdb", + "ibis-polars", + "ibis-sqlite", +] + +# ibis-sqlite has no HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND truncate +# support at all (capabilities/datetime/rounding.py) -- every HOUR-based +# round_temporal case below is UNSUPPORTED there. +HOUR_CAPABLE_BACKENDS = [b for b in TEMPORAL_BACKENDS if b != "ibis-sqlite"] + +# ibis-polars declares MONTH/YEAR UNSUPPORTED on round_calendar (CEIL/tie +# modes cannot translate a calendar-length interval); ibis-sqlite has no +# TimestampBucket rule, so multiple > 1 is UNSUPPORTED there for every unit. +MONTH_YEAR_CAPABLE_BACKENDS = [b for b in TEMPORAL_BACKENDS if b != "ibis-polars"] +QUARTER_MULTIPLE_CAPABLE_BACKENDS = [ + b for b in TEMPORAL_BACKENDS if b not in ("ibis-polars", "ibis-sqlite") +] + +# 2026-03-15 10:30:00 -- an exact tie point at the hour granularity (10:30:00 +# is the midpoint of [10:00, 11:00)) and non-boundary at every finer/coarser +# granularity, so FLOOR/CEIL/tie-mode all produce distinct, unambiguous +# results across DAY/HOUR and MONTH/YEAR/WEEK. +_TIE_DATA = {"ts": [datetime(2026, 3, 15, 10, 30, 0)]} +_MULTI_DATA = {"ts": [datetime(2026, 3, 15, 10, 30, 0)]} + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", TEMPORAL_BACKENDS) +class TestRoundTemporalFloorCeilDay: + """DAY is supported on every backend, including ibis-sqlite.""" + + def test_floor_day(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_temporal(rounding="FLOOR", unit="DAY") + ) + assert actual == [datetime(2026, 3, 15, 0, 0, 0)] + + def test_ceil_day(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_temporal(rounding="CEIL", unit="DAY") + ) + assert actual == [datetime(2026, 3, 16, 0, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", HOUR_CAPABLE_BACKENDS) +class TestRoundTemporalFloorCeilHour: + def test_floor_hour(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_temporal(rounding="FLOOR", unit="HOUR") + ) + assert actual == [datetime(2026, 3, 15, 10, 0, 0)] + + def test_ceil_hour(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_temporal(rounding="CEIL", unit="HOUR") + ) + assert actual == [datetime(2026, 3, 15, 11, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", HOUR_CAPABLE_BACKENDS) +class TestRoundTemporalTieBreaking: + """10:30:00 is exactly the midpoint of the [10:00, 11:00) hour bucket.""" + + def test_tie_down_ties_to_earlier(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_temporal(rounding="ROUND_TIE_DOWN", unit="HOUR") + ) + assert actual == [datetime(2026, 3, 15, 10, 0, 0)] + + def test_tie_up_ties_to_later(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_temporal(rounding="ROUND_TIE_UP", unit="HOUR") + ) + assert actual == [datetime(2026, 3, 15, 11, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", HOUR_CAPABLE_BACKENDS) +class TestRoundTemporalMultiple: + def test_floor_multiple_two_hours(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_MULTI_DATA, backend_name) + actual = collect_expr( + df, + ma.col("ts").dt.round_temporal(rounding="FLOOR", unit="HOUR", multiple=2), + ) + assert actual == [datetime(2026, 3, 15, 10, 0, 0)] + + def test_ceil_multiple_two_hours(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_MULTI_DATA, backend_name) + actual = collect_expr( + df, + ma.col("ts").dt.round_temporal(rounding="CEIL", unit="HOUR", multiple=2), + ) + assert actual == [datetime(2026, 3, 15, 12, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", TEMPORAL_BACKENDS) +class TestRoundTemporalYearMonthWeekUnsupported: + """v1 scope: round_temporal declares YEAR/MONTH/WEEK UNSUPPORTED on + every backend (ambiguous fixed-duration length); round_calendar (below) + covers them.""" + + @pytest.mark.parametrize("unit", ["YEAR", "MONTH", "WEEK"]) + def test_raises_capability_error(self, backend_name, unit, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + expr = ma.col("ts").dt.round_temporal(rounding="FLOOR", unit=unit) + with pytest.raises(BackendCapabilityError, match="round_temporal"): + collect_expr(df, expr) + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", ["ibis-sqlite"]) +class TestRoundTemporalSqliteSubDayUnsupported: + """ibis-sqlite has no HOUR/MINUTE/SECOND/MILLISECOND/MICROSECOND + TimestampTruncate support at all -- every round_temporal case above + that isn't DAY is UNSUPPORTED there.""" + + @pytest.mark.parametrize("rounding", ["FLOOR", "CEIL", "ROUND_TIE_DOWN", "ROUND_TIE_UP"]) + def test_raises_capability_error(self, backend_name, rounding, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + expr = ma.col("ts").dt.round_temporal(rounding=rounding, unit="HOUR") + with pytest.raises(BackendCapabilityError, match="sqlite"): + collect_expr(df, expr) + + +WEEK_CAPABLE_BACKENDS = [ + b for b in TEMPORAL_BACKENDS if b not in ("narwhals-polars", "narwhals-pandas") +] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", TEMPORAL_BACKENDS) +class TestRoundCalendarFloorCeilDay: + """DAY is supported on every backend.""" + + def test_floor_day(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="DAY") + ) + assert actual == [datetime(2026, 3, 15, 0, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", WEEK_CAPABLE_BACKENDS) +class TestRoundCalendarFloorCeilWeek: + """narwhals dt.truncate rejects the '1w' duration on both dialects.""" + + def test_floor_week(self, backend_name, backend_factory, collect_expr): + # 2026-03-15 is a Sunday; ISO week starts Monday 2026-03-09. + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="WEEK") + ) + assert actual == [datetime(2026, 3, 9, 0, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", ["narwhals-polars", "narwhals-pandas"]) +class TestRoundCalendarNarwhalsWeekUnsupported: + def test_raises_capability_error(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + expr = ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="WEEK") + with pytest.raises(BackendCapabilityError, match="round_calendar"): + collect_expr(df, expr) + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", MONTH_YEAR_CAPABLE_BACKENDS) +class TestRoundCalendarFloorCeilMonthYear: + def test_floor_month(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="MONTH") + ) + assert actual == [datetime(2026, 3, 1, 0, 0, 0)] + + def test_ceil_month(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_calendar(rounding="CEIL", unit="MONTH") + ) + assert actual == [datetime(2026, 4, 1, 0, 0, 0)] + + def test_floor_year(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="YEAR") + ) + assert actual == [datetime(2026, 1, 1, 0, 0, 0)] + + def test_ceil_year(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + actual = collect_expr( + df, ma.col("ts").dt.round_calendar(rounding="CEIL", unit="YEAR") + ) + assert actual == [datetime(2027, 1, 1, 0, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", ["ibis-polars"]) +class TestRoundCalendarPolarsMonthYearUnsupported: + @pytest.mark.parametrize("unit", ["MONTH", "YEAR"]) + def test_raises_capability_error(self, backend_name, unit, backend_factory, collect_expr): + df = backend_factory.create(_TIE_DATA, backend_name) + expr = ma.col("ts").dt.round_calendar(rounding="FLOOR", unit=unit) + with pytest.raises(BackendCapabilityError, match="polars sub-backend"): + collect_expr(df, expr) + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", QUARTER_MULTIPLE_CAPABLE_BACKENDS) +class TestRoundCalendarMultiple: + def test_floor_quarter_via_month_multiple_three( + self, backend_name, backend_factory, collect_expr + ): + df = backend_factory.create(_MULTI_DATA, backend_name) + actual = collect_expr( + df, + ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="MONTH", multiple=3), + ) + assert actual == [datetime(2026, 1, 1, 0, 0, 0)] + + def test_ceil_quarter_via_month_multiple_three( + self, backend_name, backend_factory, collect_expr + ): + df = backend_factory.create(_MULTI_DATA, backend_name) + actual = collect_expr( + df, + ma.col("ts").dt.round_calendar(rounding="CEIL", unit="MONTH", multiple=3), + ) + assert actual == [datetime(2026, 4, 1, 0, 0, 0)] + + +@pytest.mark.cross_backend +@pytest.mark.parametrize("backend_name", ["ibis-sqlite"]) +class TestRoundCalendarSqliteMultipleUnsupported: + def test_raises_capability_error(self, backend_name, backend_factory, collect_expr): + df = backend_factory.create(_MULTI_DATA, backend_name) + expr = ma.col("ts").dt.round_calendar(rounding="FLOOR", unit="MONTH", multiple=3) + with pytest.raises(BackendCapabilityError, match="TimestampBucket"): + collect_expr(df, expr) diff --git a/tests/expressions/cross_backend/test_datetime_unit_dispatch.py b/tests/expressions/cross_backend/test_datetime_unit_dispatch.py index 39495feb..8d048af8 100644 --- a/tests/expressions/cross_backend/test_datetime_unit_dispatch.py +++ b/tests/expressions/cross_backend/test_datetime_unit_dispatch.py @@ -54,19 +54,13 @@ "narwhals-pandas", ) -# (backend, op) → reason. round/ceil have no native datetime impl on ibis or narwhals -# (the silent truncate-fallback is an anti-pattern); Task 3 declares them UNSUPPORTED so -# the visitor raises a clean BackendCapabilityError. ibis floor was fixed in Task 3 -# (floor == truncate; applies the unit-mapping) and is NO LONGER divergent — its removal -# from this map was forced by the strict xfail flipping to XPASS, exactly as intended. -_KNOWN_FALLBACK_DIVERGENCES: dict[tuple[str, str], str] = { - ("ibis-duckdb", "round"): "ibis has no native datetime round; declared UNSUPPORTED -> BackendCapabilityError (Task 3)", - ("ibis-duckdb", "ceil"): "ibis has no native datetime ceil; declared UNSUPPORTED -> BackendCapabilityError (Task 3)", - ("narwhals-polars", "round"): "narwhals has no native datetime round; declared UNSUPPORTED -> BackendCapabilityError (Task 3)", - ("narwhals-polars", "ceil"): "narwhals has no native datetime ceil; declared UNSUPPORTED -> BackendCapabilityError (Task 3)", - ("narwhals-pandas", "round"): "narwhals has no native datetime round; declared UNSUPPORTED -> BackendCapabilityError (Task 3)", - ("narwhals-pandas", "ceil"): "narwhals has no native datetime ceil; declared UNSUPPORTED -> BackendCapabilityError (Task 3)", -} +# (backend, op) → reason. Historically ibis/narwhals had no native datetime +# round/ceil (silent truncate-fallback anti-pattern); item 74's round_temporal/ +# round_calendar redirect gave every backend a real implementation, so this +# map is now empty. ibis floor was fixed first (Task 3 of the earlier plan); +# round/ceil followed via item 74 — each removal was forced by the strict +# xfail flipping to XPASS, exactly as intended. +_KNOWN_FALLBACK_DIVERGENCES: dict[tuple[str, str], str] = {} @pytest.mark.cross_backend diff --git a/tests/expressions/cross_backend/test_datetime_value_class_dispatch.py b/tests/expressions/cross_backend/test_datetime_value_class_dispatch.py index 34f1b3b7..e4911ae9 100644 --- a/tests/expressions/cross_backend/test_datetime_value_class_dispatch.py +++ b/tests/expressions/cross_backend/test_datetime_value_class_dispatch.py @@ -2,22 +2,13 @@ Encodes the controller Task-5 semantic probe matrix (`.superpowers/sdd/vc-probe-matrix.md`) as an explicit regression lock — NOT a -re-probe. DURATION_MULTIPLIER (integer unit multipliers >= 2, e.g. "2d"/"3h"/ -"12mo") and IANA_TIMEZONE (`assume_timezone`) value-class facts must gate the +re-probe. IANA_TIMEZONE (`assume_timezone`) value-class facts must gate the declared (op, backend) cells with a clean ``BackendCapabilityError``, while honored cells compile and evaluate. Probe matrix (every value in each cell AGREES — no partial/disagree cells, so there are no xfails here): - DURATION_MULTIPLIER - - ibis (ibis-duckdb): RAISED on truncate / round / ceil / floor (all four) - — TimestampTruncate rejects the Polars-style duration form. - - narwhals-{polars,pandas}: SILENTLY-WRONG on round / ceil (no native - datetime round/ceil -> truncate fallback) — DECLARED; HONORED on - truncate / floor. - - polars: honored on all four. - IANA_TIMEZONE :: assume_timezone - ibis + both narwhals dialects: SILENTLY-WRONG (drop the tz, return a naive timestamp) — DECLARED. @@ -27,6 +18,14 @@ option is non-functional, so it carries NO value-class fact and stays parked (see backlog: is_dst-placeholder-implementation). `offset_by` and `strftime` are honored on every fixture — no facts. + +DURATION_MULTIPLIER (integer unit multipliers >= 2, e.g. "2d"/"3h"/"12mo") +facts and this file's former `test_multiplier_gate` regression were RETIRED +by item 74: truncate/round_dt/ceil_dt/floor_dt now redirect through the real +round_temporal/round_calendar implementation instead of a silent-wrong +truncate fallback, so every fixture honors every multiplier value (see +`src/mountainash/expressions/backends/capabilities/datetime/value_classes_ma.py` +module docstring for the re-probed disposition table). """ from __future__ import annotations @@ -46,7 +45,6 @@ from mountainash.core.constants import CONST_BACKEND from mountainash.core.types import BackendCapabilityError from mountainash.expressions.core.expression_system.function_keys.enums import ( - FKEY_MOUNTAINASH_SCALAR_DATETIME as M, FKEY_SUBSTRAIT_SCALAR_DATETIME as S, ) @@ -59,22 +57,9 @@ # (fkey, param, backend, dialect, value_class) tuples that MUST resolve to an # UNSUPPORTED value-class fact. ibis carries a family-default (dialect=None) AND # an ibis-duckdb fact; narwhals is per-dialect only. -_MULT = ValueClass.DURATION_MULTIPLIER _TZ = ValueClass.IANA_TIMEZONE EXPECTED_DECLARED_CLASS_FACTS = [ - # ibis multiplier: all four rounding ops, family default + duckdb - *[ - (fkey, "unit", CONST_BACKEND.IBIS, dialect, _MULT) - for fkey in (M.TRUNCATE, M.ROUND, M.CEIL, M.FLOOR) - for dialect in (None, "ibis-duckdb") - ], - # narwhals multiplier: round/ceil only, per-dialect - *[ - (fkey, "unit", CONST_BACKEND.NARWHALS, dialect, _MULT) - for fkey in (M.ROUND, M.CEIL) - for dialect in ("narwhals-polars", "narwhals-pandas") - ], # assume_timezone IANA: ibis family default + duckdb; narwhals per-dialect *[ (S.ASSUME_TIMEZONE, "timezone", CONST_BACKEND.IBIS, dialect, _TZ) @@ -87,7 +72,6 @@ ] _REPRESENTATIVE_VALUE = { - _MULT: "2d", _TZ: "Australia/Sydney", } @@ -105,37 +89,6 @@ def test_declared_class_cells_have_facts(): # --- Cross-backend production regression ---------------------------------- -# (backend, public-op) cells the multiplier class DECLARES unsupported. -_MULT_DECLARED = { - ("ibis-duckdb", "truncate"), - ("ibis-duckdb", "round"), - ("ibis-duckdb", "ceil"), - ("ibis-duckdb", "floor"), - ("narwhals-polars", "round"), - ("narwhals-polars", "ceil"), - ("narwhals-pandas", "round"), - ("narwhals-pandas", "ceil"), -} - - -@pytest.mark.cross_backend -@pytest.mark.parametrize("backend_name", ALL_BACKENDS) -@pytest.mark.parametrize("op", ["truncate", "round", "ceil", "floor"]) -@pytest.mark.parametrize("value", ["2d", "3h"]) -def test_multiplier_gate(backend_factory, collect_expr, backend_name, op, value): - """A multiplier on a declared (backend, op) raises BackendCapabilityError at - compile (NOT a silent truncate / raw backend error); an honored cell - evaluates to a datetime.""" - df = backend_factory.create({"ts": [_TS]}, backend_name) - expr = getattr(ma.col("ts").dt, op)(value) - if (backend_name, op) in _MULT_DECLARED: - with pytest.raises(BackendCapabilityError): - collect_expr(df, expr, alias="r") - else: - got = collect_expr(df, expr, alias="r") - assert isinstance(got[0], datetime) - - @pytest.mark.cross_backend @pytest.mark.parametrize("backend_name", ALL_BACKENDS) @pytest.mark.parametrize("tz", ["UTC", "Australia/Sydney"])