Recovery Recipes¶
Reference for the ragraf-core skill. Every recipe addresses a state that has
already occurred in this project or is described by the code. Order: diagnosis, then
action, then verification of the result.
Translation note: recipes referencing author-internal tools (
measure_safe_excludes.py,check_ragraf_config.py,check_service_excludes.py,measure_dedupe_rules.py,tests/test_dedupe.py,tests/check_admin_*.py) name them as they are cited by the shipped source comments; those tools are not shipped in the public repository. Where a recipe depends on them, an equivalent manual check is given.
1. The index is stale or «trembling»¶
Symptom. Operations answer, but the facts do not match the code; freshness
reports a divergence; check repeats reindexing on every call.
Diagnosis.
python tools/ragraf.py -p config/ragraf.yaml check
python tools/ragraf.py -p config/ragraf.yaml status
check compares the corpus checksum with the one recorded in the revision. If the
checksums match but stale does not clear, the problem is not the files but the
revision record.
Action.
The cause of looping, if it repeats. The checksum must be computed over exactly
the files that land in the index, and after duplicate collapsing
(src/ragraf/corpus.py:59-70, :242-253). If collapsing is moved into the indexer
or the guard, the checksum diverges from the index contents and reindexing never
stops. The check for this case is tools/Invoke-ProjectDoctrine.ps1, the collapsing
rule.
2. The registry shows an empty revision and zeros¶
Symptom. python tools/ragraf.py catalog shows rev- «none», nodes 0,
edges 0 for a corpus, while status of the same corpus reports a revision and nodes.
Cause (measured, historical). Registering a corpus via ensure used to register
the development before indexing and did not write the run result into the registry
(src/ragraf/ensure.py:308-312). The entry stayed with trigger register and zeros.
This is fixed in the shipped code: on successful indexing ensure now calls
record_index_run(..., trigger="ensure:index") (src/ragraf/ensure.py:338-348).
Action — immediate workaround (still valid if you ever see zeros).
This path writes the result into the registry (src/ragraf/cli.py:247). A second
path is any call that makes the guard work: the guard records the result itself
(src/ragraf/watch.py:554). Confirmation after the action — catalog: the entry
gains a revision, node and edge counts and a trigger of the form guard:fast.
The proper fix (already applied). Write the result in ensure after successful
indexing by calling catalog.record_run (src/ragraf/catalog.py:235) with the
numbers from the read revision — exactly as the guard does. After such a change:
python tests/test_ensure.py, then re-run the checker: the registry-coverage rule
must go green.
3. capability=degraded¶
Symptom. index_status reports capability=degraded; the slice operation refuses.
What it means. The code-property layer was not built or its export failed; the
other layers (lexicon, vector, parse graph) work. Silent degradation does not exist:
src/ragraf/cpg.py:9-11.
Diagnosis.
The cpg stage will hold the reason. A known case on our own corpus: the export
returned code 1 with an error of the form «next on empty iterator», while the code
property graph file was in fact built. The cause was not localized — that is a
defect of the layer, not of the configuration.
Action.
- Make sure Java and Joern are available and located where the code looks for them
(
src/ragraf/cpg.py:82-93,:391). - Restart indexing: the layer is rebuilt from scratch.
- If the refusal repeats — work without the slice operations and record the finding
separately; do not present
degradedas the whole index being broken.
Important. The Joern server is stopped automatically when the indexer closes
(src/ragraf/indexer.py:1166-1183). An unclosed server is a multi-gigabyte hanging
process holding the port; check the process list after manual experiments.
4. An exclusion edit threw out working code¶
Symptom. Files that were visible in search disappeared; no errors reported.
Cause. Pattern matching is case-sensitive and understands only «any directory
tail» templates for cutting directories: **/cache/** catches src/cache/ but not
src/Cache/ (src/ragraf/util.py:72-158).
Action.
The author-internal measurement tools are not shipped; the equivalent manual check:
# 1. Count what the corpus scans to BEFORE the change
python tools/ragraf.py -p config/ragraf.yaml status
# 2. Apply the exclusion change, then:
python tools/ragraf.py -p config/ragraf.yaml check
python tools/ragraf.py -p config/ragraf.yaml reindex
# 3. Compare the file count in status; investigate EVERY file that disappeared
python tools/ragraf.py -p config/ragraf.yaml query search "<name of a vanished module>"
The rule is simple: if extending the base exclusion list throws out zero files in every corpus — it is safe; if even one — the name goes into the specific corpus's config, where the directory's purpose is visible.
5. Duplicate collapsing and its price¶
Symptom. The file count in the index is lower than the file count on disk.
What it is. Copies with identical content collapse; one primary remains; files
on disk are not deleted. By default collapsing is OFF (src/ragraf/config.py:541),
and our own corpus config has no section for these settings — meaning it is not
applied to that corpus. When enabled, the index state carries the discarded
counters: how many copies, how many groups, bytes and lines
(src/ragraf/indexer.py:779-786).
What must not be done. Changing the primary-copy selection rule to «the first
one that comes along»: a tie must be resolved by path, otherwise the corpus
checksum trembles and the guard loops (src/ragraf/dedupe.py:165-223).
Verification. The author-internal tools/measure_dedupe_rules.py and
tests/test_dedupe.py are not shipped; the portable check is the guard behavior:
run check twice in a row — the second run must not trigger reindexing.
Remember. Enabling collapsing changes the corpus checksum: the guard reindexes the corpus once. That is a conscious consequence, not a defect.
6. The computer fell back to CPU¶
Symptom. index_status reports the CPU computer; indexing time is higher than
expected.
Causes (in check order).
- The GPU is disabled in the settings.
- The volume of work is below the break-even threshold: preparing the map takes
about a quarter of a minute one-time, so on a small number of texts it loses
(
src/ragraf/config.py:276-301). - The package the GPU needs is not installed:
sentence-transformersandtorchare not declared in the package description (src/ragraf/compute.py:141-146). - Free GPU memory is below the threshold — fallback to CPU with a reason.
Action. Look at the reason field in the compute state: the reason is recorded
there, not guessed. Do not lower the threshold «so the GPU works» — that slows the
work down.
7. The admin panel¶
Local access only, port 8777; the token is printed at startup and handed to the page
by a separate request. Read requests need no token; any settings change requires it
and is written with a backup copy plus key and bounds validation
(src/ragraf/settings.py:327-386 — project-config path; note that the global
settings store writes without a backup — roadmap R-SEC-3). Live checks of the panel:
python tests/check_admin_agents.py and python tests/check_admin_dedupe.py
(not shipped; the panel must be running).
Security note (added in the 2026-10 revision): the panel's
GET /api/tokenendpoint returns the access token to any local client without authentication, and the page fetches it automatically. Until roadmap R-SEC-1 is implemented, treat the token as protection against accidental changes only — not against a malicious local process or DNS-rebinding. Do not expose the port; keep the panel bound to 127.0.0.1 (the default).
8. What to do in any of these states¶
- Write down the measurement: the command, the output, the revision, the checksum.
- Distinguish a pre-existing state from the consequence of your own edit. In the
published tree the checker ships 14 checks: 11 pass, while 3 report files
deliberately absent from the public subset (roadmap
R-REL-1). The author's full tree records its own baseline inAGENTS.md§10 (not shipped). - Do not report a green result without inspecting the object: every check in the checker has a counter of inspected objects, and zero on success counts as a false PASS.