8000 feat(graph): a versioned, replayable entity graph with history, as-of, diffs, rollback and a History tab by adeelahmad · Pull Request #119 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(graph): a versioned, replayable entity graph with history, as-of, diffs, rollback and a History tab - #119

Merged
adeelahmad merged 11 commits into
mainfrom
claude/graph-versioning-49x5up
Oct 4, 2026
Merged

adeelahmad merged 11 commits into
mainfrom
claude/graph-versioning-49x5up

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 4, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: renames, merges, links and other entity curation changed the graph in place. Only merges and graph changes could be undone, and there was no way to see what the graph looked like yesterday, who changed it, or to go back.

After: every change to the entity graph (entities, other names, cross-namespace links, "not the same" pairs) is an append-only, numbered version. Each version records who made it (a person, routine:<id>, analysis or the assistant), how it was made (web, token, oauth, assistant, mcp, routine, workflow, analysis, cli) and why, plus every record before and after. One commit per part:

  1. History API. GET /api/v1/graph/history lists versions; pass entity= for one entity's history. /graph/history/{version} shows a version in full, /graph/as-of/{version} shows the graph at that version, /graph/diff?from=&to= compares two versions, and /graph/tags names versions such as "before the cleanup".
  2. Rollback. POST /graph/rollback {to, namespace, dry_run} shows a preview by default. Running it undoes every later change in the namespaces you can edit as one new version, so a rollback can be rolled back too. Merges come undone with their mentions, graph changes are marked undone and moved mentions go back. What analysis found since stays. It needs editor access to every namespace the changes touched.
  3. Replay and verify. Checkpoints are taken at the first change and then every 1000. Replay rebuilds the graph from the history alone. GET/POST /graph/verify (admins) and lens history verify [--fix] compare the replay with today's graph and can record any unrecorded write as one graph.drift version. lens history checkpoint|list is also added.
  4. Web app. A new Routines › History tab shows each version's diff. Editors can name a version or roll back to it after a preview. An entity's drawer gets a History button that filters the tab to that entity.

See docs/graph-history.md.

Motivation and Context

Adeel asked for a "replayable and versioned graph". It builds on the existing graph changes (organize.py) and entity merges: their events point back at them. Two things are left for later:

  • The explorer and Cypher as of a version. This waits for the Graph explorer thread's PRs, as agreed with that thread.
  • Showing graph events in the activity history.

The schema only gains four new tables in store.SCHEMA and no data is rewritten. An archive that already has entities replays from a checkpoint taken at the first change. Mentions aren't versioned, since they come from transcripts.

Screenshots (if appropriate):

Checked in the running app: the History tab shows versions with actor, via and why, an opened version shows its diff with Name and Roll back buttons, and the rollback preview lists what would change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project. pre-commit run --from-ref origin/main passes, including the OpenAPI and client regeneration.
  • I added or updated tests:
    • tests/domain/test_graph_history.py: every version replays to the exact earlier state; a rollback, and a rollback of the rollback, restore the exact state including mention counts; rights; checkpoints; drift.
    • tests/api/test_graph_history.py, plus lens history in test_cli.py.
    • __tests__/graph-history.test.ts for the frontend.
    • Full backend suite: 546 passed against a SurrealDB 3.2.4 server and 542 passed embedded. The only failure is the known LibreOffice conversion test, which fails because of the environment. Frontend jest (655), tsc and lint pass.
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe

claude added 2 commits October 4, 2026 09:42
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
…ith as-of, diffs and named versions

Every change to entities, their other names, links across namespaces and
distinct pairs is one append-only graph_event with who, through what and
why, and the rows before and after. The graph can be read as of any
version, compared between versions, and an entity's history listed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
@adeelahmad adeelahmad self-assigned this Oct 4, 2026
claude added 3 commits October 4, 2026 09:57
Every change since a version is undone newest first as one new event:
merges with their mentions, graph changes marked undone, moved mentions
back, then every record as it was. What analysis found stays. A
rollback can itself be rolled back.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
The graph is kept whole with its first recorded change and every 1000
after; replaying from the newest checkpoint rebuilds it from history
alone. Verify compares the replay with today's graph and can record any
unrecorded writes as one graph.drift change. lens history verify,
checkpoint and list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
…t did, named versions and rollback

Routines › History lists every version with who, through what and why;
opening one shows what changed and lets editors name it or roll back to
it after a preview. An entity's History button shows its own changes.
Diffs name the entities other names point at.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
@adeelahmad adeelahmad changed the title feat(graph): record every entity graph change as a versioned event, with as-of, diffs and named versions feat(graph): a versioned, replayable entity graph with history, as-of, diffs, rollback and a History tab Oct 4, 2026
claude added 6 commits October 4, 2026 12:03
…Cypher as of a version

Keeps both sides in entities.py (graph_history.change around delete, plus
notebook.release), the entity drawer (Page and History buttons), mkdocs nav
and DEVLOG. Adds as_of to graph_model.build (entities and links from
graph_history.state_at), to /graph/schema, /graph/related, /graph/paths and
Cypher /graph/query, and keys the graph cache on graph_history.head.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
…d topic entity hide/show

Keeps both sides in CHANGELOG, DEVLOG and mkdocs nav. Turning an entity
into a topic hides it, and deleting the topic shows it again; both now run
inside graph_history.change so they are versions with why, not drift.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
…aude/graph-versioning-49x5up

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCB28xsaiCpiDKKk2JjRpe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
5DA3

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0