Meridian / Case study
Rebuilding the Past Without Rewriting It
Meridian began with a personal need. I had years of exported Google location history and wanted to make that record understandable to someone other than myself. Importing it and putting it on a map was the beginning. The harder question was what the software was entitled to say about the past.
- Period
- July–August 2026
- Field
- Software / Geospatial Evidence / Data
The first version
The first implementation, in July 2026, was a relatively small Google Timeline ETL pipeline and viewer. ETL describes the practical work of extracting data, transforming it into a useful structure, and loading it somewhere it can be queried. Google Timeline JSON became structured data that could be grouped, mapped, and explored. I wanted another person to be able to navigate the history and understand what supported a conclusion.
That initial framing made the problem seem mostly organizational. There was a large archive; the application needed to make it legible. But even a useful timeline requires interpretation. A parser decides how to read a source structure. A reconstruction decides which observations belong together. A map decides what to connect. Those decisions can make a record easier to understand while also making it appear more complete or certain than its source.
The import-and-visualization problem became an evidence problem. If I changed a rule and the timeline changed, I needed to distinguish a better interpretation from a different source record. Google Timeline observations were the source material, not independently verified physical truth. Preserving that distinction became part of the application's design.
Meridian is the current user-facing name. Timeline Analyzer remains the engineering and repository identity. The reasoning depends on what the Google Timeline sources record.
Preserve the source
I moved toward an immutable evidence model: preserve the exact uploaded bytes before treating their contents as something to interpret. Content-addressed identity gives source content an identity based on the content itself. It makes identical material recognizable without depending on a convenient name or the order in which it arrived.
The next distinction was between a source record and an occurrence of that record. Identical information can appear more than once. Recognizing it as identical is useful, but it should not erase the fact that it appeared in different places or was repeated. The content answers one question; the record of where it occurred answers another.
That changed what deduplication meant to me. It could reduce repeated representation of the same information while preserving every occurrence. Otherwise, an operation intended to tidy the data would remove part of its history. Nor should repeated content automatically count as independent corroboration: repetition and independent support are different ideas.
Preserving source material also established a boundary around later improvements. A changed parser or reconstruction policy should produce a changed interpretation, without overwriting the material it interprets.
Interpretations can change
The architecture separates source bytes, source records and their occurrences, parser interpretations, canonical reconstruction, and derived presentations or reports. Each step has a different responsibility. Bytes preserve the upload. Records and occurrences retain what appeared within it. A parser gives that material a structured interpretation. A canonical build assembles the application's reconstruction, and the presentation makes that reconstruction readable.
Canonical is a term for the reconstruction the system organizes around. It is not a claim that software has independently verified the past. The reconstruction still rests on source observations and explicit rules. Calling it canonical should never dissolve that dependence.
Versioned parser results and canonical builds let the software's understanding evolve while keeping earlier interpretations distinguishable. If a later parser reads a supported structure differently, that is a change in interpretation with its own version. It should not look as though the source always said whatever the newest software now concludes.
I wanted a result to remain traceable through those layers. At the reviewed revision, the storage and provenance model supports richer raw-source detail than the current interface exposes. The architecture is therefore further along than the UI in making every part of that trail available for direct inspection. Rebuilding the understanding is useful; making its basis accessible is continuing work.
Don't invent the missing road
A map creates a strong temptation to fill a gap. When observations exist on either side of missing movement, a connector can make the display easier to follow. But visual continuity is not evidence that a particular journey occurred. The surrounding locations do not supply the missing movement segment.
Meridian distinguishes observed movement from reconstructed Journeys supported by movement evidence. Trips are a further derived grouping. A visual or inferred map connector is another kind of object again. These distinctions keep a presentation choice from quietly becoming canonical travel.
If the interface draws an inferred connector, it must remain explicitly distinguishable from recorded movement. It can help a reader orient themselves without claiming that the missing road was observed. A plausible connection is still an inference, and a gap in the source should remain a gap in what the system claims to know.
This was one of the most useful constraints I encountered. I could improve the experience without requiring the reconstruction to say more. Sometimes the trustworthy behavior is to refuse an inference, even when the resulting timeline looks less complete.
“How long was I there?”
A question that sounds simple can conceal several different calculations. Elapsed span measures the distance between the earliest start and latest end. Summed observed intervals add the duration of each observation. The union of observed intervals counts the time covered by at least one observation, so overlapping time is counted once.
Consider a wholly synthetic example: three observations at an unnamed place, from 09:00 to 10:00, 09:30 to 10:30, and 11:00 to 11:30. The elapsed span is two and a half hours. Summing the observations also gives two and a half hours, because it counts the overlapping half-hour twice. Their union covers two hours. There is a half-hour gap between 10:30 and 11:00, which the elapsed span includes and the union does not.
The matching totals for span and sum in this example hide different meanings. One includes an unobserved gap; the other double-counts an overlap. None of these measures independently proves continuous physical presence. Meridian distinguishes the measures so that a report can be precise about the question its number answers.
Calendar boundaries require just as much care. A reporting timezone determines which local day an interval belongs to. An interval crossing midnight may need to be apportioned across days. Daylight-saving rules mean that a local calendar day does not always contain 24 elapsed hours, and local clock labels can repeat or be skipped. Overlapping observations still need a defined counting policy after those boundaries are applied.
Working through these cases made duration feel less like a field to display and more like a definition to preserve. A useful answer needs both a number and a clear account of what was counted.
A Place is not a Location
Geography brought a related modeling problem. A canonical geographic Place, provider knowledge about that Place, and a human semantic Location are different things. Coordinates can identify geographic evidence. A provider can add a name or other metadata. Neither automatically supplies the meaning a person attaches to it.
I wanted human meaning to survive a reconstruction rebuild or a provider refresh. If a provider changes its label, that should not silently redefine a person's semantic Location. If the application rebuilds its geographic understanding, it should not discard that meaning as though it were merely a temporary display value.
Separating these layers allows enrichment to change without being confused with the underlying evidence or the human interpretation of a place. It also makes the origin of a label consequential: a provider description and a human association have different authority, even when they are displayed close together.
The newest dataset is not necessarily the right dataset
A successful build answers a processing question: did this work complete? It does not automatically answer the publication question: is this the record another person should review? Treating the most recently completed build as the active dataset would let completion order make that decision.
The system developed explicit distinctions between successful processing, reviewer eligibility, and active publication. A reconstruction can exist without becoming eligible for review, and eligibility does not itself make it the published record. That separation makes the choice of what reviewers see an explicit part of the workflow.
For me, this followed from preserving interpretations. Keeping multiple builds is only useful if the application also knows which one it is presenting and why. A later result should not displace the review record simply because it finished last.
Intelligence without a runtime LLM
I used an agent-assisted engineering workflow while building Meridian. That is distinct from the reasoning the application performs when it processes a person's archive. The inspected repository contains no runtime language-model pipeline for deciding what happened.
The application's intelligence is primarily deterministic: versioned parsers, reconstruction policies, aggregation, temporal logic, trip grouping, geographic enrichment, and controlled reports and presentation. These mechanisms do substantial interpretive work. Their value comes from having rules and boundaries that can be examined, rather than from generating a narrative that sounds convincing.
AI helped me build Meridian. Meridian itself did not need a language model to decide what happened. That distinction describes an engineering choice for this problem, not a position against AI. I needed changes in the answer to be explainable in terms of source material, parser versions, and reconstruction policy.
Determinism does not establish that an observation is accurate or a rule is correct. It gives me a stable basis for examining the rule and its consequences. Tests and architecture decisions can document and challenge that behavior without turning a source observation into verified truth.
What the work clarified
I began by wanting someone else to understand a large archive. Building Meridian forced me to define what understanding that archive actually required: preserving the source, accounting for repeated records, naming interpretations, distinguishing observed movement from inferred connections, and being precise about time.
The timeline is a reconstruction of evidence. Its usefulness depends on whether a reader can understand the relationship between the two. Better software can produce a better reconstruction, but it should leave earlier interpretations distinguishable and keep uncertainty visible. An absent observation should not disappear behind a more polished map.
The work clarified a practical standard for me. When software reconstructs history, it should be able to explain what supports its conclusions and which rules brought it there. Sometimes that explanation ends at the edge of the available evidence. Leaving that edge visible is part of the work.