From 232235cfc0c061b246b0be992d9133cd2bc7925c Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Mon, 14 Sep 2026 16:06:07 +0200 Subject: [PATCH] Back a bare name by the functions that carry it as their SQL name The parity audit backs a bare name by the MEOS functions whose C name starts with it (`overlaps_*`, `same_*`), else by the curated `explicitBacking` prefixes. The spelled-out comparison names and `tDistance` match neither: `tEqual` is the @sqlfn of the `teq_*` family, `eEqual` of `ever_eq_*`, `aEqual` of `always_eq_*` and `tDistance` of `tdistance_*`, so the audit flags all 19 as needing an explicit backing entry and reads 22 of 41 operators backed. Between the prefix and the explicit map, the audit backs a bare name by the catalog functions whose @sqlfn is that name, the SQL name MobilityDB declares for them. Over MobilityDB master b541442a30 it reads 41 of 41 operators backed, and the live gate of tests/test_portable_parity.py requires every operator of the contract to be backed. --- docs/portable-aliases.md | 12 +++++++----- tests/test_portable_parity.py | 20 +++++++++++++++++--- tools/portable_parity.py | 21 ++++++++++++++------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/docs/portable-aliases.md b/docs/portable-aliases.md index dc8960c..26cce47 100644 --- a/docs/portable-aliases.md +++ b/docs/portable-aliases.md @@ -97,11 +97,13 @@ bare name against the catalog's function families (by the MEOS bare-name prefix convention), and every position operator against the family its position prefixes (`left_*`, `before_*`) with its SQL names by class, and writes `output/meos-portable-parity.json`. A bare name whose C family -prefix differs is resolved through `explicitBacking` (`nearestApproachDistance` -through `nad`, the `nad_*` family), and one that no entry resolves is -flagged `needs-explicit-backing` — never silently dropped; -`tests/test_portable_parity.py` gates this (no operator may be -unclassified). +prefix differs is backed by the functions whose `@sqlfn` is the bare name +(`tEqual` by the `teq_*` family, `eEqual` by `ever_eq_*`, `tDistance` by +`tdistance_*`), else through `explicitBacking` (`nearestApproachDistance` +through `nad`, the `nad_*` family), and one that none of them resolves is +flagged `needs-explicit-backing` — never silently dropped. +`tests/test_portable_parity.py` gates this: no operator may be +unclassified, and over a derived catalog every operator is backed. ## Provenance diff --git a/tests/test_portable_parity.py b/tests/test_portable_parity.py index a8201d3..193293f 100644 --- a/tests/test_portable_parity.py +++ b/tests/test_portable_parity.py @@ -20,9 +20,11 @@ _CATALOG = ROOT / "output" / "meos-idl.json" -def _catalog(fn_names): +def _catalog(fns): + """A catalog of the given functions: a name, or a function record.""" idl = attach_portable_aliases( - {"functions": [{"name": n} for n in fn_names]}, MAP) + {"functions": [f if isinstance(f, dict) else {"name": f} + for f in fns]}, MAP) return idl @@ -30,7 +32,10 @@ class ParityLogicTests(unittest.TestCase): def test_backed_vs_needs_explicit(self): cat = _catalog([ "overlaps_span_span", "overlaps_tbox_tbox", # backs `overlaps` - "teq_temporal_temporal", # backs `teq` + {"name": "teq_temporal_temporal", # backs `tEqual` + "sqlfn": "tEqual"}, # by its SQL name + {"name": "ever_eq_temporal_temporal"}, # no SQL name: backs + # nothing "same", # exact-name back "nad_tfloat_tfloat", # explicit backing # of nearestApproach… @@ -51,6 +56,13 @@ def test_backed_vs_needs_explicit(self): self.assertNotIn("nearestApproachDistance", r["unbacked"]) self.assertEqual(r["byBareName"]["overlaps"]["family"], "topology") self.assertEqual(r["byBareName"]["tEqual"]["operator"], "#=") + # a C family whose prefix differs is backed by the functions carrying + # the bare name as their @sqlfn, and only by those + teq = r["byBareName"]["tEqual"] + self.assertEqual(teq["status"], "backed") + self.assertEqual(teq["via"], "sqlfn") + self.assertEqual(teq["sample"], ["teq_temporal_temporal"]) + self.assertIn("eEqual", r["unbacked"]) # a position operator is backed by the MEOS family its position prefixes left = r["byPosition"]["<<"] self.assertEqual(left["status"], "backed") @@ -100,6 +112,8 @@ def test_no_bare_name_silently_dropped(self): self.assertEqual( r["backed"] + r["needsExplicitBacking"], r["total"]) self.assertEqual(r["total"], 41) + # every operator of the contract is backed in the catalog + self.assertEqual(r["unbacked"] + r["unbackedPositions"], []) if __name__ == "__main__": diff --git a/tools/portable_parity.py b/tools/portable_parity.py index c235e4c..ce14be8 100644 --- a/tools/portable_parity.py +++ b/tools/portable_parity.py @@ -4,13 +4,14 @@ # python run.py # catalog with `portableAliases` + functions # python tools/portable_parity.py # -> output/meos-portable-parity.json # -# For every canonical bare name (PR #8 / RFC #920) it reports the catalog -# function family that backs it, by the MEOS bare-name prefix convention -# (`overlaps_*`, `teq_*`, `same_*`, …). A bare name with no prefix match is -# **not** asserted to be an API gap (some map through a different C prefix, -# e.g. `nearestApproachDistance` ↔ `nad_*`): it is flagged -# `needs-explicit-backing` so the cross-repo work can add an explicit -# operator→C-family entry — an honest signal, never a fabricated verdict. +# For every canonical bare name it reports the catalog functions that back it: by the MEOS bare-name prefix convention +# (`overlaps_*`, `same_*`, …), else by the functions whose @sqlfn IS the bare +# name (`tEqual` on the `teq_*` family, `eEqual` on `ever_eq_*`: the SQL name +# MobilityDB declares for them), else by a verified `explicitBacking` prefix. +# A bare name none of them resolves is **not** asserted to be an API gap: it +# is flagged `needs-explicit-backing` so the cross-repo work can add an +# explicit operator→C-family entry — an honest signal, never a fabricated +# verdict. # # A position operator has no bare name: its SQL names are one per class # (`setLeft` … `stboxLeft`, the catalog's `positionNames`), and its MEOS C @@ -34,6 +35,10 @@ def build_parity(catalog: dict) -> dict: for fam, lst in pa["families"].items() for p in lst} explicit = pa.get("explicitBacking", {}) names = [f["name"] for f in catalog.get("functions", [])] + by_sqlfn = {} + for f in catalog.get("functions", []): + if f.get("sqlfn"): + by_sqlfn.setdefault(f["sqlfn"], []).append(f["name"]) def _matches(prefix): return [n for n in names @@ -42,6 +47,8 @@ def _matches(prefix): by_bare = {} for bare, (fam, op) in sorted(fam_of.items()): hits, via = _matches(bare), "prefix" + if not hits: # the functions named by it in SQL + hits, via = list(by_sqlfn.get(bare, [])), "sqlfn" if not hits: # try the verified explicit map for pref in explicit.get(bare, []): hits += _matches(pref)