本文へ移動
cccskills
無料GitHub で公開

rfdb-v2-clear-ephemeral-trap

Fix RFDB V2 graph data silently not persisting to disk after analysis. Use when: (1) rfdb-server reports "0 nodes, 0 edges" on restart despite successful analysis, (2) segment directories exist but are empty (no .bin files), (3) manifest_index.json shows total_nodes: 0 despite analysis logging 70k+ nodes, (4) Docker builds produce empty graph databases, (5) --clear flag used before analyze command. Root cause: GraphEngineV2::clear() replaces the store with MultiShardStore::ephemeral() which has path: None, causing all flush operations to write to in-memory buffers only.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md6.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

RFDB V2 Clear Makes Engine Ephemeral

STATUS UPDATE (2026-06-11, branch feat/datalog — W8 Part 2)

Both flavors of this trap are FIXED on feat/datalog. GraphEngineV2::clear() / clear_durable() now performs a REAL durable clear: it truncates the on-disk database (deletes segments/ + gc/ + manifest authority, recreates a fresh empty manifest and shard skeleton) and resets all engine caches (D2 materialize pins, planner-stats, W9 shared indexes, derive pin sidecars). The engine stays DISK-BACKED after clear — no ephemeral swap, so post-clear analysis persists (the 2026-02 data-loss flavor) and a clear+restart does NOT resurrect the old graph (the 2026-06 placebo flavor, gaps.md). Wire Clear surfaces truncation errors to the client. Tests: w8_durable_clear_truncates_disk_and_survives_reopen, w8_durable_clear_drops_pin_sidecars (engine_v2.rs). Manual fallback remains rm -rf <db>.rfdb (e.g. after a crash inside the tiny manifest-reset window). On binaries WITHOUT this fix, everything below still applies.

Problem

After running grafema analyze --clear, the analysis completes successfully and reports tens of thousands of nodes/edges, but on restart the database is empty (0 nodes, 0 edges). The data was never persisted to disk despite multiple flush operations succeeding without error.

Context / Trigger Conditions

  • grafema analyze --clear reports successful analysis with node/edge counts
  • On restart, rfdb-server logs "Default database: 0 nodes, 0 edges"
  • manifest_index.json shows "total_nodes": 0, "total_edges": 0
  • Segment directories (segments/00/, segments/01/, etc.) exist but are empty
  • No error messages anywhere in the logs
  • The tracing::info!("Flushing...") message from collect_and_write_data() never appears (because CommitBatch already flushed, but to ephemeral storage)

Root Cause

GraphEngineV2::clear() (engine_v2.rs:572-578) replaces the store and manifest with ephemeral versions:

fn clear(&mut self) {
    self.store = MultiShardStore::ephemeral(DEFAULT_SHARD_COUNT);  // path: None!
    self.manifest = ManifestStore::ephemeral();
    // ...
}

MultiShardStore::ephemeral() creates shards with path: None. When Shard::flush_with_ids() runs (shard.rs:710), it checks if let Some(path) = &self.path — ephemeral shards take the else branch which writes to an in-memory Cursor<Vec<u8>> instead of disk files.

The data lives in memory segments and is queryable (nodeCount/edgeCount return correct values), but nothing is written to disk. When the process exits, all data is lost.

Why It's Hard to Detect

  1. No errors: All operations succeed — add_nodes, flush, nodeCount all work correctly
  2. Counts are correct: The server reports accurate node/edge counts from in-memory segments
  3. CommitBatch masks the issue: Each CommitBatch internally calls flush(), which succeeds (to memory). The subsequent explicit flush() from the CLI finds an empty delta_log and returns early — so the tracing::info!("Flushing...") message never appears
  4. Segments directory structure exists: The directories are created during initial DB creation before clear() is called

Solution

Don't use --clear when you need data to persist. For fresh builds (Docker, CI):

# BAD: --clear makes V2 engine ephemeral, data lost
RUN grafema analyze /build --clear

# GOOD: No --clear needed for fresh build (no existing DB)
RUN grafema analyze /build

If you truly need to clear and re-analyze an existing database, the proper approach is to delete the database directory before starting the server, rather than using --clear:

rm -rf .grafema/graph.rfdb
grafema analyze .

Verification

After analysis completes, check that segments contain actual data:

# Should show .bin files with non-zero size
ls -la .grafema/graph.rfdb/segments/00/

# Should show total_nodes > 0
cat .grafema/graph.rfdb/manifest_index.json

Notes

  • This is a V2-specific issue. V1 engine's clear() resets in-place without making shards ephemeral.
  • The --clear flag sends a Clear command to the server which calls engine.clear().
  • create_ephemeral() is designed for test databases that don't need persistence. Using it in clear() is an architectural shortcut that creates this trap.
  • Related MEMORY note: "Ephemeral databases skip flush" — this is the V2 manifestation of the same concept documented for V1.

Second flavor discovered 2026-06-09: clear+restart = PLACEBO (stale data SURVIVES)

The Feb-2026 flavor above is data LOSS (clear, then analyze into the ephemeral engine, no restart). The CLI's actual --clear flow (analyzeAction.ts:340-346) is backend.clear() → shutdownServer() → connect() — the shutdown DISCARDS the ephemeral state and the fresh auto-started server reloads the untouched on-disk DB. Net effect: --clear clears nothing; the manifest version just keeps counting (observed 660 → 1001 across a "cleared" run).

Detection signature: after --clear + full reanalysis, edges from a PRIOR run survive with an older _generation in their metadata (e.g. 15 531 DERIVED_FROM edges at gen 36 alongside the fresh gen-37 DERIVES_FROM — 15 014 (src,dst) pairs carrying BOTH). Forensics: edge metadata _generation/_source (stamped by orchestrator gc.rs) maps every edge to the run that wrote it; gen-tracker.json holds the run counter. Segment-file mtimes are NOT evidence of write time — compaction rewrites old data into new files.

Workaround stands: rm -rf .grafema/graph.rfdb (+ optionally gen-tracker.json) before the server starts. Real fix: GraphEngineV2::clear() must clear the persistent store. Gap recorded in _ai/gaps.md (2026-06-09).

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Fix Elixir/Erlang AST processing bugs in Grafema beam-analyzer. Use when: (1) Elixir parser returns MODULE node but 0 functions/calls — body nesting issue, (2) Erlang parser crashes with "cannot convert list to string" on OTP 26+ — location format changed from integer to keyword list, (3) pipe operator |> creates spurious CALL nodes instead of desugared function calls — clause ordering bug, (4) multi-module .ex files return only the first module — missing __block__ handler, (5) installing Erlang/Elixir on macOS with outdated Xcode/Clang.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fires after fixing any non-trivial bug or regression. Asks: could the graph have caught this as a guarantee? Pairs with reflection-in-and-on-action — picks up after "earliest catchable signal" and asks the next question: was that signal expressible in graph? Triggers: (1) after any non-trivial bug fix is verified working, (2) after a regression report (something used to work, broke), (3) during step 6 (knowledge extraction) of the workflow, (4) when reflection-on-action surfaces a "would have been catchable" signal. Outcome is a triage decision (graph-reachable? rule expressible? rule sound?) and either a draft Linear issue + guarantee proposal, or a recorded "graph capability gap" note. Never auto-creates guarantees.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix Playwright automation failures against code-server (VS Code in browser). Use when: (1) trust dialog blocks all clicks — "monaco-dialog-modal-block intercepts pointer events", (2) button:has-text() finds wrong buttons behind modal dialog, (3) keyboard shortcuts don't work — Meta vs Control inconsistency, (4) VS Code extension activity bar icon not found by aria-label, (5) panels show placeholder text despite extension being "Connected". Covers trust dialog dismissal, keyboard shortcut hybrid mode, extension panel selectors, and database connection verification for Grafema extension.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Systematic methodology for achieving 100% backward dataflow reachability in a new language. Create gauntlet fixture, write trace, diagnose gaps, fix analyzer/algorithm, iterate to 100%. Language-agnostic process. Use when: (1) adding a new language to Grafema, (2) auditing dataflow coverage for existing language, (3) user says "/dataflow-gauntlet".

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix docker exec hanging when starting background processes (servers, daemons) inside containers. Use when: (1) docker exec never returns despite using & or nohup, (2) background server started in container causes docker exec to hang indefinitely, (3) env_startup_command in SWE-bench or similar frameworks times out, (4) setsid/disown needed for proper process detachment in Docker. Root cause: docker exec tracks ALL processes in the exec session, not just the top-level PID.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix Node.js CLI tools crashing inside Docker containers when host-installed node_modules require a newer Node version than the container provides. Use when: (1) "SyntaxError: Invalid regular expression flags" with /v flag in string-width or similar packages, (2) node_modules installed on host with Node 20+ but container has Node 18, (3) `npm install` with file: protocol creates symlinks that break inside Docker, (4) pnpm workspace packages become broken symlinks in containers. Covers version detection, Node binary mounting, and npm install strategies for cross-version compatibility.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Disentinel のスキルをすべて見る

このスキルの問題を報告する