Repository navigation
Fix/graph completeness and blast - #10
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.