docs: propose rebuilding the graph without blocking writes - #347
Open
Artexis10 wants to merge 1 commit into
Open
docs: propose rebuilding the graph without blocking writes#347Artexis10 wants to merge 1 commit into
Artexis10 wants to merge 1 commit into
Conversation
A full epistemic graph rebuild runs inside the vault mutation boundary, so it blocks every other vault mutation for its duration. Measured on a maintainer workstation: one write against an unusable sidecar costs 7.7s over 500 pages and 32.4s over 2,000, against 315ms and 1.19s steady state. CI records hold_ms=39092 at 2,000 pages and hold_ms=172205 at 8,000. The trigger is routine, not exotic: the sidecar is unusable whenever schema_version, core_registry_version, or extension_registry_hash disagrees with the running build. SCHEMA_VERSION is at 7, and editing one extension relation invalidates it too. Design-only. Includes the reproduction harness and the pre-change baseline to beat, plus why #346's approach (defer to reconcile) is not available: four tests require the write path to leave the graph built.
Owner
Author
|
Independent merge-gate review confirms the availability problem is real, but the current design needs revision before merge: explicitly modify/supersede the active bounded-index-maintenance contract; choose and prove a Windows-safe publication protocol for open SQLite readers; make single-flight and temp ownership process-safe; prevent cleanup from deleting an active build; and resolve whether writers arriving during rebuild block or defer without losing their own edit. Please update onto current main and rerun review/CI after those choices are closed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Design-only OpenSpec change. No behaviour change in this PR.
The bug is confirmed and it affects us
Reproduced on a maintainer workstation against main, one
upsert_after_writewith no usable sidecar:CI's write-latency benchmark shows the same shape larger:
hold_ms=39092at 2,000 pages,hold_ms=172205at 8,000. Every other vault mutation is blocked for that whole window, and a client that gives up meanwhile sees a timeout on a write that then lands.(The warning names the holder because of #344. Before that it read
operation=unknown holder_kind=unknown, which is why this went unnoticed.)The trigger is routine
_open_read_snapshottreats the sidecar as unusable when any ofschema_version,core_registry_version, orextension_registry_hashdisagrees with the running build. So a full rebuild is provoked by:SCHEMA_VERSION— currently 7, bumped seven times, most recently in feat(memory): relation-filtered recall on find and ask_memory #313A maintainer-sized vault eats ~32 s on the next write after any of those.
Why the obvious fix is unavailable
#346 removed the escalation so writes deferred to
reconcile. CI rejected it, correctly:test_refresh_missing_sidecar_routes_to_full_rebuildrequires a write against a missing sidecar to index the whole vault and leave it available, and three further tests depend on the same escalation. The rebuild must happen. What must change is that it stops holding the boundary while it happens.Shape of the fix
Build rebuild passes into a temporary database beside the sidecar with no boundary held, then take the boundary only to swap it in.
Two implementation facts drive this rather than something simpler:
_rebuild_all_passwipes the live sidecar (DELETE FROM graph_edges/graph_nodes/graph_parent_refs) before refilling. That is only safe today because the boundary excludes everyone, so temp-build-and-swap is required, not merely tidier.Rebuilds also become single-flight: today the boundary serialises them implicitly, and without it N concurrent writers would each start a full rebuild.
Deliberately unresolved
Two open questions are recorded rather than guessed:
REBUILD_STABILIZATION_ATTEMPTSneeds raising now that concurrent Exomem writes can perturb freshness mid-pass, where previously only out-of-band edits could.Also flagged as a risk: replacing an open SQLite file on Windows does not follow POSIX rename semantics, and the service runs on Windows. Task 2.4 requires verifying that path rather than assuming.
What is in this PR
openspec/changes/rebuild-graph-without-blocking-writes/— proposal, design, spec, tasksscripts/repro_graph_rebuild_hold.py— the harness that produced the numbers above, so the fix can be measured against the same baselinenpm exec @fission-ai/openspec -- validate --specs --strict— 23 passed, 0 failed.