Commit Graph
21 Commits
Author SHA1 Message Date
ayushcodes10 9d747f4da5 Compare partition structure, not just the node id set, for staleness
The node id set comparison missed a whole class of staleness: a merge,
a split, or a single node moving from one community to another can
leave the overall node set exactly unchanged while still describing a
different clustering, so a stale sidecar that happened to still cover
the same nodes kept winning. Compare each side's set of community
blocks instead, which catches a partition change even when the flat
node set stays identical, while still ignoring a pure id renumbering
of the same partition per the existing #1667 guard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 30a5955931)
2026-09-17 11:01:38 +01:00
ayushcodes10 11d91c8e17 Add negative control test for a sidecar that still matches
Guards against a false positive: an up to date sidecar (the normal
case immediately after extract or the clustering command) must not
trip the new staleness warning or take the reconstruction path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 21342bda37)
2026-09-17 11:01:38 +01:00
ayushcodes10 bafe75b86b Add regression test for stale sidecar cohesion recomputation
Confirms the wiki export path specifically, since it is the one that
prints cohesion into article metadata: a stale, impossibly large
cohesion value in the sidecar must not survive into the export once
staleness is detected, proving score_all actually ran on the fresh
reconstruction rather than the fossil value merely being ignored by
coincidence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 12c50b975a)
2026-09-17 11:01:38 +01:00
ayushcodes10 18cae252cb Add regression test for the stale sidecar html export path
Corrupts the analysis sidecar community node id set (the exact
staleness signature the issue describes) and confirms export html
still succeeds, still renders graph.html, and prints the new warning
instead of silently exporting against the fossil.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 4518bae439)
2026-09-17 11:01:38 +01:00
yiheng-kkk f69dca3c6c fix: prefer top-level hyperedges in export
(cherry picked from commit 5faf7a774c)
2026-09-05 01:18:59 +01:00
safishamsi 56c1060158 test(query): assert the CLI query call site wires graph_path (#2789)
The header logic is unit-tested, but only a real subprocess run proves the CLI
query command actually passes the resolved graph path through — the wiring that
was the point of #2789. Cover both the under-CWD relative form and an explicit
--graph outside the CWD shown in full. Plus 0.9.47 changelog entry.
2026-08-18 22:38:47 +01:00
safishamsiandClaude Opus 4.8 6ba0868228 fix(cli): surface four silent success-exit failures (#2534)
cluster-only warns when --backend/--model/--batch-size are ignored on the
label-reuse path; the community-label prompt key no longer collides with
the discard sentinel (an echoed key was silently dropped); tree --root
exits non-zero when it matches no source file instead of flattening the
tree; and cluster-only stamps built_at_commit from the analysed graph, not
the shell cwd. Also folds in the cluster-only refused-write guard from
PR #2522 (thanks @aniJani).

Thanks @elecnix for the report.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-07 22:49:25 +01:00
safishamsiandClaude Opus 4.8 07b9143d4b fix(hyperedge,skill): merge/load hyperedge integrity + community labels; bump to 0.9.34
#2486 (thanks @adminwat): normalize dict-shaped hyperedge members to ids
(or drop with a warning) so a malformed hyperedge can't abort a completed
merge with a TypeError.
#2484 (thanks @sortakool; approach from @oleksii-tumanov's #1691):
merge-graphs relabels hyperedge member ids and ids with the repo prefix,
unions both inputs' hyperedges instead of clobbering, and writes both
persistence slots.
#2485 (thanks @sortakool): build_from_json reads hyperedges from the
top-level and nested slots; a full validation wipeout is reported loudly.
#2490 (thanks @PapiScholz): the skill Step-5 flow passes curated
community_labels to to_json, so graph.json ships community_name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-05 22:08:29 +01:00
safishamsiandClaude Opus 4.8 0d0e5780c8 test(cli): graph.json node ids are portable across checkout paths (#1789)
The absolute-path-in-node-ids leak reported on 0.8.19 is already fixed on v8:
detect() returns paths relative to the scan root, so the CLI-produced graph.json
uses relative structural node ids (portable, no username/home leak). Lock it with
a regression test that extracts the same corpus from two different absolute
checkout dirs and asserts identical, leak-free node ids.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 16:31:10 +01:00
bbqboogiedwonsenandClaude Opus 4.8 c5db9ffb06 fix(cli): keep outputs/cache with --out / --graph, not the corpus or CWD (#1747)
Case 1 — `extract <corpus> --out <dir>`: the graph went to <dir> (cache_root is
already passed to the AST extractor), but detect()'s word-count/stat-index cache
uses the scan root, so a stray graphify-out/cache/ was created inside the corpus
(and left behind even when the run aborted at the no-LLM-key gate). Thread an
optional cache_root through detect() -> cached_word_count() -> _ensure_stat_index()
and pass out_root from the extract CLI, so the stat index lives under --out. Entry
keys are absolute paths, so relocating the index file is safe.

Case 2 — `cluster-only --graph <elsewhere>/graphify-out/graph.json`: outputs
(GRAPH_REPORT.md, re-clustered graph.json, labels, analysis, html) were written to
the CWD's graphify-out/, ignoring where --graph lives. They now write beside the
input graph when it sits in a graphify-out/ dir (another project/tenant's output),
while still falling back to the CWD for an arbitrary archived backup/graph.json —
the restore-into-place workflow #934 pins.

Regression tests for both cases; #934 still passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 02:06:26 +01:00
sanmaxdev 62f49bad73 fix: persist cluster-only analysis sidecar 2026-07-02 22:29:29 +01:00
safishamsiandClaude Opus 4.8 b8dc31f760 Honour GRAPHIFY_OUT end-to-end, not just in the path guards (#1423)
The GRAPHIFY_OUT override (custom output-dir name / absolute path, #686) was only
respected by some readers. `graphify extract` and several commands hardcoded the
literal "graphify-out", so `GRAPHIFY_OUT=custom-out graphify extract` still wrote
to graphify-out/ and downstream query/serve/update looked in the wrong place.

Resolve the output-dir name through graphify.paths everywhere it matters:
- new graphify.paths.out_path()/default_graph_json() helpers
- __main__: extract write dir, cluster-only/label, query/affected/benchmark
  defaults, save-result --memory-dir, uninstall --purge, cache-check
- detect: _MANIFEST_PATH, memory/ + converted/ dirs, and the scan-exclude (a
  renamed output dir is no longer re-ingested as source input)
- transcribe._TRANSCRIPTS_DIR; build_merge/serve/benchmark/prs graph-path defaults

Default behaviour is unchanged: with no env var everything still uses graphify-out/.
Verified end-to-end (extract -> cluster-only -> query under GRAPHIFY_OUT=custom-out
writes/reads custom-out/, no stray graphify-out/) and added a CLI regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 21:15:51 +01:00
Gal Shubeli 7aa300709f feat: add FalkorDB export backend (#1175)
Adds FalkorDB as a sibling option to the existing Neo4j sink, selected via
`graphify export falkordb [--push redis://localhost:6379]`.

- New push_to_falkordb() in graphify/export.py mirrors push_to_neo4j; FalkorDB
  is OpenCypher-compatible so the MERGE/SET upsert queries are identical.
- export falkordb subcommand wired in graphify/__main__.py (cypher.txt when no
  --push, direct push otherwise). Auth is optional; target graph defaults to
  "graphify".
- falkordb optional extra in pyproject.toml (and in the all extra).
- Tests: CLI cypher generation (CI-safe) + real-FalkorDB integration tests that
  skip when no instance is reachable.
- README extras table + command reference and CHANGELOG updated.
2026-06-07 15:03:49 +03:00
Leon GyeongMan BaekandClaude Opus 4.7 9abaa77c62 fix(cli): apply remap_communities_to_previous in cluster-only path (#1028)
cluster-only re-runs Leiden clustering and then re-applies the existing
.graphify_labels.json by raw cid index, which causes labels to attach to
clusters whose members are unrelated to the label's original meaning
whenever the graph has changed between labeling and re-clustering.

Mirror the safety net already present in watch.py:_rebuild_code added in
#822 for the watch/update paths.

Adds a regression test that fails without the fix (label cids become
orphaned from graph.json community attributes after re-clustering).

Refs: #1027

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 20:12:02 +01:00
mohamadkattan12 d778e2c36b fix(cli): reconstruct communities from per-node attribute when sidecar missing (#1001)
`graphify export html|obsidian|wiki|svg|graphml|neo4j` reads `communities`
exclusively from `.graphify_analysis.json` (set to `{}` if missing). The
post-commit / watch rebuild path doesn't regenerate that sidecar — only
graph.json + GRAPH_REPORT.md. Several skill workflows also delete temp
files at the end of `graphify extract`. In both cases the per-node
`community` attribute (`to_json` writes it on every node) is intact, but
the CLI ignores it.

Observed failure: `graphify export html` on a graph that exceeds the
viz node limit prints

    Graph has 64703 nodes (above 5000 limit). Building aggregated community view...
    Single community - aggregated view not useful. Skipping graph.html.

even though the same graph.json has 2,026 distinct `community` values
on its nodes — `to_html` just received an empty `communities` dict and
the aggregator collapsed to a single meta-node.

Fix: when the analysis sidecar is absent (or its `communities` field is
empty), reconstruct the `cid -> [node_ids]` mapping from the per-node
attribute in graph.json. The sidecar remains the canonical source of
truth when present; the reconstruction is a strict fallback. Every
downstream subcommand (`html`, `obsidian`, `wiki`, `svg`, `graphml`,
`neo4j`) sees the same shape it always did, just populated from the
graph itself instead of an externally-cached sidecar.

Tests added (tests/test_cli_export.py):
- `test_export_html_falls_back_to_node_community_attribute` —
  delete the sidecar, run export html, confirm `graph.html` exists
  and the "Single community" bail-out path does NOT fire.
- `test_export_html_fallback_recovers_multiple_communities` —
  stronger guarantee that the reconstructed community count equals
  what the sidecar would have provided (no silent data loss).
- `test_export_html_no_community_data_at_all_still_succeeds` —
  hand-build a graph.json with no per-node `community` attribute
  (older `to_json` versions, manually-constructed graphs); the
  command must still exit cleanly rather than crash.

All 26 tests in test_cli_export.py pass; ruff clean on both files.
2026-05-24 20:35:21 +01:00
SafiandClaude Sonnet 4.6 076e6b7c06 fix cluster-only crash when graphify-out/ absent, add regression test (#934)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 18:27:53 +01:00
cinosandHermes Agent ec4c87c86e fix(export): accept edges-only graph JSON for wiki export (#909)
Co-authored-by: Hermes Agent <hermes-agent@users.noreply.github.com>
2026-05-17 11:32:55 +01:00
Safi f7c9a9ad82 fix watch.py labels churn, edges/links schema, shrink-check duplication, and skill.md ID edge cases 2026-05-14 00:29:54 +01:00
Ahmad FathallahandCursor 8e4c803f31 reduce graph update churn and stabilize community IDs
Make `graphify update` idempotent by skipping output rewrites when graph/report content is unchanged, add `update --no-cluster`, and preserve community IDs across runs via overlap-based remapping with deterministic partition inputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 02:23:51 +03:00
Chris Stephens 81bc2f9298 Fix GRAPHIFY_OUT defaults for graph query commands 2026-05-06 17:04:57 -04:00
SafiandClaude Sonnet 4.6 b6ffdbb8dd v0.7.2: Fortran support + export CLI subcommands + skill.md size reduction
- Add Fortran support (26th language): .f/.F/.f90/.F90/.f95/.F95/.f03/.F03/.f08/.F08
  via tree-sitter-fortran; capital-F files preprocessed with cpp -w -P
- Add graphify export {html,obsidian,wiki,svg,graphml,neo4j} CLI subcommands
- Add graphify query/path/explain CLI subcommands
- Reduce skill.md from 63KB to 47KB by replacing Python heredocs with CLI calls
- Extend to_html() with node_limit param for auto-aggregation on large graphs
- Add integration tests for all export/query/path/explain subcommands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 11:17:06 +01:00