Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,87 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [10.3.2] — 2026-02-09 — Seek CLI fixes & demo portability

### Added

- **`--save=NAME`, `--load=NAME`, `--drop=NAME` equals form**: `parseSeekArgs` now accepts `=`-separated values for `--save`, `--load`, and `--drop`, matching the existing `--tick=VALUE` form.

### Fixed

- **BATS CI: missing `append-patch.js` helper**: `test/bats/helpers/append-patch.js` was untracked, so Docker builds (which copy from the git context) never included it — causing test 55 to fail with `MODULE_NOT_FOUND` on Node 20.
- **`seek-demo.tape` not portable**: Replaced hardcoded `$HOME/git/git-stunts/git-warp` with `export PROJECT_ROOT=$(pwd)` captured before entering the temp sandbox.
- **`emitCursorWarning` / `applyCursorCeiling` JSDoc**: Clarified that non-seek commands intentionally pass `null` for `maxTick` to skip the cost of `discoverTicks()`.
- **`_resolveCeiling` treated `undefined` as valid**: The `'ceiling' in options` check returned `undefined` when options contained the key but no value. Switched to `options.ceiling !== undefined` so explicit `null` still overrides the instance ceiling but `undefined` correctly falls through.

## [10.3.1] — 2026-02-09 — Seek polish, arrowheads & demo GIF

### Added

- **Seek demo GIF** (`docs/seek-demo.gif`): Animated walkthrough showing `git warp seek` time-travel — graph topology visually changes at each tick while `git status` proves the worktree is untouched. VHS tape at `docs/seek-demo.tape`.
- **README seek demo**: Embedded `seek-demo.gif` in the CLI section below the seek command examples.
- **ROADMAP backlog**: New `## Backlog` section with two future ideas — structural seek diff (`diffStates()`) and git-cas materialization cache.
- **Op summary renderer** (`src/visualization/renderers/ascii/opSummary.js`): Extracted operation summary formatting from history renderer into a shared module used by both history and seek views.

### Fixed

- **ASCII graph arrowheads missing**: `drawArrowhead` was silently dropping arrows when the ELK endpoint fell inside a node's bounding box. Now steps back one cell to place the arrowhead just outside the node border.
- **Seek ASCII renderer**: Reworked swimlane dashboard with improved windowing, writer rows, tick receipt display, and op summary formatting.
- **Seek ceiling via public API**: Replaced direct `graph._seekCeiling` mutation in `materializeOneGraph` and `handleSeek` with `graph.materialize({ ceiling })`, using the public option instead of poking at internals.
- **Seek timeline missing currentTick**: When the active cursor referenced a tick absent from the discovered ticks array, the renderer fell back to index 0 and never showed the current tick marker. Now inserts the cursor tick at the correct sorted position so the window always centres on it.
- **Docs `--tick` signed-value syntax**: Updated GUIDE.md, README.md, and CHANGELOG examples to use `--tick=+N`/`--tick=-N` (equals form) for signed relative values, matching BATS tests and avoiding CLI parser ambiguity.
- **Ceiling cache stale on frontier advance**: `_materializeWithCeiling` cached state keyed only on ceiling + dirty flag, so it could return stale results when new writers appeared or tips advanced. Now snapshots the frontier (writer tip SHAs) alongside the ceiling and invalidates the cache when the frontier changes.
- **`resolveTickValue` duplicate tick 0**: The relative-tick resolver blindly prepended 0 to the ticks array, duplicating it when ticks already contained 0. Now checks before prepending.

### Changed

- **History renderer**: Extracted `summarizeOps` and `formatOpSummary` into shared modules, reducing duplication between history and seek views.

## [10.3.0] — 2026-02-09 — Time Travel (`git warp seek`)

Adds cursor-based time travel for exploring graph history. Navigate to any Lamport tick, save/load named bookmarks, and see materialized state at any point in time. Existing commands (`info`, `materialize`, `history`, `query`) respect the active cursor.

### Added

- **`git warp seek` command**: Step through graph history by Lamport tick.
- `seek --tick N` — position cursor at absolute tick N.
- `seek --tick=+N` / `seek --tick=-N` — step forward/backward relative to current position.
- `seek --latest` — clear cursor and return to the present (latest state).
- `seek --save NAME` / `seek --load NAME` — save and restore named cursor bookmarks.
- `seek --list` — list all saved cursors.
- `seek --drop NAME` — delete a saved cursor.
- `seek` (bare) — show current cursor status.
- **`WarpGraph.discoverTicks()`**: Walks all writer patch chains reading only commit messages (no blob deserialization) to extract sorted Lamport timestamps and per-writer tick breakdowns.
- **`materialize({ ceiling })` option**: Replays only patches with `lamport <= ceiling`, enabling time-travel materialization. Skips auto-checkpoint when ceiling is active to avoid writing snapshots of past state.
- **Cursor persistence via refs**: Active cursor stored at `refs/warp/<graph>/cursor/active`, saved cursors at `refs/warp/<graph>/cursor/saved/<name>`. All data stored as JSON blobs.
- **ASCII seek renderer** (`src/visualization/renderers/ascii/seek.js`): Dashboard view with timeline visualization, writer inclusion status, and graph stats at the selected tick. Activated via `--view`.
- **Cursor-aware existing commands**: `info` shows active cursor in summary; `materialize` skips checkpointing when a cursor is active; `history` filters patches to the selected tick; `query` materializes at the cursor ceiling.
- **BATS CLI tests** (`test/bats/cli-seek.bats`, 10 tests): End-to-end integration tests for all seek operations.
- **Domain unit tests** (`test/unit/domain/WarpGraph.seek.test.js`, 12 tests): `discoverTicks()`, `materialize({ ceiling })`, ceiling caching, multi-writer ceiling, `_seekCeiling` instance state.
- **Renderer unit tests** (`test/unit/visualization/ascii-seek-renderer.test.js`, 7 tests): Timeline rendering, writer rows, dashboard layout.

### Changed

- **`RefLayout`**: New helpers `buildCursorActiveRef()`, `buildCursorSavedRef()`, `buildCursorSavedPrefix()` for cursor ref path construction.

### Fixed

- **Cursor blob validation**: Added `parseCursorBlob()` utility that validates JSON structure and numeric tick before use. `readActiveCursor`, `readSavedCursor`, and `listSavedCursors` now throw descriptive errors on corrupted cursor data instead of crashing.
- **GUIDE.md**: Added `--view seek` to the supported commands table.
- **CHANGELOG**: Fixed `RefLayout` helper names to match exported API (`buildCursorActiveRef`, not `buildCursorRef`).
- **`_materializeWithCeiling` cache**: Cache fast-path no longer returns empty `receipts: []` when `collectReceipts` is true; falls through to full materialization to produce real receipts.
- **`_resolveCeiling` null override**: `materialize({ ceiling: null })` now correctly clears `_seekCeiling` and materializes latest state, instead of ignoring the explicit null.
- **Seek timeline duplicate 0**: `buildSeekTimeline` no longer prepends tick 0 when `ticks` already contains it, preventing a duplicate dot in the timeline.
- **Seek timeline label drift**: Tick labels now stay vertically aligned under their dots for multi-digit tick values by computing target column positions instead of using fixed-width padding.
- **RefLayout docstring**: Added `cursor/active` and `cursor/saved/<name>` to the module-level ref layout listing.
- **BATS seek tests**: Use `--tick=+1` / `--tick=-1` syntax instead of `--tick +1` / `--tick -1` to avoid parser ambiguity with signed numbers.

### Tests

- Suite total: 2938 tests across 147 vitest files + 66 BATS CLI tests (up from 2883/142 + 56).
- New seek tests: 23 unit (14 domain + 9 renderer) + 10 BATS CLI = 33 total.
- New parseCursorBlob unit tests: 11 tests covering valid parsing, corrupted JSON, missing/invalid tick.

## [10.2.1] — 2026-02-09 — Compact ASCII graphs & hero GIF

### Changed
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,26 @@ git warp history --writer alice
# Check graph health, status, and GC metrics
git warp check

# Time-travel: step through graph history
git warp seek --tick 3 # jump to Lamport tick 3
git warp seek --tick=+1 # step forward one tick
git warp seek --tick=-1 # step backward one tick
git warp seek --save before-refactor # bookmark current position
git warp seek --load before-refactor # restore bookmark
git warp seek --latest # return to present

# Visualize query results (ascii output by default)
git warp query --match 'user:*' --outgoing manages --view
```

All commands accept `--repo <path>` to target a specific Git repository, `--json` for machine-readable output, and `--view [mode]` for visual output (ascii by default, or browser, svg:FILE, html:FILE).

When a seek cursor is active, `query`, `info`, `materialize`, and `history` automatically show state at the selected tick.

<p align="center">
<img src="docs/seek-demo.gif" alt="git warp seek time-travel demo" width="600">
</p>

## Architecture

The codebase follows hexagonal architecture with ports and adapters:
Expand Down
12 changes: 12 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2439,3 +2439,15 @@ Things this project should not try to become:
| ECHO | 3 | 3 | 17 | ~820 |
| BULKHEAD | 5 | 15 | 49 | ~2,580 |
| **Total** | **40** | **67** | **230** | **~11,510** |

---

## Backlog

Ideas that don't yet have milestone homes. No estimates, no ordering — just a
parking lot so they aren't forgotten.

| Idea | Description |
|------|-------------|
| **Structural seek diff** | Full `diffStates()` between arbitrary ticks returning added/removed nodes, edges, and properties — not just count deltas. Would power a `--diff` flag on `git warp seek` showing exactly what changed at each tick. |
| **git-cas materialization cache** | Cache `WarpStateV5` at each visited ceiling tick as content-addressed blobs via `@git-stunts/git-cas`, enabling O(1) restoration for previously-visited ticks during seek exploration. Blobs naturally GC unless pinned to a vault. |
Loading