timescale.info
Sign inSign up

How OpenChronology was built

Every merged pull request of openchronology/timeline-app, its first week of commits and its releases; and before them the 2020 PureScript editor, from snapshots of its deleted repositories in the Wayback Machine. Written to this server through the HTTP API.

327 moments · 2020-03-09T00:15:08Z CE – 2026-11-02T20:11:21Z CE · by @athan · @athan

#29 · Relate moments and durations, draw relationship arcs, and separate by connections

  • timeline-app
  • pull request

Implements #22 as planned in our discussion: plain links, arcs included, separating moves the entity together with its relations, and the "Related to" section lists direct relations plus a transitive count. ### Model - **Format:** a top-level `relationships` array of undirected links, `{a, b}`, where each endpoint is `{moment}` or `{duration}`. The two ID spaces are separate, so each endpoint names its kind. - **Rules:** links are n-to-n. Self-links and missing endpoints are rejected, and each link is stored once in canonical order. - **Deletion:** deleting an entity removes its links when saved. Until then, undoing the deletion restores them. - **Round trips:** links survive `.ochx`, `.och`, server saves, forks and history. Merges treat them as a set, keeping a link only while both of its entities survive. ### UI - **"Related to"** in moment details and the duration dialog: - **Listing:** direct relations, 25 at a time, each with its time or extent. Choosing one opens it. - **Transitive count:** a line such as "14 more through other relationships". - **Editing:** **Add a relationship** (search titles and notes) and **×** to unlink. Both are covered by Undo/Redo. - **Separate related / Separate all connected:** moves the entity and its direct, or transitively reachable, relations into a read-only track above everything else. This reuses the derived-view separation from #28. - **Arcs** above the axis connect related entities, ending at a moment's time or a duration's start. - **Off-screen ends:** arcs to off-screen entities run off the edge. - **Short arcs:** not drawn when both ends fall inside one summary. - **Limits:** at most 256 per window, with a notice when more cross it. - **Hover:** shows what an arc connects. ### Arcs without loading the timeline - **Index:** each relationship is indexed as a fixed interval between its endpoints' times, in the **same augmented interval tree as duration bands**. - **Viewport queries** visit only subtrees touching the window and skip subtrees made entirely of arcs shorter than the threshold. The view gets just the arcs it needs. ### Storage and queries | | Links | Arcs | Transitive reach | | --- | --- | --- | --- | | PostgreSQL | `oc_relationships` (indexed from both ends) | `oc_edge_nodes` | recursive CTE | | Desktop SQLite | `relationships` table | `edge_intervals` / `edge_nodes` | recursive CTE | | In-memory | adjacency map | in-memory tree | breadth-first search | - **`related` query:** direct relations, paged by kind and ID. The first page also returns `direct` and `reachable` counts. - **Separation filters:** relationship filters for the separation views. - **Sparse saves:** send idempotent `relationshipChanges`. ### Tests - **PostgreSQL oracle** (`test/relationships-postgres.mjs`, added to CI) checks against the in-memory index: - arcs over 30 random views of a random graph; - related listings across pages, with exact direct and reachable counts; - relationship separations; - sparse link edits with cascade on deletion. - **Rust:** round trip, arcs and their collapse, related pages and counts, direct and transitive views, sparse link changes with cascade, and rejection of self or missing links. - **Unit:** canonical form and validation, direct and transitive reach, links surviving an undone deletion, arcs, separation filters, the sparse overlay/patch/apply on client and server, save rebasing, and merges. - **Browser** (served and offline): linking by search, the transitive count, arcs, navigation, unlink with undo, and separating all connected entities. - **Passing locally:** 179 unit tests; 20 Rust tests; all PostgreSQL suites run (except `sql-oracle`, which needs a same-host database and runs in CI); and the Chromium and Firefox served and offline browser suites. ### Not included (possible follow-ups) - **Labels on links:** plain links were chosen; adding labels later needs no data migration. - **Arcs inside separated or compared tracks.** - **Clicking an arc** to open either e…

Sources

Open #29 · Relate moments and durations, draw relationship arcs, and separate by connections in the timeline