MileageAlgorithm

The seam that lets more than one mileage algorithm exist at the same time.

Today a tracking app has exactly one distance algorithm, welded into the service that acquires the fixes. That makes three ordinary questions unanswerable: is the other algorithm better on this route, what does this threshold actually buy, and did the change I just made help. You cannot answer any of them by reading code, because the algorithm cannot be run without a phone, a drive, and a day.

This interface exists to make those questions cheap. Everything here is deliberately pure:

  • no coroutines, no Dispatchers, no I/O, no logging

  • no clock — time arrives as Fix.timeMs and never as now()

  • no platform types, no Android, no dependencies at all

That purity is not tidiness for its own sake. It is the single property that makes replay, shadow-mode comparison and parameter sweeps possible: an algorithm that cannot be re-run deterministically over a recorded trace cannot be compared against anything, and a comparison you cannot re-run is an opinion.

:location is the right home precisely because it has zero dependencies and builds for every target including wasmJs. Keep it that way — the moment this file needs a dependency to compile, the harness that replays traces in a browser preview stops working.

ponytail: three implementations, not four. Two of the four known algorithms differ only in threshold constants, so they are two TuningProfiles of one class, not two classes. Sibling classes that differ only in numbers are the mistake this abstraction exists to avoid.

Inheritors

Properties

Link copied to clipboard
abstract val id: AlgorithmId

Stable identity, used for persistence, selection and shadow-mode result attribution.

Link copied to clipboard
abstract val knobs: List<KnobSpec>

The knobs this algorithm understands. Drives generic tuning UI and automated sweeps.

Functions

Link copied to clipboard
open fun flush(): List<FixResult>

Emit anything still buffered and end the journey.

Link copied to clipboard
abstract fun process(fix: Fix): FixResult

Consume one fix and report what it contributed.

Link copied to clipboard
abstract fun reset(session: SessionContext)

Begin a new journey. Must clear all accumulated state.

Link copied to clipboard
abstract fun restore(state: AlgorithmState)

Resume from a snapshot.

Link copied to clipboard
abstract fun snapshot(): AlgorithmState

Capture enough state to resume this journey later. Must round-trip with restore.