Skip to content

antikythera_spectral.bridge — Pyodide Bridge API

Version: v0.1.0 (36 methods).

The bridge is the consumer-facing entry surface — what a Pyodide / web / CLI consumer calls into. Every method:

  • returns a Pyodide-JSON-serializable dict,
  • carries an 'ok' key (True for valid input + computation; False for caller-side input errors with an error string explaining why),
  • raises only on genuine internal bugs (not user-input issues).

Numpy arrays in return values are real-valued. Complex state vectors serialize as Float32 real+imag interleaved of length 2*D so JS consumers use new Float32Array(...) directly. See ADR 0002.


Method index by group

§5.1 — State ← date

Method Returns
get_dial_state(jd_tdb, *, D=940, backend='bit') Per-dial residues + HDC vector. v0.3.0 default-backend flip: backend='bit' (default) returns state as {dtype: 'uint64', shape: [n_words], n_bits: D, packed_uint64: list[int]}; backend='complex128' returns the v0.2.x {dtype: 'complex128', shape: [D], interleaved_f32: list[float]} shape. The envelope adds 'backend': str so consumers can dispatch. Dial residues / angles are backend-independent.
get_dial_angle(jd_tdb, dial) Continuous angle (D-independent)
get_pointer_xy(jd_tdb, *, layout='dial' \| 'spatial', D=940) Per-dial render coords (always uses the complex128 path internally; backend keyword not exposed because the return is rendering coords, not raw state)
get_all_dial_metadata() List of supported dials with cycle info
get_version() Package version + frozen-data manifest

§5.2 — Date ← state

Method Returns
decode_dial(state_vec, dial, *, D=940) Recovered residue. Auto-detects the backend from the input shape (v0.3.0): uint64 array / dict-with-packed_uint64 → bit-ALU decoder; complex128 / interleaved-Float32 → dense FHRR decoder. Response includes 'backend': str so the caller can confirm the dispatch. Both decoders return D-bin residues in [0, D).
decode_to_jd(state_vec, *, D=940, reference_jd=REFERENCE_JD) Median JD across dials. Same auto-detect dispatch as decode_dial; response includes 'backend': str.

§5.3 — Calendar conversion

Method Returns
jd_to_gregorian(jd_tdb) Proleptic Gregorian date
gregorian_to_jd(year, month, day, hour=0, minute=0, second=0, era='CE') JD
jd_to_julian_calendar(jd_tdb) Julian-calendar date (pre-1582)
jd_to_athenian(jd_tdb, *, archon_table='attic') Attic month + day; archon=null in v0.1.0 (ADR 0007)
jd_to_olympiad(jd_tdb) Olympiad number + year-in-Olympiad

§5.4 — Astronomical observables

Method Notes
get_visibility_windows(jd_lo, jd_hi, planet, kernel='de421') Skyfield required
get_next_heliacal_rising(jd_tdb, planet, kernel='de421') Skyfield required
get_solar_elongation(jd_tdb, planet, kernel='de421') Skyfield required
get_eclipse_anchors(era='hellenistic' \| 'modern' \| 'all') Frozen data
get_period_relations(source='mulapin' \| 'almagest' \| 'all') Frozen data
find_eclipses(jd_lo, jd_hi, *, kind='all', kernel='de421') Skyfield required

§5.5 — Operator workflow (§11.6.16 simulation, ADR 0006)

Method Notes
start_operator_session(initial_jd, *, D=940, dials='all') Returns OperatorState
operator_advance(state, delta_days) Returns new state
operator_observe(state, dial, observed_residue) Records anchor
operator_diagnostics(state) Per-dial drift
set_anchor(dial, jd_tdb, observed_residue) Bare CalibrationDelta
apply_anchor(state, calibration_delta) Apply to state

§5.6 — Cross-comparators

Method Notes
compare_ephemerides(jd_tdb, body, kernel_a, kernel_b) DE-kernel delta
compare_models(jd_tdb, body, model_a, model_b, kernel='de421', params='ptolemy') Mars-only. model_* ∈ {uniform, epicycle, equant, bronze} (bronze added v0.3.0). params ∈ {ptolemy, freeth_2012, freeth_2021} (added v0.3.0; default 'ptolemy' for backward-compat).
compare_reconstructions(jd_tdb, *, dials='all') Freeth/Wright/Price disagreements

§5.7 — What-if + archaeology (ADR 0008)

Method Notes
encode_with_custom_train(jd_tdb, dial, p, q) p,q ∈ [1,500], gcd(p,q)=1
compare_to_ground_truth(jd_tdb, dial, p, q) Custom vs canonical residual
get_fragment_inventory(fragment='all') Reads _data/fragments.json

§5.8 — Babylonian Goal-Year

Method Notes
goalyear_predict(planet, jd_tdb, *, source='mulapin') Lookup date N years prior
goalyear_compare(planet, jd_tdb) Goal-Year + encoder side-by-side

§5.9 — Animation export

Method Notes
encode_range(jd_lo, jd_hi, *, step_days=1.0, D=940) Time-series of states
export_animation(jd_lo, jd_hi, step_days, *, format='json' \| 'npz', D=940) Base64-encoded payload

§5.10 — Hypothesis battery

Method Notes
run_hypothesis_battery(*, ephemeris=None) All 31 rows
get_hypothesis(id) Single-row lookup

Common return shape

Success:

{"ok": True, "...": ...}

Failure (caller-side input):

{"ok": False, "error": "..."}

Internal failures raise; callers should catch broadly only at the JS / Pyodide boundary.

State vector format

Complex-valued HDC state of dimension D serialised as real+imag interleaved Float32 of length 2*D. For cell k:

state[k] = arr[2*k] + 1j * arr[2*k+1]

This matches the chess-spectral qm_4d_bridge ComplexArray convention; web consumers cast directly to Float32Array.

Validation patterns

  • jd_tdb must be finite, in approximately (-1_000_000, 5_000_000) (covers any plausible Julian Day).
  • D must be in (940, 13440) (Callippic / packing variants).
  • dial must be in the frozen list returned by get_all_dial_metadata.
  • kernel must be in ephemeris.ALLOWED_KERNELS (frozen tuple).
  • planet must be in visibility.SUPPORTED_PLANETS.
  • layout must be in ('dial', 'spatial').

All validations run before any expensive computation.

ADR cross-reference

  • ADR 0001 — pure-Python only in v0.1.0
  • ADR 0002 — bridge API shape (this document is the contract)
  • ADR 0003 — ephemeris allowlist (CodeQL discipline)
  • ADR 0006 — stateless bridge (no server-side state)
  • ADR 0007 — Athenian-calendar fidelity caveats
  • ADR 0008 — what-if mode bounded input
  • ADR 0009 — single-branch rollout
  • ADR 0010 — TestPyPI pre-merge gating