Generate the explicit MEOS object model (class lattice, methods, error contract)#10
Conversation
d0adfd4 to
b97fef8
Compare
b97fef8 to
4ec925f
Compare
Extend objectModel.dispatch to the complete editorial-member set, transcribed verbatim from PyMEOS RFC #94 §7 (AST-extracted 1:1 from the hand-written oracle; do not re-derive per §6): geo += minus, nearest_approach_distance (single-block); temporal restructured to the adopted per-concrete contract dispatch.temporal.{tfloat,tint,tbool,ttext}.<member> with always_/ever_(not_)equal, temporal_(not_)equal, at, minus (tbool: only temporal_(not_)equal/at/minus; no temporal distance — none in the oracle). Schema additions: scalarType field, argTransform += textsetMake, py:"list[str]"; attach_object_model passthrough unchanged. Verified: JSON valid, non-dispatch facets byte-identical, generator emits it, zero #10 test regression vs the prior tip (identical 20 passed; the lone parity failure is the pre-existing cross-file test-ordering issue, independent).
4ec925f to
6cd5d5b
Compare
Makes ecosystem-wide 100% parity provable at one point instead of asserted from per-PR isolation-green. meta/integration-train.json is the PR dependency DAG + per-wave gates + merge order; verify-train.sh composes the train and runs each wave's gate (PASS only when just-run green here, else BLOCKED with the exact gate it needs). Operationalizes MobilityDB discussion #895 (wave-based merge plan). Stacked on feat/object-model (the catalog anchor): Wave 0 verifies here (2699 fns, PR #10 21/21, from_mfjson + constructors uniform); Waves 1-3 are honestly gated on the MEOS-1.4 bump (the single universal unblock).
Makes ecosystem-wide 100% parity provable at one point instead of asserted from per-PR isolation-green. meta/integration-train.json is the PR dependency DAG + per-wave gates + merge order; verify-train.sh composes the train and runs each wave's gate (PASS only when just-run green here, else BLOCKED with the exact gate it needs). Operationalizes MobilityDB discussion #895 (wave-based merge plan). Stacked on feat/object-model (the catalog anchor): Wave 0 verifies here (2699 fns, PR MobilityDB#10 21/21, from_mfjson + constructors uniform); Waves 1-3 are honestly gated on the MEOS-1.4 bump (the single universal unblock).
Makes ecosystem-wide 100% parity provable at one point instead of asserted from per-PR isolation-green. meta/integration-train.json is the PR dependency DAG + per-wave gates + merge order; verify-train.sh composes the train and runs each wave's gate (PASS only when just-run green here, else BLOCKED with the exact gate it needs). Operationalizes MobilityDB discussion #895 (wave-based merge plan). Stacked on feat/object-model (the catalog anchor): Wave 0 verifies here (2699 fns, PR MobilityDB#10 21/21, from_mfjson + constructors uniform); Waves 1-3 are honestly gated on the MEOS-1.4 bump (the single universal unblock).
Makes ecosystem-wide 100% parity provable at one point instead of asserted from per-PR isolation-green. meta/integration-train.json is the PR dependency DAG + per-wave gates + merge order; verify-train.sh composes the train and runs each wave's gate (PASS only when just-run green here, else BLOCKED with the exact gate it needs). Operationalizes MobilityDB discussion #895 (wave-based merge plan). Stacked on feat/object-model (the catalog anchor): Wave 0 verifies here (2699 fns, PR MobilityDB#10 21/21, from_mfjson + constructors uniform); Waves 1-3 are honestly gated on the MEOS-1.4 bump (the single universal unblock).
|
Coordination note from a sibling session — proposing a third per-function facet for this PR's object model.
Grounded backing: a v4 mechanical classifier (~250 LOC, deterministic) has already been applied to the catalog this PR emits — it classifies 2,240 public-API functions into 6 streaming tiers with 97.4% mechanical coverage (2.6% ambiguous = 59 functions). The classifier output has already driven a working codegen wedge on MobilityFlink and MobilityKafka (1 PR each, OPEN, 57 generated Java classes × 2,097 methods compile clean against JMEOS PR #19). This RFC formalizes the classifier as a catalog facet so every binding consumes the same tier assignments, and resolves the 59 ambiguous corner cases + 2 streaming-semantic nuances per-function so the facet ships complete with zero ambiguity remaining. Motivation (one paragraph)The MEOS public API has 2,240 functions. The first per-engine streaming binding (MobilityFlink) currently hand-wires 10 distinct operators to support the 9 BerlinMOD benchmark queries — 0.4% API coverage by operator. A mechanical classification (the v4 streaming-relevance baseline, deterministic name + signature + role rules) lifts that ceiling to 97.4% covered (87% streamable, 9.7% I/O-meta, 0.6% honestly marked non-streamable; 2.6% / 59 functions ambiguous under the mechanical rules). This RFC adopts the v4 baseline as the catalog's VocabularyClosed 7-value set. Every public MEOS function has exactly one tier.
Classification rules (deterministic, 18 rules applied in order; first match wins)Each rule fires off
Full ordered rule list reproducible from the reference classifier; the catalog ships it as Per-function overridesTwo override sources: A. The 59 ambiguous cases (post-hoc deterministic resolution)
Total: 57 entries covering all 59 ambiguous functions. Post-override ambiguous count: 0. Net additions: +33 stateless · +4 bounded-state · +3 cross-stream · +7 sequence-only · +8 io-meta. B. The 2 streaming-semantic nuances (per-function semantic overrides)Functions where the mechanical tier is technically correct but a streaming engineer needs a different operational reading. The override exposes BOTH so codegen can pick by mode.
Both modes are valid; the catalog ships them as a JSON schema (proposed){
"functions": {
"eintersects_tgeo_geo": {
"objectModel": {
"role": "predicate",
"classes": ["TGeo"],
"dispatch": { /* D1 facet, unchanged */ },
"nullable": { /* D2 facet, unchanged */ },
"streamingSemantics": {
"tier": "bounded-state",
"tierConfidence": "high",
"classificationRule": "rule-10: ever-rel on 1 temporal",
"alternateMode": {
"tier": "windowed",
"modeKey": "streamingMode.eRelOverWindow",
"reasoning": "OR-fold over trajectory lifetime"
}
}
}
}
}
}For functions with no Generator integrationAdd to MEOS-API:
Adoption path
The Wave-1 PR is small: ~250 LOC classifier + ~150 LOC override JSON + one-line Reference artifacts
Happy to provide the JSON files / classifier source as a follow-up PR off |
|
Reviewed the whole PR end-to-end (docs, lattice, parser, run.py wiring, setup.py, and tests). The work itself is super solid: the three-axis design (template / type-family / method-binding) is really well thought out, the reconciliation against Chapter 7 (Figure 7.1) of MobilityDB is well-documented with OM-M6, and the companion hierarchies for the closed algebra are fully there. On top of that, tests run perfectly clean locally (16/16 green on object_model, and 5/5 green on parity with honest skips where the oracle is missing). That being said, I can't approve this just yet. There are two hard blockers we need to sort out, plus a few smaller notes. Hard BlockersBranch base / rebase issue: the branch is currently based on a697ba9, which means it misses two recently merged PRs that both modify run.py and add new steps to the pipeline:
On your feat/object-model branch, both of these files are missing and run.py drops those pipeline steps entirely. Merging this as-is would silently roll back the work done in #15 (the IDL would re-collapse bool / int64 / TimestampTz into ints) and #8 (we'd lose the portableAliases catalog). You'll need to rebase on master, make sure both stages are preserved, and chain object_model as a subsequent step (so the pipeline flows: parse -> recover -> merge -> portable -> object_model). README diff: The diff shows that the "Portable bare-name dialect" section was deleted instead of just extending the document with "The object model". If portable-aliases is meant to coexist with objectModel (which the catalog seems to point to), we should keep both sections in the doc. Smaller Observations
LGTM on direction and content. I recommend rebasing on master, restoring the typerecover + portable_aliases stages in run.py and keep the README "Portable bare-name dialect" section. |
Extend objectModel.dispatch to the complete editorial-member set, transcribed verbatim from PyMEOS RFC #94 §7 (AST-extracted 1:1 from the hand-written oracle; do not re-derive per §6): geo += minus, nearest_approach_distance (single-block); temporal restructured to the adopted per-concrete contract dispatch.temporal.{tfloat,tint,tbool,ttext}.<member> with always_/ever_(not_)equal, temporal_(not_)equal, at, minus (tbool: only temporal_(not_)equal/at/minus; no temporal distance — none in the oracle). Schema additions: scalarType field, argTransform += textsetMake, py:"list[str]"; attach_object_model passthrough unchanged. Verified: JSON valid, non-dispatch facets byte-identical, generator emits it, zero #10 test regression vs the prior tip (identical 20 passed; the lone parity failure is the pre-existing cross-file test-ordering issue, independent).
6cd5d5b to
fae2912
Compare
|
Thanks for the thorough review. All five points are addressed on the rebased branch. Hard blockers
Smaller notes
The live parity gate now honestly skips when the PyMEOS oracle is not checked out beside the repo (mirroring the other parity test), so the suite is green whether or not PyMEOS is present — matching the "honest skips where the oracle is missing" behavior. Full suite: 100 passed, 6 skipped. |
Extend objectModel.dispatch to the complete editorial-member set, transcribed verbatim from PyMEOS RFC #94 §7 (AST-extracted 1:1 from the hand-written oracle; do not re-derive per §6): geo += minus, nearest_approach_distance (single-block); temporal restructured to the adopted per-concrete contract dispatch.temporal.{tfloat,tint,tbool,ttext}.<member> with always_/ever_(not_)equal, temporal_(not_)equal, at, minus (tbool: only temporal_(not_)equal/at/minus; no temporal distance — none in the oracle). Schema additions: scalarType field, argTransform += textsetMake, py:"list[str]"; attach_object_model passthrough unchanged. Verified: JSON valid, non-dispatch facets byte-identical, generator emits it, zero #10 test regression vs the prior tip (identical 20 passed; the lone parity failure is the pre-existing cross-file test-ordering issue, independent).
fae2912 to
cb63cf4
Compare
Makes ecosystem-wide 100% parity provable at one point instead of asserted from per-PR isolation-green. meta/integration-train.json is the PR dependency DAG + per-wave gates + merge order; verify-train.sh composes the train and runs each wave's gate (PASS only when just-run green here, else BLOCKED with the exact gate it needs). Operationalizes MobilityDB discussion #895 (wave-based merge plan). Stacked on feat/object-model (the catalog anchor): Wave 0 verifies here (2699 fns, PR MobilityDB#10 21/21, from_mfjson + constructors uniform); Waves 1-3 are honestly gated on the MEOS-1.4 bump (the single universal unblock).
Extend objectModel.dispatch to the complete editorial-member set, transcribed verbatim from PyMEOS RFC #94 §7 (AST-extracted 1:1 from the hand-written oracle; do not re-derive per §6): geo += minus, nearest_approach_distance (single-block); temporal restructured to the adopted per-concrete contract dispatch.temporal.{tfloat,tint,tbool,ttext}.<member> with always_/ever_(not_)equal, temporal_(not_)equal, at, minus (tbool: only temporal_(not_)equal/at/minus; no temporal distance — none in the oracle). Schema additions: scalarType field, argTransform += textsetMake, py:"list[str]"; attach_object_model passthrough unchanged. Verified: JSON valid, non-dispatch facets byte-identical, generator emits it, zero #10 test regression vs the prior tip (identical 20 passed; the lone parity failure is the pre-existing cross-file test-ordering issue, independent).
cb63cf4 to
2c3c44e
Compare
What
Makes the implicit MEOS object model explicit as a first-class pipeline stage, so every binding/engine (PyMEOS, JMEOS, MEOS.NET, MobilityDuck, MobilitySpark, …) derives the identical class hierarchy and methods from one mapping instead of re-curating the C prefix convention by hand.
MEOS is C — no classes. The model is encoded by convention in (1) the
Temporal/TInstant/TSequence/TSequenceSetstruct family (template axis), (2) thetemptypediscriminator whose base type is the missing template parameter (type-family axis), and (3) the function-name prefixes that bind a function to the class it is a method of.How
meta/object-model.json— curated source of truth: the single-inheritance lattice (Temporal → TAlpha/TNumber/TSpatial →leaves), the geometry/geodetic trait axis, the Box and Collection companion hierarchies required to type the closed algebra, theerrorCodecontract, and the irregularity worklist.doc/images/tspatial.svg):TSpatial → TGeo → {TGeometry, TGeography, TPoint → {TGeomPoint, TGeogPoint}}withTCbuffer/TNpoint/TPose/TRGeometryunderTSpatial.TGeois the broad parent of all PostGIS-derived types (= the Ctgeo_type_allpredicate);TPointis an API-level intermediate underTGeo(the figure omits it, but thetpoint_*family must bind to a class). Class names use the manual spelling (TGeo,TNpoint,TCbuffer,TPose,TRGeometry); C prefixes unchanged. A test gates the model against the figure so the reconciliation cannot regress.parser/object_model.py+run.pyfinal stage — derive the class tree and assign every catalog function to the class it is a method of by longest-prefix match (the function is its own backing symbol — equivalence by construction). Additiveidl["objectModel"];functions[]untouched. Per-function raisederrorCodes derived by a static scan of the MobilityDB sources (directmeos_error+ oneensure_*indirection), honestsource-unavailablewhen the sources are absent. The stage chains after type recovery, portable aliases, and temporal covering, so the recovered PG-vendored types and theportableAliasescatalog are all preserved in the emitted IDL.object_model_parity.py— audits the derived lattice against the PyMEOS factory oracle (parsed, never hard-coded); reports an honest oracle-unavailable status (and the tests skip) when PyMEOS is not checked out beside the repo.MEOS_TEMPTYPE_CATALOG/ enums (TGeogated againsttgeo_type_all); a manual-figure gate; a parity gate (every divergence has a stated correction).setup.pyalso fetchesmeos/srcfor the error scan;docs/object-model.md+ README document the model.Result
The object-model stage derives 83 classes and binds every class-method prefix to its class (
temporal_,tnumber_,tgeo_,tpoint_,tgeometry_,tcbuffer_,tnpoint_,trgeo_, and all leaves/subtypes are fully classified). The functions that remain unclassified are cross-type operators (the portable-aliases / RFC-920 domain), base PostGIS/datum_helpers, and runtime lifecycle — the object-model and portable-aliases models cleanly partition the API into methods vs operators;objectModel.summarylists theunclassifiedNamesso the complement is visible directly.Parity vs PyMEOS: the concrete classes align, and every divergence carries a stated correction (0 needs-correction). The error scan reports
scannedwith a derivedraisesset per function.Irregularities surfaced (corrections worklist, report-only)
MEOS: OM-M1 (
TGeois broad per the manual, but the Ctgeo_type()/tgeo_*API is narrower — rejects points); OM-M2 (tgeometry_type()misnomer); OM-M3 (TRGeometrybase =T_POSE≠ name); OM-M4 (talpha_typehas no class name); OM-M5 (tpose_to_tpointrename strain); OM-M6 (manual Figure 7.1 is partial — spatial-only, noTPoint; the model is the superset); OM-M7 (tpcpoint/tpcpatchabsent from master MEOS and the figure — out of the drift-gated source of truth until MEOS adds them; derived automatically once present). PyMEOS: OM-P1/P3/P4/P5/P6/P7 (missing leaves, the full Collection hierarchy, theTSpatial/TGeoabstracts, dummy constructors, shapely-base inconsistency, ad-hocbearing()).