Skip to content

The one-call Study

LunarTrace 0.2 puts the temporal method behind one call. You name a site, an event interval and a product type. You get back a Study: the observations before and after the event, every PRE × POST pair, the pairs that no other pair beats, and a digest that proves none of it moved.

import lunartrace as lt
study = lt.temporal.study(site=(-69.3741, 32.32),
event="2023-08-23T12:33Z/12:35Z",
products="LRO/LROC/CDRNAC4",
archive="vikram-2026-10-14")
study.frontier("angles") # the 13 pairs nothing beats
study.why("pair:002ea7a82e1060f1") # names the pair that beat it
study.save("vikram.study.json") # replays to the same sha256

archive="vikram-2026-10-14" replays the archived pages of the 14 October 2026 run. Those pages ship inside the package, so the call needs no network and returns the same Study every time. A live call, with archive left out, fetches the Lunar ODE archive now. The archive grows, so it can return more products than the 108 of that run, and a different digest.

The call is a facade over the method lunartrace.temporal_prepost/v1. It does not add a method and it does not add a field to the Study record. Everything on this page is a view over that record.

Install LunarTrace 0.2 with pip install lunartrace (Install). The call below is the one above, as a session you can paste. The repr says retained: the Study was compiled from the pages of the 14 October 2026 run.

>>> import lunartrace as lt
>>> study = lt.temporal.study(site=(-69.3741, 32.32),
... event="2023-08-23T12:33Z/12:35Z",
... products="LRO/LROC/CDRNAC4",
... archive="vikram-2026-10-14")
>>> study
Study(vikram:minute-envelope · retained · sha256:3d75a662… · 108 products · 2,340 pairs)
>>> study.digest
'sha256:3d75a662ce75f00cd34dd9ba288012ad471c73b1e56ecf0abe36896d0b199dd0'

Each example on these pages is self-contained: copy one into a fresh session and it runs. A live run says live in its repr and is never claimed to reproduce those numbers.

A frontier is the set of pairs that no other pair beats on every objective. No weights are chosen. The angles frontier minimises the three angle differences and holds 13 of the 2,340 pairs.

>>> import lunartrace as lt
>>> study = lt.temporal.study(site="vikram", event="vikram:minute-envelope",
... products="LRO/LROC/CDRNAC4", archive="vikram-2026-10-14")
>>> len(study.frontier("angles"))
13
>>> print(study.why("pair:002ea7a82e1060f1"))
pair:002ea7a82e1060f1 is off the angles frontier: pair:0033128b0d75e56c is at least as good on every angle (Δsun 2.78° vs 6.79°, Δview 0.29° vs 0.83°, Δphase 2.67° vs 3.14°) and strictly better on one.
>>> print(study.why("pair:1ca27f6bd456b92d"))
pair:1ca27f6bd456b92d is on the angles frontier: no pair beats it.

The file holds the canonical bytes of the record. Loading it checks the digest again.

>>> import lunartrace as lt
>>> study = lt.temporal.study(site="vikram", event="vikram:minute-envelope",
... products="LRO/LROC/CDRNAC4", archive="vikram-2026-10-14")
>>> study.save("vikram.study.json").name
'vikram.study.json'
>>> lt.temporal.load("vikram.study.json").digest == study.digest
True
PageWhat it covers
StudyThe arguments, the registry, live against retained
Frontiers and whyThe four frontiers and the witness behind each answer
Save and replayThe file, the sources bundle, verify and replay
NotebookOpen a saved Study as a marimo notebook
Command lineThe same operations as the lunartrace console script
ReferenceEvery public name

The Study’s four limits are in the file, word for word. study.limits returns them:

>>> import lunartrace as lt
>>> study = lt.temporal.study(site="vikram", event="vikram:minute-envelope",
... products="LRO/LROC/CDRNAC4", archive="vikram-2026-10-14")
>>> for limit in study.limits:
... print(limit)
Temporal PRE/POST adjacency is not a surface-change claim.
Footprint intersection with the query box is not image registration or alignment.
ODE pagination reconciles the declared Count at query time; archive currentness and a coherent provider snapshot are not established.
Source authenticity is not independently established beyond retained byte digests.

The Study is recorded as METHOD_EXECUTED. See Limitations for what each limit rules out.