Plate № 32 · Recoverability · backup depth
A pattern from the gf.cx specimen book
See how deep the safety net goes
"Is it possible to see the number of back-ups of that file, on say rsync.net?" … "Adding an accordion could allow a graphical visual that shows this mapping." … "Add data-tooltips for hover state on date / 3 days ago / 15th March 2026."
The problem
A recoverability surface that reports "backed up · 9.9h old · green" answers only the shallowest question: does one copy exist? It hides depth. A single green tick reads identically whether the off-site sink holds one snapshot or twenty-seven — and whether the last real backup was daily-fresh or a lonely copy from six weeks ago that nothing has touched since.
The honest question is how recoverable: how many point-in-time copies actually exist, spread across what span, and — the part a bare count still can't tell you — when the backups became regular. Two sinks can both say "12 copies" while one drip-fed them over a year and the other has run daily for a fortnight. The reader needs to see that difference, not compute it.
The element, in-page
The specimen below is the real shelf module (assets.gf.cx/depth-timeline) rendering live agent-edge data — the same code the status.gf.cx/core page ships. A native <details> accordion (no JS to display; Rocket-Loader-safe) folds the visual away until asked. Open it: twelve dots, each one a recoverable snapshot placed at its true date across the span. Two dots almost touch at the far left (two backups on 22 Jun), then the line breathes through July, then clusters daily from 30 Jul — the "it got regular" story a count can't tell. Hover any dot for its data-tip readout: relative age · long date.
Depth12recoverable restore points on rsync.net · 22 Jun 26 → 5 Aug 26
↑ Live — click show timeline, then hover a dot. This is the production shelf module, not a mock-up.
The shape — three deliberate choices
- HTML dots, not SVG. The dots are
<span>s positioned withleft:<pct>%, precisely so each can host the shared data-tip tooltip primitive — SVG elements can't carry CSS pseudo-elements, so an SVG<circle>could never show the styled hover card. Choosing HTML keeps the whole thing zero-JS to display when server-rendered. - Placed by true date, not evenly spaced. A dot's
leftis its real fraction of the first→last span. Even spacing would draw a tidy ruler and throw away the signal; true placement is what makes "sparse then daily" visible at a glance. - Folded behind a native
<details>. Depth is a secondary, on-demand read — the accordion keeps the card calm (one line: Depth 12 …) until the reader wants the map. Native<details>means no JS, so Cloudflare Rocket Loader can't break it.
The tooltip trap
Each dot sets data-tip and aria-label — never title. The browser fires its own grey native tooltip from title= ~500 ms after hover, doubling up with the styled card. aria-label satisfies screen readers without triggering the UA tooltip. The readout format is deliberately two-register — "3 days ago · 3rd August 2026" — the relative age for instant recency, the ordinal long-date for the exact when.
Where it applies
- Any recoverability / backup surface with per-item snapshot history. Origin and reference consumer: status.gf.cx/core, where every off-sited repo's page shows its restore-point timeline. Fed by the fleet-wide
restic_backup_depth.py, which emits one dot per restic snapshot that actually contains the asset. - Static surfaces emit the
.depth-accmarkup server-side and load only the CSS — nothing to run to display it. - Dynamic surfaces drop a
<span data-depth-timeline='[…ISO…]'>placeholder and letdepth-timeline.jsrender it (auto on load;window.gfcxDepthTimeline(root)for fetched-in nodes). - Skip when only a single copy exists — a one-dot line is noise, so the module renders nothing and the surface keeps its plain count line. Depth needs ≥ 2 points to mean anything.
Reusable elements
The named, copyable pieces — lift any one without the others:
- Shared asset
assets.gf.cx/depth-timeline/—depth-timeline.css(the accordion + dot-strip) +depth-timeline.js(client-render from a JSON stamp list) + README + live demo. One CDN source of truth; import the CSS, optionally the JS. Requirestooltip.cssfor the hover bubble. - HTML-dot timeline over SVG — the
position:relativerail withleft:%-placed.depth-dotspans. The reusable insight: when points need styled tooltips, place them as HTML, not SVG. - The
data-tip+aria-labelpairing — the tooltip primitive applied to a data-viz point, with the no-double-tooltip discipline baked in. - Two-register date readout —
"<relative> · <ordinal long date>"(3 days ago · 3rd August 2026). Relative for recency, absolute for precision. The_human_ago/_long_datehelpers exist in both the server producer and the client JS so the two paths render identically. - Server producer
gfcx_core_snapshot.py::_restore_depth_timeline— the reference emitter that turns a restic depth record into the.depth-accmarkup for a static page.
Reference
- Source
- Dan, 2026-08-06 — asked whether the restore-point count on
status.gf.cx/core/agent-edge/could be seen as a graphical mapping in an accordion, with hover tooltips carrying relative + absolute dates. - In use / example
- status.gf.cx/core/agent-edge/ — every off-sited asset's page renders its restore-point timeline from the shared shelf module. The live specimen above is that same module and data.
- Reusable elements
- Shared CDN CSS+JS shelf · HTML-dot-over-SVG timeline · data-tip + aria-label pairing · two-register date readout · server producer helper (listed above).
- Origin
- Extracted from the
/corerecoverability surface the day it was built, generalised toassets.gf.cx/depth-timelinein the same session — the favicon-control-plane / provenance-footer single-source discipline applied to a backup-depth visual. Sibling of the data-tip tooltip it builds on. - Build cost
- ~15 min to lift the inline
/corerenderer into the shelf module (CSS + client JS + README + demo); ~1 line per consuming surface (import the CSS, emit the markup or drop adata-depth-timelinespan).