Skip to content

Fix/graph completeness and blast - #10

Merged
Naseem77 merged 17 commits into
mainfrom
fix/graph-completeness-and-blast
Oct 16, 2026
Merged

Naseem77 merged 17 commits into
mainfrom
fix/graph-completeness-and-blast

Conversation

@Naseem77

Copy link
Copy Markdown
Owner

No description provided.

Naseem77 and others added 17 commits October 16, 2026 20:30
mcp>=1.0 resolved to 2.x on a fresh install, where mcp.server.fastmcp
no longer exists, so serve-mcp crashed. Use MCPServer when present and
fall back to FastMCP, report Graphora's version (not the SDK's), and
bound the dependency to <3.

CI started no FalkorDB, so 46 of 115 tests (store, blast, CLI, MCP)
silently skipped. Add a FalkorDB service, test both mcp majors, and
fail the job if anything is skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…arse

_walk_nodes recursed once per tree level, so a long expression
(e.g. 3,000 chained '+' terms) raised RecursionError, and the indexer
did not catch it, aborting the whole run. Walk with an explicit stack
and isolate parse failures per file with a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The signature was content.splitlines()[line - 1], recomputed for every
symbol. splitlines() also breaks on form feeds and U+2028, so after such
a character the signature came from the wrong line; and re-splitting the
whole file per symbol was quadratic (74% of a 126 s index of a 461-file repository).
Slice the line around the node's start byte instead, and number regex
fallback lines by newline only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d subcommand

'graphora sessions --project X connected ...' dropped X: the inner
parser re-applied its own defaults over the outer parser's values, so
the command silently fell back to cwd as project and auto backend.
Nested parsers now declare the common flags with SUPPRESS defaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Running 'graphora blast X' from the wrong directory queried an empty
graph named after cwd and answered 'not found' with no hint why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_merge_call scanned every existing edge (quadratic), and write_files
rewrote the whole JSON after every file. Keep a (caller, callee, line)
index and let the indexer save once via link_cross_file_calls.
A 461-file repository: 19.3 s -> 3.4 s, identical graph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Inside a git work tree, collect files with 'git ls-files --cached
--others --exclude-standard' so ignored build output and secrets are
not indexed. Skip generated code (ANTLR/protobuf/'@generated'/
'DO NOT EDIT' headers, *.min.js, *_pb2.py) unless --include-generated.
On one test repository, 4 ANTLR files alone produced 7,300 functions and 24,000
call edges; indexing drops to 0.7 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop git fix-history mining: graphora/risk.py, the 'risk mine/top'
commands, the risk_top MCP tool, FixCommit/TOUCHED/FIXED storage, and
the risk fields on blast-radius results and review findings. Graphora
focuses on what a change could break. Review keeps the missing-test
warning. README is rewritten in a later commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each symbol now carries a qualified name (Widget.render, geo.Square.area),
its parent scope and kind, and an end line; each call records its
receiver ("" for a bare call, "self", "os.path"); each file records
its import bindings (local name -> module/member).

Newly covered: JS/TS arrow and function-expression variables, class
fields, object-literal methods, generators, TS interfaces/enums/abstract
classes; TSX now uses the TSX grammar (was 0 symbols); Java constructors,
interfaces, enums, records; Go methods attached to their receiver type;
Rust impl methods and union/mod scopes; C/C++ destructors, out-of-class
A::f definitions, typedef'd anonymous structs, enums; Ruby singleton
methods; PHP interfaces, traits, enums; Python lambdas.

Removed false definitions: C struct *usages* (struct point *p) and
bodiless declarations (interface/abstract methods, prototypes) are no
longer counted as definitions.

Checked against Python's ast on real repos: Shiftory 498/498 and
a larger 27,383-definition repository fully found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… updates

Calls were linked by bare name to every same-named function in the repo
(the 14 test calls to cli.main() fanned out to all 8 main() functions:
98 false edges) and imports were parsed but never used. A shared
resolver (graphora/resolve.py), used by both stores, now resolves each
call site through, in order: self/this -> enclosing class; the same file
(innermost visible scope); import bindings (Python absolute/relative and
src/ layouts, submodules, JS/TS relative paths, default exports, Go
packages, Java, Rust, C includes, Ruby require, PHP use); the same Go
package; and only then a name match. Imports that leave the repository
(os.path.join, fmt.Println) produce no edge; a call site with more than
8 candidates is left unlinked. An unknown receiver (x.save()) links every
method candidate as AMBIGUOUS, and each edge records its candidate count
so tools can say 'X or Y'.

Symbol keys use qualified names (with #n for redefinitions), so the
seven __init__ methods of one file are no longer merged into one node.

Stores persist raw call sites and re-resolve globally on link, so
re-writing a callee's file no longer drops callers in other files.
FalkorDB writes are batched with UNWIND and indexed; File->File
IMPORTS_FILE edges replace module-name suffix matching for importers.

Shiftory, checked against the source: build_evidence and analyze callers
exact; cli.main 2 test callers, worker.main 1 (no false edges).
Confidence mix 52/26/22 -> 83/5/12 % EXTRACTED/INFERRED/AMBIGUOUS.
A 457-file repository on FalkorDB: 134 s -> 2.3 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New graphora/impact.py walks callers up to --depth hops (default 2) from
the changed symbols (a class includes its methods) and splits them into:
- Will break: every call on the path is certain (EXTRACTED/INFERRED).
- Might break: some call is ambiguous. Instead of picking one, it lists
  what that call could mean: 'X or Y', plus 'a method outside this
  repository' when the receiver's type is unknown.
- Tests that reach it.

Diffs are mapped hunk-by-hunk to the innermost enclosing function,
method, or class, so edits inside a body count (review used to see only
changed def lines and missed them). Diff symbol names now use only their
file's language patterns (C's patterns read Python 'return len(' as a
definition of len).

Exposed as 'graphora breaks NAME... | --diff | --git-range' and the MCP
tools what_could_break / what_could_break_for_diff; review and
blast_radius_for_diff build on it, and the agent skill now leads with it.
Review no longer claims tokens were 'sent to model' in facts mode.

Resolver precision: a capitalized constructor receiver (Db().save()) is
typed, and production code is not resolved to test doubles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove unused imports, replace a lambda assignment, annotate the
remaining untyped containers, fix a mistyped loop variable in the
resolver and argparse option forwarding, and add ruff (E/F/W) and mypy
config plus a CI lint job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The benchmark only compared prompt sizes and the README claimed 'more
accurate reviews' without measuring accuracy. It now reports:
- definition coverage: every def/class Python's own ast finds must be a
  graph node with the same qualified name;
- call-edge certainty: EXTRACTED / INFERRED / AMBIGUOUS counts.
The public benchmark table gains both columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Calls on variables no longer fall back to 'any method with this name'
when the source states the type:
- typed parameters and annotations (g: Graph, (g: Graph), Graph g,
  g *Graph, g: &Graph, Graph $g), constructor assignments
  (db = FalkorDB(), x := &Foo{}, let x = Foo::new(), $x = new Foo,
  x = Foo.new) and self./this./@ attributes;
- call results through the callee's declared return type
  (graph = db.select_graph(); graph.query() and chained
  db.select_graph().query()), including Promise<T>/Optional[T]/Self.

Imports now follow re-exports (package __init__.py, export ... from,
export * from) and resolve absolute modules from the nearest source
root, so 'from falkordb import X' no longer also matches
falkordb/asyncio/falkordb.py.

Certain call edges (EXTRACTED+INFERRED): falkordb-py 28% -> 57%,
Shiftory 91% -> 97%, GraphRAG-SDK 66% -> 66%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
'x: A | B' (and Union[A, B]) now resolves x.m() to A.m or B.m, reported
as an X-or-Y call. Graphora's own functions were annotated 'store:
GraphStore' but also receive the embedded store, so its graph (and mypy)
saw only one backend; they now take GraphBackend, a union of both.
Text output lists at most 10 tests (JSON keeps all).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lead with what could break and X-or-Y answers; drop risk memory; replace
the token-only benchmark tables with accuracy (definition coverage vs
Python's ast, call-edge certainty) measured on Shiftory,
falkordb-py, and GraphRAG-SDK; recapture every use case from real runs.
The banner GIF showed risk memory and is no longer referenced.
Bump to 0.3.0 (risk memory removal and the store schema are breaking).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Twenty new tests: call resolution in Java, Rust, C, C++, Ruby, PHP, TS,
JS, and Go (imports, typed variables, implicit this, includes,
namespaces); review in facts mode and with a fake LLM; diffs that delete
functions or add/delete files; the CLI from --git-range and stdin; and
what_could_break giving identical answers on FalkorDB and embedded.

They found two bugs, fixed here:
- calls to the same name on one line with different receivers
  (r.area() + c.area()) were merged into one;
- namespace and object-literal calls (geo::total(), util::clamp(),
  api.load()) fell through to 'unknown receiver'.

Coverage 88% -> 91%; 200 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Naseem77
Naseem77 merged commit 0f402f2 into main Oct 16, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant