Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Design decisions and open questions

Design · one register, one ID per decision, linked to the page that argues it

Each design page argues its own decisions, with the options and the recommendation; this page only lists them, so one ID means one question everywhere. An ID is the page code, a hyphen and the page’s own label: OP-O8 is open question O8 on the operators page. When a status changes, change it on the page first, then here.

Statuses: decided (with the date), forced (follows from the dependency rules, no real choice), open (not yet decided; the page gives the recommendation and the alternative), superseded (replaced; the page says by what), deferred. Testing gates are not listed here; each page keeps its own.

1Decide first

These change a principle or block other work.

IDQuestionWhy first
CS-F1A readable type becomes a dim signature that any carrier can matchdecided 23 Oct 2026 (geostack #74): principle 5 changed; GeoImageSeries is time band y x, GeoMapSeries is time y x
CS-F2One L3 algorithm may take carriers from two familieschanges vision principle 4
CS-F11Packaged pipelines are versioned and record provenancea new principle; most of the missing pipelines page
OP-O8May an L3 algorithm call another L3 algorithm inside a differentiated costdecides how esmax and vardax compose
GA-Q2 / LL-F1The CRS encoding on the xarray sidedecided 23 Oct 2026 (geostack #77): a hand-written CF spatial_ref with crs_wkt, CRS.to_cf() attributes and GeoTransform; no rioxarray
GA-Q5Do geoops kernel operators accept a DataArray directlydecided 23 Oct 2026 (geostack #78): yes, lazily through apply_ufunc; geometry operators raise and name xrops.lift

2Vision (VI)

IDQuestionStatus
VI-V1Where packaged pipelines live: each in the package that owns its domain (plumax.pipelines, esmax_ocean.pipelines)open
VI-V2Which run modes are first-class at first: eager and compiled, lazy through apply_ufuncopen
VI-V3Which pipelines to package first: methane plume detection, SLA mappingopen
VI-V4How a pipeline runs concurrently: the pipekit runner schedules synchronous operators; I/O stages are concurrentopen
VI-V5Whether pipeline checks can be switched off: entry checks always on; per-stage dim checks may be turned offopen

3Case studies (CS)

Findings from running thirteen workflows through the vision; each proposes an edit.

IDFindingStatus
CS-F1Readable types stop at GeoArray, so lazy inputs have nonedecided 23 Oct 2026: a readable type is a name, a dims pattern and a kind that any carrier matches (GA-T5)
CS-F2One L3 algorithm takes carriers from two familiesopen (decide first)
CS-F3Fixed shapes before jit: padding is part of the named crossing (to_jax(pad_to=...))open
CS-F4The runner fans out I/O and carries state between cyclesopen; for the pipelines page
CS-F5Derived geometry is more than spacing: time and viewing geometry, unit vectorsapplied to the three levels
CS-F6Results can be records: a Detections type on GeoPoints["variable obs"]open
CS-F7xrops wraps the native xarray operations pipelines need (Climatology, Anomaly, Resample)open
CS-F8Operators declare backends; eager-only ones are listedopen (see OP-O6)
CS-F9A pipeline slot says whether it expects a fitted operator; replace checksopen
CS-F10geoops.geom.interp_at held equal to scipy.ndimage.map_coordinates (what xr.interp uses); GeoPoints to and from data framesopen
CS-F11Packaged pipelines are versioned, record provenance and re-run idempotentlyopen (decide first)
CS-F12Carrier-free geometry helpers, and one documented path L1 → KernelOp → pipelineopen
CS-F13Runners own splits and hold back truthopen; for the pipelines page
CS-F14pipelines.register(...) promotes a graph to a pipelineopen; for the pipelines page
CS-F15A dim convention for distribution summaries (moment or stat) beside memberopen
CS-F16Every L3 algorithm exposes its L1 loop; seeds come from the runopen
CS-F17Ahead-of-time compile for apps; the slim geoops base is requiredpartly decided (the slim base, with the tiers)

4geoarray (GA)

IDDecision or questionStatus
GA-A1Compose a frozen dataclass; do not subclass ndarrayopen
GA-A2Float64 transform leaf; to_jax requires x64open
GA-A3FrozenAttrs keeps whole-carrier metadata; per-band metadata lives on a SpectralAxisopen (narrowed 21 Oct 2026)
GA-A4No fill value by defaultopen
GA-B1map and combine instead of arithmetic dundersopen
GA-B2Per-band attrs follow a band selectionsuperseded 21 Oct 2026 by coordinates
GA-B3geoarray reads only the georeference (re-index, join, re-describe, read at); everything that computes is geoops; H(x) is interp_atdecided 24 Oct 2026; amended 4 Nov 2026 by GA-B6
GA-B4The positional band guard stays until geoops takes dim= (geotoolz #531); removed in geotoolz-array 0.4decided 24 Oct 2026
GA-B5geoarray.stack is a 0.3 deprecation shim; pipekit_array.stack from 0.4decided 24 Oct 2026
GA-B6interp_at and the named reductions move to geoops: geoops.geom.interp_at plus an InterpAt operator, and nodata-aware geoops.compositing.reduce / argreduce; geoarray stops re-exporting reduce / argreduce (they stay in pipekit-array, GA-Q3). geoarray’s documented computing exceptions are valid_mask (the nodata model) and astype (a cast)decided 4 Nov 2026
GA-C1Eager np.asarray copies to host and raises under transforms; mixed NumPy and JAX inputs refuse (0.3 warns, 0.4 raises)decided 17 Oct 2026, partly superseded 21 Oct 2026; migration decided 24 Oct 2026
GA-D1One coordinated breaking release from GeoTensor to GeoArraydecided 17 Oct 2026
GA-E1JAX kernels in geoops.functionalsuperseded 22 Oct 2026 by the kernel model on operators
GA-T1GeoImageSeries and GeoTimeSeries as the series namesdecided 21 Oct 2026
GA-T2band and variable are separate dimsdecided 21 Oct 2026
GA-T3level is allowed on observationsdecided 21 Oct 2026
GA-T4coordax is an optional converter, not the JAX lane’s foundationdecided 21 Oct 2026
GA-T5Readable types are dims signatures any carrier matches; a DataArray’s horizontal dims read as y x; GeoMapSeries is time y x beside GeoImageSeries (time band y x)decided 23 Oct 2026 (CS-F1)
GA-Q1What esmax and vardax take at their boundaryopen
GA-Q2The georeference in xarray: CF grid_mapping plus GeoTransform (same as LL-F1)decided 23 Oct 2026
GA-Q3Shared dim-level functions live in pipekit-arraydecided 21 Oct 2026
GA-Q4What happens to geoops compositingopen
GA-Q5Do geoops operators accept a DataArraydecided 23 Oct 2026: kernel operators yes, lazily; geometry operators no
GA-Q6map_over on xarrayopen
GA-Q7Dim-name conventionsopen
GA-Q8The name of the curvilinear carrieropen
GA-Q9check_dims on pipekit_ops.Signaturedecided 21 Oct 2026
GA-Q10Edit geotoolz issues #511–#534 in placeopen

5Labeled lane (LL)

IDDecision or questionStatus
LL-F1CRS as a spatial_ref coordinate with crs_wkt, CRS.to_cf() attributes and GeoTransformdecided 23 Oct 2026 (with GA-Q2)
LL-F2Per-band metadata: band holds names; wavelength and FWHM are non-index coordinatesopen
LL-F3Multi-resolution products as a DataTree, one node per gridopen
LL-G1Where a coordax grid coordinate livesdeferred until esmax or vardax asks
LL-G2Accept coordax’s static grid; batching and gradients stay on carriersdecided 21 Oct 2026 (with GA-T4)
LL-H1Operators on labeled data: geometry operators through xrops.lift; kernel operators on DataArraydecided: lifting 22 Oct 2026 (OP-O4), kernel operators 23 Oct 2026 (GA-Q5)
LL-H2geoarray owns the converters, behind extrasdecided

6pipekit kernels (PK)

IDDecision or questionStatus
PK-P1Adapter interface and registry in pipekit core; adapters and dim-level functions in pipekit-arrayforced
PK-P2A kernel’s spec is declared at the operator layer, not by a decoratoropen
PK-P3Abstract core-dim letters plus a core= mappingopen
PK-P4The xarray adapter lives in pipekit-array [xarray]open
PK-P5DataArray only at first; Dataset and DataTree dispatch stays in xropsopen
PK-P6pipekit_jax.to_jax lives in pipekit-jaxforced
PK-P7The carrier for outputs that drop a spatial dim: pipekit_array.DimArray (data, dims, labels; no georeference, alignment or arithmetic)decided 23 Oct 2026

7Operators (OP)

IDDecision or questionStatus
OP-O1Observation and sensor kernels in geoops; state-domain kernels (MLD, budgets) in xrops, which never re-implements a geoops kerneldecided 22 Oct 2026
OP-O2One named-dims einx bridge in pipekit-array [einx]; geoops keeps only SpatialPooldecided 29 Oct 2026
OP-O3to_rows / from_rows plus one scikit-learn Estimator in pipekit-array [sklearn]decided 29 Oct 2026
OP-O4Lifting is xrops.lift(op, dim=...); geoops has no [xarray] extradecided 22 Oct 2026
OP-O5Operators use KernelOp by composition, not subclassingdecided 29 Oct 2026
OP-O6The backends vocabulary: "numpy", "jax", "dask"; a DataArray reports its data’s backenddecided 29 Oct 2026
OP-O7The diagnostic gradient kernel lives in geoops; model-grade calculus stays in finitevolXdecided 22 Oct 2026
OP-O8Whether an L3 algorithm calls another L3 algorithm inside a differentiated costopen (decide first)

8Operator coupling (OC)

IDDecision or questionStatus
OC-Q1The name: “coupling class”, not “family” (taken for carrier families and namespaces)decided 4 Nov 2026
OC-Q2Where the class lives: a coupling class attribute holding a frozen Coupling record, public in geoops.carrierdecided 4 Nov 2026
OC-Q3The dim vocabulary: geoarray’s dims, with y x as one spacedecided 4 Nov 2026
OC-Q4The contract test requires measured ⊆ declared, and equality where the probe is exact (indices, spectral, radiometry)built as recommended (geotoolz #616), open for review
OC-Q5The axis of the N-ary reducers: time for compositing, source for different sensorsopen
OC-Q6Where the probe lives: geoops.testing.measure_coupling / assert_coupling, with a report scriptbuilt as recommended (geotoolz #615), open for review

9Package layout (PL)

IDDecision or questionStatus
PL-Q1The xarray bridgessuperseded by OP-O2, OP-O3 and OP-O7
PL-Q2The xarray Operator base in xrops._srcdecided 29 Oct 2026 (its Signature part with GA-Q9)
PL-Q3The reader’s name: xrproductsdecided 29 Oct 2026
PL-Q4How to split xrtoolz.geodecided 29 Oct 2026
PL-Q5No shims: old import paths are removed outrightdecided 29 Oct 2026
PL-Q6State-physics families stay in xropsdecided 22 Oct 2026 (OP-O1)
PL-Q7geoproducts or xrproducts, by what one read returnsdecided 29 Oct 2026
PL-Q8load_states stays in geocatalogdecided 29 Oct 2026
PL-Q9Points: a CF DSG Dataset on the labeled side, GeoPoints on the array sideGeoPoints decided; DSG open

10Levels across the stack (SL)

IDDecision or questionStatus
SL-O1Ocean and atmosphere diagnostics: option D (xrops L1 and L2; model closure to esmax; products to xrproducts)decided 29 Oct 2026
SL-O2Carrier code behind [geo] and [xarray] extras (esmax-core[geo])open
SL-O3CH₄ column physics: L1 in radtrax, xarray operators behind radtrax[xarray]open
SL-O4A plumax.runs module per model for L3 runsopen
SL-O5Fix filterax and optax_bayes missing from the capability index before classifying themopen
SL-O6What xtremax.simulations is foropen
SL-O7somax’s future is the esmax workspaceopen (see ES-N1)

11esmax (ES)

IDDecision or questionStatus
ES-N1The umbrella name: esmaxopen
ES-N2One distribution per component, like pyroxopen
ES-N3Land and ice start only with real code (phase P4)open
ES-N4les_fvm stays in plumaxopen
ES-N5Synthetic climates are not in esmaxopen

12Neural fields (NF)

IDDecision or questionStatus
NF-D1Deterministic neural-field parts in geonnax, probabilistic in pyrox-nn, assimilation in vardax; case 9, case 11 and methane stage 3 are the acceptance testsopen (proposed; Wave 6)
NF-O1Averaging kernels: field on pressure levels or one collapsed weight per pixelopen
NF-O2pyrox Parameterized registry under eqx.tree_at rebuildsopen
NF-O3geonnax field names pyrox-nn swaps are added to, never renamedopen
NF-O4Error bars for neural-field 4D-Var: ensemble spread from the startopen
NF-O5SWOT wave-correlated noise in case 9open
NF-O6Ownership of field derivatives (geonnax.diffops vs xrgrad vs spectraldiffx)open
NF-O7Whether compression is worth buildingopen (research, geostack#86)