Skip to content

fix(capabilities): gate ibis-sqlite MA multiplier durations — clean BackendCapabilityError (item 99) - #301

Merged
discreteds merged 4 commits into
developfrom
bugfix/ibis-sqlite-timestampbucket-raw-error-leak
Aug 18, 2026
Merged

fix(capabilities): gate ibis-sqlite MA multiplier durations — clean BackendCapabilityError (item 99)#301
discreteds merged 4 commits into
developfrom
bugfix/ibis-sqlite-timestampbucket-raw-error-leak

Conversation

@discreteds

Copy link
Copy Markdown
Member

Summary

Closes backlog item 99: the last raw-error leak in the datetime rounding surface.

dt.truncate("2d") / round_dt("3h") / ceil_dt("12mo") / floor_dt("2w") on ibis-sqlite reached ibis's TimestampBucket (multiple > 1), which has no sqlite compilation rule — raising a raw native OperationNotDefinedError instead of the clean BackendCapabilityError the capability spine promises. Every other backend/dialect honored the multiplier or raised the declared error; ibis-sqlite was the sole silent leak.

Root cause

  • The MA api-builder stores only the raw duration string in the node's unit option ("2d"); the multiplier is derived later by the backend body via parse_ma_unit. There is no multiple option on the MA node.
  • The visitor's option gate resolves capability_for(MA_FKEY, "unit", ..., option_value="2d"). The existing ibis-sqlite facts in capabilities/datetime/options.py are exact-value facts for the single-unit domain ("1h", "1q", …) — "2d" matched nothing, so the call passed through to x.bucket().
  • The direct Substrait ops (round_temporal/round_calendar) already gate multiple on ibis-sqlite (rounding.py); only the MA-wrapper path was ungated.

Fix

  • 4 new DURATION_MULTIPLIER value-class facts (param="unit", ibis, ibis-sqlite) for TRUNCATE/ROUND/CEIL/FLOOR in capabilities/datetime/value_classes_ma.py. The visitor option gate resolves value-class facts, so the clean BackendCapabilityError now fires at build time. "1d"-style single units do not match the class predicate (multiplier ≥ 2) — unaffected.
  • Integrity guard: the matrix-exercise class arm in test_option_fact_integrity.py now exempts class facts whose (backend, dialect) the 4-fixture matrix cannot instantiate (mirrors the existing _MATRIX_UNREACHABLE_DIALECT_FACTS exact-arm precedent), with a new staleness guard.
  • Dedicated gate tests: TestMaMultiplierIbisSqliteGate builds a real ibis-sqlite backend — 4 multiplier durations raise BackendCapabilityError, 4 single-unit durations still compile/evaluate (no over-gating). RED→GREEN: the tests failed with the raw OperationNotDefinedError before the facts landed.
  • Registry cleanup: the 2026-08-16 KNOWN_GAPS entry (added when the gap was only disclosed) is retired — the fact supersedes it. Coverage docs regenerated.

Verification

  • Full suite: 23119 passed, 81 skipped, 3470 xfailed (baseline +13 = the new gate tests).
  • Targeted (877 passed / 72 xfailed): test_datetime_rounding.py, test_option_fact_integrity.py, test_datetime_value_class_dispatch.py, test_arg_types_datetime.py, test_datetime_unit_dispatch.py, test_expression_coverage_doc.py, test_capability_value_class_gate.py.
  • Coverage artifacts byte-equal after regeneration (test_expression_coverage_doc.py).
  • Ruff: clean on all changed files.
  • Empirically confirmed pre/post: truncate('2d') raised OperationNotDefinedError: Compilation rule for 'TimestampBucket' operation is not defined → now BackendCapabilityError; truncate('1d') unchanged.

Spec: mountainash-central/04.planning/mountainash/superpowers/specs/2026-08-18-ibis-sqlite-timestampbucket-raw-error-leak-design.md
Plan: mountainash-central/04.planning/mountainash/superpowers/plans/2026-08-18-ibis-sqlite-timestampbucket-raw-error-leak.md

@discreteds
discreteds merged commit 01703e5 into develop Aug 18, 2026
4 checks passed
@discreteds
discreteds deleted the bugfix/ibis-sqlite-timestampbucket-raw-error-leak branch August 18, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant