fix(export): detect a stale .graphify_analysis.json and reconstruct from graph.json - #3557
ayushcodes10 wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Detects a stale .graphify_analysis.json during graphify export (html/wiki/obsidian/svg/graphml/neo4j) by comparing the node-id set the sidecar records against the one in graph.json, rather than trusting mere presence of the file. On a mismatch — which happens because update/watch advance per-node community attributes without regenerating the sidecar — it reconstructs communities from graph.json, recomputes cohesion via score_all, drops stale god-node data, and warns on stderr naming cluster-only as the refresh command. Comparison uses node-id sets rather than community ids since those renumber run-to-run for the same partition; an up-to-date sidecar takes no warning and keeps its recorded data.
No blocking issues surfaced. 6 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 560 functions depend on the 341 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 124 callees - new:
_make_graph()— 36 callers, 6 callees - new:
_stale_graph_sources()— 7 callers, 6 callees - new:
_run_hook_guard()— 4 callers, 8 callees - new:
test_poisoned_manifest_is_healed()— 0 callers, 6 callees
Verification — 560 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 498 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
275 of 275 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_affected_cli.py— impact, full-run-safetytests/test_affected_member_seed.py— full-run-safetytests/test_agents_platform.py— impact, full-run-safetytests/test_analyze.py— full-run-safetytests/test_anthropic_custom_endpoint.py— full-run-safetytests/test_antigravity_install.py— full-run-safetytests/test_apm_fallback_version.py— full-run-safetytests/test_architecture_doc.py— full-run-safetytests/test_astro_extraction.py— full-run-safetytests/test_astro_import_ids.py— full-run-safetytests/test_atomic_canvas_export.py— full-run-safetytests/test_atomic_version_stamp.py— full-run-safetytests/test_atomic_writes.py— full-run-safetytests/test_backend_env_isolation.py— full-run-safetytests/test_backend_extras.py— full-run-safetytests/test_benchmark.py— full-run-safetytests/test_benchmark_raw_graph.py— full-run-safetytests/test_build.py— full-run-safetytests/test_build_merge_dedup_scope.py— full-run-safetytests/test_build_merge_hyperedges_and_prune.py— full-run-safetytests/test_build_merge_shrink_guard.py— full-run-safetytests/test_builtin_global_type_refs.py— full-run-safetytests/test_cache.py— full-run-safetytests/test_callflow_html.py— full-run-safetytests/test_cargo_introspect.py— full-run-safetytests/test_carried_hyperedge_remap.py— full-run-safetytests/test_case_sensitive_resolution.py— full-run-safetytests/test_charmap_encoding.py— full-run-safetytests/test_chunking.py— full-run-safetytests/test_cjs_module_extension.py— full-run-safetytests/test_claude_cli_backend.py— full-run-safetytests/test_claude_md.py— full-run-safetytests/test_cli_broken_pipe.py— full-run-safetytests/test_cli_export.py— impact, changed-test, full-run-safetytests/test_cli_help.py— full-run-safetytests/test_cluster.py— full-run-safetytests/test_codebuddy.py— impact, full-run-safetytests/test_community_hub_labels.py— full-run-safetytests/test_community_labels_skill.py— full-run-safetytests/test_confidence.py— full-run-safetytests/test_corrupt_graph_json.py— full-run-safetytests/test_cpp_nested_and_cli.py— full-run-safetytests/test_cpp_objc_cross_file_calls.py— full-run-safetytests/test_cpp_preprocess.py— full-run-safetytests/test_cross_extension_reexport_self_cycle.py— full-run-safetytests/test_cross_language_call_resolution.py— full-run-safetytests/test_cross_repo_member_calls.py— full-run-safetytests/test_cross_repo_shared_types.py— full-run-safetytests/test_csharp_call_site_generic_args.py— full-run-safetytests/test_csharp_enum_members.py— full-run-safety- … and 225 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
· 5 more finding(s) on lines outside this diff (see the check run).
Toward issue 2386: this hoists the reconstruction from graph.json's per node community attribute out of the "sidecar is missing" branch so it runs every time, with no behavior change yet since it is still only used when the sidecar produced nothing. The next commit compares it against the sidecar to also catch a sidecar that exists but is stale. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
Fixes issue 2386. The existing fallback only reconstructed communities from graph.json when the sidecar was missing entirely; a sidecar that exists but was written by an earlier clustering pass looked identical from the outside and kept winning, since update and watch never regenerate .graphify_analysis.json. This compares the node id set each side covers, cheap and already in memory, rather than the community ids themselves, since those can renumber run to run even for the same partition. A mismatch means the sidecar is stale: prefer the fresh reconstruction, recompute cohesion with score_all so wiki articles and the HTML export do not swap one silent degradation for a smaller one, reset gods_data so the existing self heal at the wiki export site recomputes it, and print a warning naming the exact command that refreshes the sidecar, since the whole point of this issue is that nothing currently signals the divergence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
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
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
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
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
ed8a6c1 to
e0640d6
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Detects a stale .graphify_analysis.json sidecar during graphify export and reconstructs communities from graph.json rather than exporting against fossil clustering data. Staleness is judged by comparing the node-id sets each side covers (not community ids, which renumber across runs); on a mismatch, dispatch_command warns to stderr naming the exact node counts and the graphify cluster-only . refresh command, recomputes cohesion via score_all, and clears god-node data. An up-to-date sidecar still wins with no warning.
Worth a look
- Stale detection uses only node-set equality, missing membership/partition changes that keep the same node set —
graphify/cli.py:3013· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 561 functions depend on the 342 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 125 callees - new:
_make_graph()— 36 callers, 6 callees - new:
_stale_graph_sources()— 7 callers, 6 callees - new:
_run_hook_guard()— 4 callers, 8 callees - new:
test_poisoned_manifest_is_healed()— 0 callers, 6 callees
Verification — 561 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 499 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
283 of 283 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_affected_cli.py— impact, full-run-safetytests/test_affected_member_seed.py— full-run-safetytests/test_agents_platform.py— impact, full-run-safetytests/test_analyze.py— full-run-safetytests/test_anthropic_custom_endpoint.py— full-run-safetytests/test_antigravity_install.py— full-run-safetytests/test_apm_fallback_version.py— full-run-safetytests/test_architecture_doc.py— full-run-safetytests/test_astro_extraction.py— full-run-safetytests/test_astro_import_ids.py— full-run-safetytests/test_atomic_canvas_export.py— full-run-safetytests/test_atomic_version_stamp.py— full-run-safetytests/test_atomic_writes.py— full-run-safetytests/test_backend_env_isolation.py— full-run-safetytests/test_backend_extras.py— full-run-safetytests/test_benchmark.py— full-run-safetytests/test_benchmark_raw_graph.py— full-run-safetytests/test_build.py— full-run-safetytests/test_build_merge_dedup_scope.py— full-run-safetytests/test_build_merge_hyperedges_and_prune.py— full-run-safetytests/test_build_merge_shrink_guard.py— full-run-safetytests/test_builtin_global_type_refs.py— full-run-safetytests/test_cache.py— full-run-safetytests/test_callflow_html.py— full-run-safetytests/test_cargo_introspect.py— full-run-safetytests/test_carried_hyperedge_remap.py— full-run-safetytests/test_case_sensitive_resolution.py— full-run-safetytests/test_charmap_encoding.py— full-run-safetytests/test_chunking.py— full-run-safetytests/test_cjs_module_extension.py— full-run-safetytests/test_claude_cli_backend.py— full-run-safetytests/test_claude_md.py— full-run-safetytests/test_cli_broken_pipe.py— full-run-safetytests/test_cli_export.py— impact, changed-test, full-run-safetytests/test_cli_help.py— full-run-safetytests/test_cluster.py— full-run-safetytests/test_codebuddy.py— impact, full-run-safetytests/test_community_hub_labels.py— full-run-safetytests/test_community_labels_skill.py— full-run-safetytests/test_confidence.py— full-run-safetytests/test_corrupt_graph_json.py— full-run-safetytests/test_cpp_nested_and_cli.py— full-run-safetytests/test_cpp_objc_cross_file_calls.py— full-run-safetytests/test_cpp_preprocess.py— full-run-safetytests/test_cross_extension_reexport_self_cycle.py— full-run-safetytests/test_cross_language_call_resolution.py— full-run-safetytests/test_cross_repo_external_call_guards.py— full-run-safetytests/test_cross_repo_member_calls.py— full-run-safetytests/test_cross_repo_shared_types.py— full-run-safetytests/test_csharp_call_site_generic_args.py— full-run-safety- … and 233 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
· 5 more finding(s) on lines outside this diff (see the check run).
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 Graphify-Labs#1667 guard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Re: "Stale detection uses only node-set equality, missing membership/partition changes that keep the same node set" — confirmed real, pushed a fix. The flat node-id-set comparison missed a whole class of staleness: a merge of two communities, a split of one, or a single node moving from one community to another can all leave the overall node set exactly unchanged while still describing a different clustering. Now comparing each side's set of community blocks ( Added a regression test that merges the fixture's two communities into one (same node set, different partition) and confirms the stale path now fires. Full suite (5597 passed, no regressions) and |
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Detects a stale .graphify_analysis.json during graphify export and reconstructs communities from graph.json instead of exporting against it. dispatch_command now always rebuilds the partition from each node's community attribute and, when a sidecar exists, compares its partition (set of community blocks, not ids or the flat node set) against the fresh one — on mismatch it warns naming cluster-only as the fix, swaps in the reconstruction, and recomputes cohesion via score_all while clearing god-node data. Previously an existing-but-stale sidecar silently won because only a missing one triggered reconstruction.
Worth a look
- Stale-sidecar detection resets gods_data unconditionally, dropping valid god-node data —
graphify/cli.py:3032· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 563 functions depend on the 344 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 125 callees - new:
_make_graph()— 37 callers, 6 callees - new:
_stale_graph_sources()— 7 callers, 6 callees - new:
_run_hook_guard()— 4 callers, 8 callees - new:
test_poisoned_manifest_is_healed()— 0 callers, 6 callees
Verification — 563 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 501 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
283 of 283 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_affected_cli.py— impact, full-run-safetytests/test_affected_member_seed.py— full-run-safetytests/test_agents_platform.py— impact, full-run-safetytests/test_analyze.py— full-run-safetytests/test_anthropic_custom_endpoint.py— full-run-safetytests/test_antigravity_install.py— full-run-safetytests/test_apm_fallback_version.py— full-run-safetytests/test_architecture_doc.py— full-run-safetytests/test_astro_extraction.py— full-run-safetytests/test_astro_import_ids.py— full-run-safetytests/test_atomic_canvas_export.py— full-run-safetytests/test_atomic_version_stamp.py— full-run-safetytests/test_atomic_writes.py— full-run-safetytests/test_backend_env_isolation.py— full-run-safetytests/test_backend_extras.py— full-run-safetytests/test_benchmark.py— full-run-safetytests/test_benchmark_raw_graph.py— full-run-safetytests/test_build.py— full-run-safetytests/test_build_merge_dedup_scope.py— full-run-safetytests/test_build_merge_hyperedges_and_prune.py— full-run-safetytests/test_build_merge_shrink_guard.py— full-run-safetytests/test_builtin_global_type_refs.py— full-run-safetytests/test_cache.py— full-run-safetytests/test_callflow_html.py— full-run-safetytests/test_cargo_introspect.py— full-run-safetytests/test_carried_hyperedge_remap.py— full-run-safetytests/test_case_sensitive_resolution.py— full-run-safetytests/test_charmap_encoding.py— full-run-safetytests/test_chunking.py— full-run-safetytests/test_cjs_module_extension.py— full-run-safetytests/test_claude_cli_backend.py— full-run-safetytests/test_claude_md.py— full-run-safetytests/test_cli_broken_pipe.py— full-run-safetytests/test_cli_export.py— impact, changed-test, full-run-safetytests/test_cli_help.py— full-run-safetytests/test_cluster.py— full-run-safetytests/test_codebuddy.py— impact, full-run-safetytests/test_community_hub_labels.py— full-run-safetytests/test_community_labels_skill.py— full-run-safetytests/test_confidence.py— full-run-safetytests/test_corrupt_graph_json.py— full-run-safetytests/test_cpp_nested_and_cli.py— full-run-safetytests/test_cpp_objc_cross_file_calls.py— full-run-safetytests/test_cpp_preprocess.py— full-run-safetytests/test_cross_extension_reexport_self_cycle.py— full-run-safetytests/test_cross_language_call_resolution.py— full-run-safetytests/test_cross_repo_external_call_guards.py— full-run-safetytests/test_cross_repo_member_calls.py— full-run-safetytests/test_cross_repo_shared_types.py— full-run-safetytests/test_csharp_call_site_generic_args.py— full-run-safety- … and 233 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
· 5 more finding(s) on lines outside this diff (see the check run).
god_nodes ranks purely by graph degree, independent of the community partition, so clearing it to an empty list on the stale path and relying on the wiki subcommand's own recompute-if-empty fallback further down worked today only because wiki happens to be the only current reader of this value. Recompute it directly here instead, so a future reader that does not carry the same fallback cannot silently lose real data. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Re: "Stale sidecar detection resets gods_data unconditionally, dropping valid god node data" — checked this directly.
Still a real fragility worth fixing though — it silently depended on that one consumer's own guard rather than being correct on its own terms, and would silently drop real data for any future reader that doesn't carry the same fallback. Pushed a commit that recomputes it directly at the stale detection site instead, mirroring how I didn't add a new regression test for this specific piece: since both the old (clear + rely on the wiki fallback) and new (recompute directly) code paths produce byte identical Full suite (5597 passed, no regressions) and |
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Detects a stale .graphify_analysis.json sidecar during graphify export (html/wiki/obsidian/svg/graphml/neo4j) by comparing the sidecar's community partition against a partition reconstructed from graph.json's per-node community attributes, rather than trusting the sidecar merely because it exists. On mismatch — which update/watch can cause since they advance graph.json but never regenerate the sidecar — it warns to stderr naming graphify cluster-only ., then exports against the reconstructed communities with cohesion recomputed via score_all and gods_data via god_nodes. The comparison uses partition blocks (not community ids, which renumber, nor the flat node-id set, which misses merges/splits that keep the node set unchanged).
No blocking issues surfaced. 5 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 563 functions depend on the 344 functions this change touches.
Health — this change adds coupling hotspots:
- new:
dispatch_command()— 2 callers, 125 callees - new:
_make_graph()— 37 callers, 6 callees - new:
_stale_graph_sources()— 7 callers, 6 callees - new:
_run_hook_guard()— 4 callers, 8 callees - new:
test_poisoned_manifest_is_healed()— 0 callers, 6 callees
Verification — 563 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 501 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
283 of 283 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_affected_cli.py— impact, full-run-safetytests/test_affected_member_seed.py— full-run-safetytests/test_agents_platform.py— impact, full-run-safetytests/test_analyze.py— full-run-safetytests/test_anthropic_custom_endpoint.py— full-run-safetytests/test_antigravity_install.py— full-run-safetytests/test_apm_fallback_version.py— full-run-safetytests/test_architecture_doc.py— full-run-safetytests/test_astro_extraction.py— full-run-safetytests/test_astro_import_ids.py— full-run-safetytests/test_atomic_canvas_export.py— full-run-safetytests/test_atomic_version_stamp.py— full-run-safetytests/test_atomic_writes.py— full-run-safetytests/test_backend_env_isolation.py— full-run-safetytests/test_backend_extras.py— full-run-safetytests/test_benchmark.py— full-run-safetytests/test_benchmark_raw_graph.py— full-run-safetytests/test_build.py— full-run-safetytests/test_build_merge_dedup_scope.py— full-run-safetytests/test_build_merge_hyperedges_and_prune.py— full-run-safetytests/test_build_merge_shrink_guard.py— full-run-safetytests/test_builtin_global_type_refs.py— full-run-safetytests/test_cache.py— full-run-safetytests/test_callflow_html.py— full-run-safetytests/test_cargo_introspect.py— full-run-safetytests/test_carried_hyperedge_remap.py— full-run-safetytests/test_case_sensitive_resolution.py— full-run-safetytests/test_charmap_encoding.py— full-run-safetytests/test_chunking.py— full-run-safetytests/test_cjs_module_extension.py— full-run-safetytests/test_claude_cli_backend.py— full-run-safetytests/test_claude_md.py— full-run-safetytests/test_cli_broken_pipe.py— full-run-safetytests/test_cli_export.py— impact, changed-test, full-run-safetytests/test_cli_help.py— full-run-safetytests/test_cluster.py— full-run-safetytests/test_codebuddy.py— impact, full-run-safetytests/test_community_hub_labels.py— full-run-safetytests/test_community_labels_skill.py— full-run-safetytests/test_confidence.py— full-run-safetytests/test_corrupt_graph_json.py— full-run-safetytests/test_cpp_nested_and_cli.py— full-run-safetytests/test_cpp_objc_cross_file_calls.py— full-run-safetytests/test_cpp_preprocess.py— full-run-safetytests/test_cross_extension_reexport_self_cycle.py— full-run-safetytests/test_cross_language_call_resolution.py— full-run-safetytests/test_cross_repo_external_call_guards.py— full-run-safetytests/test_cross_repo_member_calls.py— full-run-safetytests/test_cross_repo_shared_types.py— full-run-safetytests/test_csharp_call_site_generic_args.py— full-run-safety- … and 233 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
· 5 more finding(s) on lines outside this diff (see the check run).
Fixes #2386.
Summary
graphify export wiki/html/obsidian/svg/graphml/neo4j/falkordbtake their community partition from.graphify_analysis.json, written only byextractandcluster-only/label— never byupdateor the watch rebuild path. So after any number ofupdateruns,graph.json(and its per-nodecommunityattribute) keeps advancing while the analysis sidecar freezes at the last fullextract.An existing fallback (
cli.py, added for #746/#1610) already reconstructs communities fromgraph.json's per-node attribute, but it's gated on the sidecar being missing (if not communities:). A sidecar that exists but is stale looks identical from the outside — no error, no warning — and takes the other branch, so the fresh data sitting ingraph.jsontwo lines above is ignored. The issue reporter measured this directly on an 8.4k-file repo: the sidecar was 9 days and one re-partitioning era behind (2,359 vs 6,243 communities), 7.4% of nodes got no wiki article, and the only visible signal was adropped N stale node ID(s)line that reads like routine housekeeping. A second commenter confirmed the same mechanism independently on a different repo with concrete before/after data (34 orphaned nodes, 1,149 mismatched community assignments).This is "Option A" from the issue, which the reporter already scoped precisely down to the exact caveat it needs to avoid trading one silent degradation for a smaller one (stale
cohesionsurviving into wiki article metadata even after communities are fixed).Changes
graphify/cli.py: the per-node reconstruction now always runs (not just when the sidecar is empty). When the sidecar exists, its covered node-id set is compared against the fresh reconstruction's — cheap, since both are already in memory, and deliberately node-id-based rather than community-id-based since community ids can renumber run to run even for the same partition (Non-deterministic community assignments across identical-corpus runs (0.9.6) #1667). A mismatch means the sidecar is stale: the fresh data wins,cohesionis recomputed viascore_all(the same call the normal path already makes),gods_datais reset so the existing self-heal at the wiki export site recomputes it, and a warning is printed naming the exact command (cluster-only) that refreshes the sidecar for real.tests/test_cli_export.py: four new tests — the html export path healing and warning on a stale sidecar, the wiki export path specifically recomputing cohesion (an impossible sentinel cohesion value must not survive into the output), and a negative control confirming an up-to-date sidecar never trips the new path.CHANGELOG.md: entry under 0.9.61 (unreleased).Testing
python -m pytest tests/test_cli_export.py -k "stale or still_matches" -q— 4 passedpython -m pytest -q— 5488 passed, 68 skipped (pre-existing unrelated failures excluded:tests/test_ollama_retry_cap.pymissing the optionalopenaimodule, andtest_ts_normalizer_scales_linearly_on_large_files/test_hyperedge_convex_hull_js_is_geometrically_sound, both known environment-specific flakes unrelated to this change)python -m tools.skillgen --check— OKexport htmlprints the new warning and renders correctly from the fresh data.🤖 Generated with Claude Code
https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh