Repository navigation
Release 0.1.9 - #1922
Merged
Merged
Release 0.1.9#1922
Conversation
… field An edit, insertion or comment on a later line of a const or field whose initializer spans several lines was reported as a body change of the module (or 'inside' the type), so test-impact seeded from the whole module. It is now the field's 'initializer changed'. A callable written inside the initializer keeps its own body; a Python module-level name is measured by its statement, not its first-to-last binding span. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
… lambda keeps its body Since data keys of const objects are declarations, an edit to a key's value was read as a typed field: 'type 3, → 4,', and on a one-line const 'LIMIT.max renamed → LIMIT'. It is now the key's 'initializer changed'. A lambda on a later line of a multi-line initializer is its own body again, as a method written there already was. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Promote staged fixes into 0.1.9
…ect method
`impact Repo.get` listed every `x.get(...)` whose receiver the engine could not
type, and among them the calls on what an unstaged package returned or
constructed (`request(app).get('/x')`, `new grpc.Metadata().get(k)`). Those
filled the first page ahead of the real leads, and seeded the by-name closure,
so tests that only issue HTTP requests counted as tests of the method.
- JavaScript and TypeScript engines: `library_receiver(site, specifier)`, an
unresolved member call whose receiver is rooted in a bare-specifier import no
staged IR declares (a binding, a member of one, a call or `new` on one, an
await of one, a never-reassigned const holding one). A call handed a project
instance is left out, since a wrapper or mock helper may return it.
- impact: such a site is the unresolved kind "library": its own by-name row,
sorted last and grouped as [library receiver] in --grep, no closure seed, no
param row; path's by-name group and the SQL fast path agree.
- Goldens: case 28 gains the shapes and controls; other JS cases gain their
library_receiver diagnostics (edges unchanged).
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…t-member-declaration TypeScript: each key of a module-level const object literal is a declaration
…t-matches-in-lockfiles context/impact: lockfiles and manifest package lists are never text leads; --in narrows text files
…onst-initializer-change-attri changed: an edit inside a multi-line const initializer is that const's
…ts after 61 Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
The 78/80 goldens both sides regenerated are blessed again from the merged engine (the result differs from the integration tip by exactly this PR's rows), and the two 86 tests gain the reads this PR resolves (module consts read through their bindings); no resolved row is lost. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…nst-read-through-member-acces engine: resolve reads of module-level consts through their import binding
…s-from-library-receivers impact: a call on a package's value is not a by-name caller of a project method
…cess and the state relations Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…e-registration-treated-global impact: a callback given to one instance reaches callers only through that instance
…s complete A caller reached through an interface was explained with the precision figure for target sets the engine could not narrow, so the only correct answer read as a guess and agents re-read the source to check it. Dispatch rows now get their own legend, and a `complete:` line is printed when no row is by-name, text or a capped set and nothing inside the impacted set is unresolved. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…iomCodeAI/axiom-code-graph into fix/impact-trustworthy-output
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
impact: word interface dispatch as certain, and say when the answer is complete
…not know; impact shows code only where no text search reaches; find leaves MCP The hook after a grep now names, for each identifier, the declarations its matched lines reach when they differ, and the callers whose call never spells the name; it is silent when grep was complete. impact lists the places a word grep already finds by location only, names places further than one hop and the tests without code, and keeps the code for the direct places grep cannot see. MCP offers impact, path and tests; find stays a shell verb. AXIOMCODE_GREP_AID=0 restores the previous answers. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…sts cover both notes A grep that finds only a route handler's declaration reads as dead code; the note now says the runtime or a framework enters it, and stays silent for a plain uncalled method. The previous note's checks run under AXIOMCODE_GREP_AID=0, and the grep-aid checks (who enters it, silence when grep was complete) run beside them. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Aid grep instead of replacing it: grep notes, smaller impact answers, three MCP tools
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
grep aid: off and false switch it off too
… saying what it is Agents on the trial build read the collapsed form as a missing direct section: an implementation listed among grep's confirmed callers, a call across a process boundary folded into one line, 'reached through the ones above' with nothing above. A direct place now drops to the grep line only when it is a plain resolved call, read or write that spells the name, and the first three direct callers keep their code even then; an override, an implementation, an injection, a hand-off as a value or a cross-process call keeps its code and carries its reason in the tag. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
impact: keep direct callers and links grep cannot make, each saying what it is
…tests listed apart - A JavaScript / TypeScript function is never a test by its name (runners collect the callback handed to test()/it()), and a module-level Python test_* function counts only in a module pytest collects: a helper in test/helpers.js or tests/helpers.py was "1 test" in a file no runner collects. - impact marks each test with loads_change: whether its file (or the fixture / conftest files its runner loads) imports the changed file, through the import closure. - test-impact lists first the files that load the change within 3 hops, then "further out" the rest (a key or registration joins them, or the route is long), with its own run command. - imports_fact resolves an ES module import written with its extension and a workspace package's specifier (package.json exports / main); IMPACT_VERSION 63. - The import-time hop no longer fires from the module that merely declares a const asked about: its readers resolve, and every importer's module was listed again (exposed once .js imports resolved). Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…ceiver is not a call by name Measured against a compiler-resolved call graph, the two largest sources of wrong caller rows were overload fans and calls by name. Overloads: the argument-type prune only compared predefined argument and parameter types, and never an extension method. It now also rejects, on the parameter the argument lands on (an extension called on a receiver shifted by one): - a lambda against a delegate parameter of another parameter count (Func / Action / Predicate / Comparison / Converter, through Expression), or against a predefined parameter type; - a predefined value against a delegate, a non-params array, an exception, or a class or struct in source that declares no conversion operator; - a value of a source class or struct against a delegate, a predefined type, or a source type it neither derives from nor implements when neither declares a conversion. Prune-only; a site is never emptied. Receivers: `string.Format(..)` (the parser writes a keyword receiver with no name) and a qualified property or field declared with a library type (`result.Errors.Add(x)`) were left unresolved, so impact read them as calls by name to every project method of that name. Both are labelled external now, as a bare local or parameter of those types already was. Cases: an-argument-shape-picks-the-overload (control: two delegates of one parameter count stay one of a set), a-library-typed-receiver-is-not-a-call- by-name (control: a qualified property of a project type still resolves). C# case suite 286/286, C# engine suite green. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…lement types; more overload prunes
Against the compiler-resolved call graph, most missing direct calls were
property accesses with no graph site at all, and most extra ones overload
fans.
Property accesses:
- An object initializer's target (`new Cfg { Size = 4 }`) names a member of
the created type; it is now looked up there, so its set / init accessor
has an edge.
- `a?.B?.C`: the parser writes each conditional member as a nameless member
access holding the name as its qualifier, which no rule read. The member
is looked up on the qualifier's type and the access takes its type, so a
chain resolves link by link.
- A project collection whose GetEnumerator returns `IEnumerator<T>` (an
iterator) now types its foreach variable as T; the framework's Current is
not staged, but the type argument is written on the method.
Overloads (prune-only, a site never emptied):
- an interface-typed argument against a delegate, a predefined type, a
class or struct in source, or an interface it does not extend;
- a lambda against a class, struct, interface or enum in source, an array,
or a reflection type (`Map(m => m.Id)` against `Map(Type, MemberInfo)`);
- explicit type arguments against an overload of another generic arity.
Cases: a-property-read-however-it-is-written (control: a plain read), and
an-argument-shape-picks-the-overload extended. C# case suite 319/319, C#
engine suite green.
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…/java-reach-loop # Conflicts: # plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact
fix(csharp): reach loop — accessor dispatch, implicit calls, delegate parameters
Java reach: narrower initializer hop, platform boundaries, operator overloads
Apps/integration 0.1.9
Release 0.1.9
The front door asks every verb for --json. In that mode path and context run the answer inside redirect_stdout; a refusal (an endpoint nothing declares) leaves through die() -> SystemExit, which escaped the with-block, so neither the JSON nor its prose was printed: 'axiomcode path main NoSuchName' answered nothing at all, rc 2. SystemExit is caught inside the redirect and its code kept, so the document is printed with the refusal as its prose. Case a-refused-endpoint-is-said: the front-door check fails on the base (2/3), all pass after; control: a declared pair still answers. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Linux: libgomp links statically for real. -fopenmp on the link line made gcc append its own dynamic -lgomp, so every engine needed libgomp.so.1, which a stock Ubuntu does not have. -fopenmp now compiles only; the link names libgomp.a by path (+ -ldl it needs). Validated on manylinux_2_28 gcc 14: NEEDED is libc/libm/libpthread/libdl/ld-linux only, max GLIBC 2.25, a real index runs on a stock Ubuntu 24.04 with no libgomp1, -j 4 and -j 1 give the same edges. Windows: no /openmp. It links vcomp140.dll (and vcruntime140.dll), absent without the Visual C++ Redistributable; every engine exited 0xC0000135 on a stock Windows Server 2022. Engines are serial on Windows, as through 0.1.8; no .parallel marker. Two new steps fail the build when an engine loads a library a stock system lacks (readelf NEEDED on Linux, dumpbin /dependents on Windows). The engine cache key hashes this file, so no binary built with the old flags is reused. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
path, context: a refusal in --json mode keeps its prose (#1911)
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
) export_lock asked whether the .exporting holder was alive with os.kill(pid, 0). On Windows signal 0 is CTRL_C_EVENT: the probe interrupted the exporter (and its console group), so a query waiting for an export killed it and took the lock over. On a stock Windows Server 2022 'impact DefaultParser.parse' on a real Java project ran 14+ min (0.1.8: 6.8 s). pid_alive: OpenProcess + GetExitCodeProcess (STILL_ACTIVE) on Windows, os.kill(pid, 0) only on POSIX; when liveness cannot be told, the lock's age decides as before. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
windows: the export lock's liveness probe no longer sends Ctrl-C to its holder (#1916)
…1918) ax_libs ran bin/axiomcode (a bash script) directly to compile each dependency; on Windows that is WinError 193, so --library auto staged nothing in any language. It now runs through AXIOMCODE_BASH (Git Bash on Windows) as every other script does. library-auto-discovers-imported-dependencies passes for python and javascript on macOS. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
build-engines: engines start on a clean machine — static libgomp on Linux, no OpenMP on Windows (#1913)
…al, as a document (#1920) impact --json with no name printed the usage text: only the front door answered for the working tree's edits. The dispatcher now sends it to ax_blocks edits-json: the impact document for the declarations the edits changed, with the edits under "edits" and a 'your edits:' line in its prose. A flag's value is not a name; --warm, --from-text and --delete keep the verb's own forms. impact <a name nothing declares> --json printed the refusal as plain text. In --json mode main() runs inside a redirect, and a refusal is printed as {targets: [], refusal, prose}. Case impact-json-without-a-name-answers-the-edits: --json parses for impact (named, no name, unknown), path (unknown), tests and context (no match); the no-name check fails on the base. Cases: python 445/445, typescript 352/352, javascript 354/354, java 374/374, csharp 319/319. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
windows: --library auto compiles dependencies through bash (#1918)
When no changed declaration can be named (an edit outside any declaration, a fresh
checkout), test-impact printed its prose even under --json, so stdout did not parse:
the CI run of impact-json-without-a-name-answers-the-edits caught it. In --json mode
main() runs inside a redirect and a non-JSON answer is printed as
{changed: [], tests: [], prose}, exit code kept.
Cases: python 445/445, typescript 352/352, javascript 354/354, java 374/374,
csharp 319/319.
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
impact --json answers in every form: no name answers the edits, a refusal is JSON (#1920)
swapnilpaliwal-sd
requested review from
JaredHLZhang,
Whua689 and
suyashpaliwal26
as code owners
October 11, 2026 02:42
macOS: build a static libomp from the pinned LLVM release with a macOS 12 deployment target and link it by path (-Xclang -fopenmp), so an engine loads only /usr/lib/libc++ and libSystem; write the .parallel marker. A new guard fails the build on anything outside /usr/lib and /System, a minos above 12.0, or a .parallel engine without the OpenMP runtime in it. Windows: compile the language engines with /openmp again and copy vcomp140.dll (plus any VC runtime DLL it imports) from the MSVC redist folder beside each engine; write the .exe.parallel marker. The guard now requires every DLL an engine or a shipped DLL imports to be part of Windows or beside it. The engine package's files list carries */*.dll. run-souffle.sh: AXIOM_SOLVE_PARALLEL=0 now holds a packaged parallel engine to -j 1 too, and the PARALLEL SOLVE comments describe every platform. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…8's time (#1924) - build: wait up to AXIOMCODE_WARM_WAIT (default 15 s) for the background impact facts export before index returns, so the first query does not sleep on the export lock; a large repository's export still goes on in the background - ax_links.unknown_sites: memoise the candidate lookups within one answer and read each file's handed-over values once (891 -> 169 SQL queries on a Java answer) - ax_fresh.py query: run the front door's renderer (ax_blocks.py) in its own process instead of starting Python again - ax_blocks: read each file's callables once instead of a full symbols scan per place, and start the word grep alongside the verb when the names match Answers are byte-identical: 60 answers on three real projects, and an exhaustive enclosing-callable check over 10 graphs in five languages. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
A packaged engine is the parallel flavor on every published platform, so run-souffle.sh passes a fixed -j 8 whenever the .parallel marker is beside it: no AXIOM_SOLVE_PARALLEL or thread-count variable changes the shipped path, and every user's solve is the configuration the release validated. A local compile keeps its OpenMP probe, AXIOM_SOLVE_PARALLEL and AXIOMCODE_SOLVE_THREADS. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…here Ship parallel engines on every platform at a fixed -j 8 (macOS static libomp, Windows vcomp140 beside the engine) (#1923)
impact: first query after index and warm queries back near 0.1.8 (#1924)
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.
Release 0.1.9
#1904