Skip to content

feat: add mine_epoch tracking and revision snapshots - #607

Open
YulelogPagoda wants to merge 9 commits into
MemPalace:developfrom
YulelogPagoda:feat/mine-epoch-tracking
Open

feat: add mine_epoch tracking and revision snapshots#607
YulelogPagoda wants to merge 9 commits into
MemPalace:developfrom
YulelogPagoda:feat/mine-epoch-tracking

Conversation

@YulelogPagoda

Copy link
Copy Markdown

What does this PR do?

Adds two features that build on top of #521's delete-before-insert fix, giving every mine run a version identity and preserving a queryable history of previous file versions.

1. Mine epoch tracking

Each mine() run increments a monotonic counter stored in {palace}/epoch.json. Every chunk filed during that run gets tagged with its mine_epoch in metadata. This gives every drawer a "generation number" that enables:

  • Knowing how stale a chunk is (current_epoch - chunk.mine_epoch)
  • Auditing which mine run introduced any given piece of content
  • Reconstructing the palace state at any previous epoch

The status command now displays the current epoch.

2. Revision snapshots

When a file is re-mined, #521's delete-before-insert purges all existing chunks for that file before the fresh ones are written. This avoids hnswlib segfaults but also destroys the previous version of the file. This PR adds a snapshot step that runs just before the delete, capturing the chunks to {palace}/revisions.jsonl so the previous version can still be retrieved.

Each revision record captures:

  • superseded_at / superseded_by_epoch — when and by which run
  • source_file / chunk_index — what it was
  • content — exact chunk text
  • original_epoch / original_filed_at — provenance

Why this is valuable

The two features compose naturally:

  • Epoch tracking tells you when something changed
  • Revision snapshots tell you what it used to be
  • Together they turn the palace into a versioned store without touching the active search index

How to test

11 tests, ~24s, no API keys, no network:

  • 4 epoch tracking tests (starts at 0, increments, persists to JSON, tags chunks)
  • 3 eviction behavior tests (shrinking, unchanged, growing)
  • 3 revision snapshot tests (file created, content preserved, accumulates)
  • 1 backward compat test (old signature still works)

Design notes

Checklist

  • Tests pass (python -m pytest tests/test_mine_epoch_tracking.py -v)
  • No hardcoded paths
  • Linter passes (ruff check .) — not run locally, please verify

Adds per-mine-run epoch counter and revision history snapshots, building on top of MemPalace#521's delete-before-insert fix.  - _load_epoch/_save_epoch helpers for {palace}/epoch.json - mine_epoch metadata tag on every drawer - _snapshot_revisions writes old chunks to {palace}/revisions.jsonl   before upstream's purge runs, preserving previous versions - status command shows current epoch  No changes to existing delete-before-insert logic.
11 pytest tests covering epoch tracking (4), stale eviction behavior (3), revision snapshots (3), and backward compatibility (1). All pass in ~24s. No network, no API keys, follows existing pytest conventions.

@web3guru888 web3guru888 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a well-scoped feature pair — epoch tracking and revision snapshots compose cleanly and the implementation is non-intrusive.

What works well

  • Epoch counter is monotonic and persisted atomically to epoch.json — simple, no external deps, survives crashes between runs.
  • _snapshot_revisions() is wrapped in try/except so a write failure never breaks mining. Right call.
  • The mine_epoch: int = 0 default on process_file() and add_drawer() means callers that don't pass palace_path get graceful degradation (epoch 0 in metadata, no snapshot attempt). The backward-compat test validates this explicitly.
  • Test coverage is solid: epoch lifecycle, eviction behaviour, snapshot content integrity, accumulation across runs. The UNIQUE_MARKER_STRING_XYZZY_12345 round-trip test is particularly good — it proves the content is right, not just that a file was created.

One real concern — revisions.jsonl grows unboundedly

Every re-mine of a changing file appends records. A project that re-mines a large codebase every day will accumulate tens of thousands of lines quickly. There's no rotation, truncation, or max-size guard. A 50K-drawer palace that re-mines 10% of its files daily would write ~5K revision records per run — ~1.5 million records after a year, uncompressed.

Worth at least a MAX_REVISIONS constant (default ~50,000 lines) with a tail-truncation on open, or a note in the docstring that the file is intentionally unbounded and callers should manage it themselves. The --purge command from #562 is a natural place to reset revisions too.

Minor: epoch.json is inside the palace directory

This is fine for the common case, but palace directories may be version-controlled or synced. epoch.json and revisions.jsonl should probably be documented as ephemeral/local files that shouldn't be committed. A note in the PR description or a .gitignore suggestion for {palace}/*.jsonl and {palace}/epoch.json would help.

Interaction with #562's cmd_purge

The purge-and-rebuild command in #562 deletes and recreates the palace directory. After a purge, _load_epoch() returns 0 and the counter restarts from 1, which means epoch numbers become non-monotonic across purge boundaries. If continuity matters (audit trail), cmd_purge would need to preserve epoch.json (or at least record the last epoch before purge in the new one). Minor edge case, but worth a comment in cmd_purge.

Verdict: LGTM with the revisions.jsonl growth concern as the main thing to address before merge.

Addresses review feedback: - mine_epoch is now int(time.time()) with +1 bump on same-second collision - Survives cmd_purge rebuilds automatically (Unix time is monotonic) - Adds REVISION_RETENTION_SECONDS (default 90 days, env-var configurable) - Time filter + MAX_REVISIONS hard cap applied in one rewrite pass
…al, retention

15 tests total (up from 12). New tests: - test_epoch_is_unix_time_and_monotonic - test_same_second_mine_bumps_epoch_by_one - test_epoch_survives_cmd_purge_equivalent - test_revisions_time_retention_drops_ancient_records  Updated existing tests to drop hardcoded epoch=1/2/3 assertions since epochs are now Unix timestamps.
Each line in revisions.jsonl is one chunk snapshot, not a whole-file revision. A file with N chunks that gets re-mined produces N lines. Updated docstring to spell this out, and added MEMPALACE_MAX_REVISIONS env var for consistency with MEMPALACE_REVISION_RETENTION_DAYS.  No behavior change. All 15 tests still pass.
@bensig
bensig changed the base branch from main to develop April 11, 2026 22:21
@bensig
bensig requested a review from igorls as a code owner April 11, 2026 22:21
@igorls igorls added area/mining File and conversation mining enhancement New feature or request labels Apr 14, 2026
@igorls

igorls commented Aug 15, 2026

Copy link
Copy Markdown
Member

Thanks for this contribution, and apologies for the slow turnaround.

develop has moved a fair way since this was opened and the branch no longer merges cleanly. If you're still interested in landing it, could you rebase onto current develop? Once it merges cleanly and CI is green I'll get it reviewed for the 3.8.0 cycle.

If you'd rather not pick it back up, no problem at all — just say so and I'll close it out, and thanks either way for taking the time to send it.

@YulelogPagoda

Copy link
Copy Markdown
Author

Thanks for this contribution, and apologies for the slow turnaround.

develop has moved a fair way since this was opened and the branch no longer merges cleanly. If you're still interested in landing it, could you rebase onto current develop? Once it merges cleanly and CI is green I'll get it reviewed for the 3.8.0 cycle.

If you'd rather not pick it back up, no problem at all — just say so and I'll close it out, and thanks either way for taking the time to send it.

I'll work up to 3.8.0 and roll back in 😊 I'm finding it a lovely useful thing to have. Thank you 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/mining File and conversation mining enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants