Skip to content

feat(capabilities): wire extract/extract_boolean, strptime_timestamp.timezone, retire MA duplicates - #290

Merged
discreteds merged 1 commit into
developfrom
feature/substrait-datetime-missing-ops
Aug 15, 2026
Merged

feat(capabilities): wire extract/extract_boolean, strptime_timestamp.timezone, retire MA duplicates#290
discreteds merged 1 commit into
developfrom
feature/substrait-datetime-missing-ops

Conversation

@discreteds

Copy link
Copy Markdown
Member

Summary

Backlog item 62 (substrait-datetime-missing-ops). Wires the two canonical Substrait datetime ops extract/extract_boolean plus an end-to-end fix for strptime_timestamp.timezone, retires the dead-code Mountainash-namespace extract/extract_boolean duplicates, and closes two additional silent-wrong bugs discovered by the semantic probe.

Spec: mountainash-central/04.planning/mountainash/superpowers/specs/2026-08-15-substrait-datetime-missing-ops-design.md (rev 2, codex-reviewed)
Plan: mountainash-central/04.planning/mountainash/superpowers/plans/2026-08-15-substrait-datetime-missing-ops.md (rev 2, GLM-5.2-reviewed)

Landed as one commit — see the commit message for why the plan's PR-1/PR-2 split collapsed (the closed-by-default option-matrix reason-staleness check ties the MA retirement to the same commit as wiring extract into the API builder).

What changed

  • extract/extract_boolean: new, fully wired (protocol → builder → 3 backends → capability facts → disposition matrix). component (23/2-value closed domains), indexing (ONE/ZERO), timezone (open IANA value class).
  • Silent-wrong fixes (probe-authoritative, gate-disabled, all 4 fixtures): deleted every fallback (x.dt.year() / pl.lit(False)); declared components now raise BackendCapabilityError, backed by facts. Also fixed MICROSECOND/NANOSECOND (were since-second, should be since-unit per Substrait) and narwhals' wrong QUARTER formula.
  • strptime_timestamp.timezone: now reaches the backend end-to-end (str.to_datetime(fmt, timezone=...)); narwhals wired for real, ibis declared (no timezone primitives).
  • MA extract/extract_boolean retired: dead code, no caller, drains their parks by deletion.
  • Disposition matrix + facts: full per-backend × per-value coverage for all 6 wired option params, with probes and invalid-sentinel rejections.
  • Conformance/reachability drift cleanup: several "known divergent" entries across test_signature_conformance.py/test_protocol_alignment.py/test_api_reachability.py are now genuinely aligned and removed.
  • AST-identity tests added for extract/extract_boolean and to_datetime timezone option presence/omission.
  • Regenerated docs/reference/expression-coverage.{md,json}.
  • Deleted tests/expressions/backends/test_narwhals_extract_capability_error.py — tested the retired MA method; same guarantee now covered by the disposition matrix.

Verification

  • Full suite: 22519 passed, 0 failed, 81 skipped, 3734 xfailed.
  • ruff check: clean.
  • mypy: no new errors (2 touched-file hits are the pre-existing ibis import-untyped baseline noise).
  • Smoke-tested end-to-end on all 4 backend fixtures via the public relation API (extract, extract_boolean, indexing, declared-component raise, strptime_timestamp+timezone).

Deferred (per spec §7, out of scope here)

  • strptime_time + precision (needs core/dtypes work) — future item.
  • is_dst real implementation — item 65.

…timezone, retire MA duplicates

Backlog item 62. Two canonical Substrait datetime ops plus one options fix,
landed as a single commit (the closed-by-default option-disposition matrix
couples the MA-retirement drain to the same commit as the wiring — see notes).

extract / extract_boolean (new):
- component (23/2-member closed domains, DatetimeComponent/BooleanComponent),
  indexing (ONE/ZERO omission-sentinel, calendar components only), timezone
  (open IANA_TIMEZONE value class) wired through protocol -> API builder ->
  three backends -> capability facts -> disposition matrix.
- Backend bodies rewritten per semantic probe (gate disabled, all 4 fixtures):
  deleted every silent fallback (return x.dt.year() / pl.lit(False));
  in-domain-but-unsupported components now raise BackendCapabilityError,
  backed by UNSUPPORTED facts (polars 6, ibis 7, narwhals 9 declared
  components; IS_DST declared on all three).
- Two additional silent-wrong bugs found and fixed: MICROSECOND/NANOSECOND
  were returning since-last-SECOND (0-999999/0-999999999) instead of Substrait's
  since-last-unit (0-999) semantics — now % 1000; narwhals QUARTER formula
  (month // 4 + 1) was wrong for months 7/10/11 — now (month-1)//3+1.
  TIMEZONE_OFFSET declared everywhere (native primitives require tz-aware
  input extract can't guarantee at build time — input-type-dependent,
  matches spec §7.3, not a raw backend exception).

strptime_timestamp.timezone (end-to-end fix):
- MountainAshScalarStringAPIBuilder.to_datetime gains timezone (IANA-
  validated), threading through the def's options tuple (now
  ("format","timezone")) to the protocol and all three backends.
- narwhals body wired for real (dt.replace_time_zone); ibis silently drops
  (no timezone primitives, matching assume_timezone/to_timezone/
  local_timestamp/extract.timezone) — now backed by an UNSUPPORTED fact
  instead of a silent discard.

Mountainash-namespace retirement:
- Deleted MA extract/extract_boolean (protocol + 3 backend impls) —
  dead code, positional-only, no caller (named wrappers call backends
  directly). Drains their option-matrix parks by deletion.

Capability facts (new capabilities/datetime/extract.py + additions to
value_classes_substrait.py):
- Closed option_value= grain (component/IS_DST) lives in extract.py.
- Open value_class=IANA_TIMEZONE grain (extract/extract_boolean/
  strptime_timestamp timezone) lives in value_classes_substrait.py per the
  placement-guard's domain-module restriction (spec §3: domain modules never
  carry value_class facts).

Disposition matrix (test_arg_types_datetime.py + option_disposition.py):
full per-backend x per-value dispositions, probes (declared cells verified
via gate-disabled native probe + strict xfail), invalid-sentinel rejections,
and TESTED_OPTION_PARAMS entries for all 6 wired option params. Drained all
6 "operation not implemented" parks plus the 2 MA argument-channel aliases.

Conformance/reachability drift entries retired (signatures/options/call-
patterns that were "known divergent" now genuinely match): protocol
alignment KNOWN_ASPIRATIONAL, signature/options drift dicts, unverifiable-
call-pattern entries, and A2 local builders + reachability builders added
for the two newly-public FKEYs.

AST-identity coverage added: extract/extract_boolean node shape
(test_ast_scalar_datetime.py), to_datetime timezone option presence/
omission (test_ast_str_to_date.py).

Regenerated docs/reference/expression-coverage.{md,json} (3 new
declarations from extract.py).

Deleted tests/expressions/backends/test_narwhals_extract_capability_error.py
— exercised the now-retired MA extract's inline ISO_WEEK raise; the same
guarantee (ISO_WEEK on narwhals raises BackendCapabilityError, not
AttributeError) is now covered by the extract disposition matrix's declared
cell + strict-xfail probe.

Deferred (spec §7, unchanged from plan): strptime_time + precision (needs
core/dtypes work); is_dst (item 65, IS_DST stays UNSUPPORTED); input-type-
dependent overload validity (error normalization, pre-existing).

Verification: full suite 22519 passed / 0 failed / 81 skipped / 3734 xfailed;
ruff clean; mypy — no new errors (2 touched-file hits are the pre-existing
ibis import-untyped baseline noise, same class as the other 95). Smoke-
tested end-to-end on all 4 fixtures (extract, extract_boolean, indexing,
declared-component raise, strptime_timestamp+timezone) via the public
relation API.

Deviation from the written plan: the plan sliced this into PR-1 (extract/
extract_boolean) and PR-2 (strptime_timestamp.timezone + MA retirement).
The option-disposition matrix's closed-by-default reason-staleness check
(test_untested_option_param_custom_reasons_still_hold) ties MA retirement
to the same commit as wiring extract into the API builder — draining the
MA park's "not implemented in API builder" reason requires the MA methods
to already be gone the moment extract becomes a builder method name, or
the check fails on the newly-false reason. Landed as one commit; still two
logically-separable diffs within it (extract+extract_boolean vs
strptime_timestamp+retirement) per the plan's task boundaries.

Backlog: substrait-datetime-missing-ops (item 62)
@discreteds
discreteds merged commit ceafbfe into develop Aug 15, 2026
3 of 4 checks passed
@discreteds
discreteds deleted the feature/substrait-datetime-missing-ops branch August 15, 2026 11:57
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