Repository navigation
Release 0.1.9 - #1905
Merged
Merged
Release 0.1.9#1905
Conversation
…ding A module-scope const used as `X.m`, `f(X)`, in a template or under `typeof X` had no data edge to its declaration, so impact matched it by name, including same-named consts in sibling packages whose files import their own. - TypeScript and JavaScript engines export field_access rows for an identifier the binder ties to a module variable, directly or through an import binding (across `export *` barrels); `typeof X` type queries bind through module scope, with a same-named parameter or local shadowing it. - The bundle positions a field-access site that is a type reference. - impact: a const the engine bound on a route line is still a registration. - Goldens re-blessed: module consts read by name now carry known_edge reads. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…s only through that instance - JavaScript engine: a new expression of a class whose instance code calls a value carries its allocation beside the instance; instance-state.dl names the edges that hold only for instances given the callee (constructor option, subscription, injected dependency) and the allocations each caller's receiver may be - a callee that also reaches the class another way (named inside it, returned to it, written onto it from outside, a class hierarchy, an entry with an unknown receiver) is not gated - impact walks a gated edge through the class's own code and leaves it only for a caller whose receiver may be an allocation given the callee, or is unknown; the SQL port does the same Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…eads; --in narrows text files A context question with a common word (debug, optional, string) listed package-lock.json and package.json lines as "text files that name these declarations" and made one of them the next step, even when --in named a directory holding neither file. - ax_nonsource: lockfiles of every package manager (npm, pnpm, yarn, NuGet, Gradle, Poetry, uv, Composer, Cargo, Go) are out of scope; a manifest's metadata and dependency lists (package.json, pyproject.toml, PackageReference) and package.json keys are skipped by line. Script commands and tool configuration values are still searched. - context: the caller's --in narrows text bindings as it narrows declarations; a mapper XML whose namespace names the declaring type stays (bound by the declaration, not the word). - ax_pages: a --source answer with no flow and no text row now ends with a next step. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…anifest; --in text dirs stay in scope The previous commit on this branch added the case but not the code it checks, and its npm lockfile fixture was gitignored, so CI ran the checks against the old scripts. - ax_nonsource: one manifest filter decided by where a word sits (entry, table, block, element), not by line: package.json, bower.json, deno.json, composer.json by JSON entry (a one-line manifest keeps its scripts); pnpm-workspace.yaml and conda environment.yml by block; pyproject.toml and Pipfile by table; requirements files whole; pom.xml, MSBuild, packages.config and .nuspec by package element. More lockfiles recognised. - context: the word-matched rows of a text-only --in use the same filter; a directory the main graph holds is no longer text to another language's graph; with several graphs, a text-only --in is answered once and never by a package outside it. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…nance-false-alarms-on-mirror Graph provenance: diff a no-commit graph against its file table; a later engine is newer
…cess-callback-registry TypeScript: join a keyed in-process registry's publish to the functions filed under the same key
…t-literal-keys-not-declared Declare the data keys of module-level const objects
…thod's body A MyBatis statement is bound to its mapper method by the mapper's namespace plus the statement id, but the plugin only used that binding one way. An edit inside <select id="findOpen"> was a file outside every indexed language: changed printed "changed declarations (0)" and test-impact selected no test. Impact did list the statement, as a [text] row after every test row, so on a mapper method stubbed in many tests the one-line-per-site answer cut it (on one project a mapper method's statement was listed at row 43). The change: - ax_nonsource.py reads the elements of a mapper XML (statements, <sql> fragments, result maps, with their lines) and maps an edit onto the statements it touches. An edit to a fragment or a result map is an edit to every statement that includes or names it. - changed reports each such statement as a body change of the method its namespace and id name (declared on the namespace type, or inherited from a base mapper), at the statement's line in the XML, with that method as the impact target, so test-impact selects the method's tests. A file stays named as outside the index when an edited line lies in no element with an id (its header). - impact labels a row that opens the method's own statement in its namespace "is its mapper statement" ([by key]), counts it as a place bound to the method in next:, and the one-line answer lists it with the direct dependents instead of after the tests. Test: tests/cases/java/mapper-statement-edit-is-its-method, with a same-id statement in another namespace as the near miss and an edit outside every statement as the control. 6 of its 7 checks fail on the release branch tip, all 7 pass with the change. Smoke, a small Spring Boot and MyBatis web app: an edit inside one statement went from 0 changed declarations and no test to 1 body change and 5 tests in the one test class that reaches the method; the statement row that had been at row 43 moved to row 2 of the one-line answer. Every statement named as a whole file maps to a method: 36 of 36 in the unedited XML files there, and 104 of 104 in a larger multi-module project; six of those checked by hand. Refs #1381 Not yet measured on the full corpus or on held-out projects; the smoke numbers above are the only corpus numbers.
…uses
Field impact missed three kinds of use that no Java reference names.
- A MyBatis parameter property. `#{it.quantity}` in the statement of a
mapper method that takes `@Param("it") Item item` reads Item.quantity
when the statement runs. The text scan matched a field name only where
no `.` came before it, so a dotted parameter path was never found, and a
bare one was not typed.
- A reflective copy OUT of the type. `BeanUtil.copyProperties(item,
ItemView.class)` reads every property of `item` by name. The copy into a
type was already a producer (`reflects on T.class`); the value handed
out was not a use.
- A key bound to the field. A field of a @ConfigurationProperties class is
defined by its key's settings line, which only the key form of the
question (`impact app.signingKey`) listed.
The change, all in impact:
- mapper_params types each parameter marker of the statements that a
field's name appears in: the statement's namespace and id give the
mapper method (ax_nonsource.mapper_methods, now shared with changed), and
its parameters type the path's root. The root can be a @PARAM name, the
one unnamed parameter, a <foreach item> over a collection parameter, or
the statement's parameterType. A segment before the last is a field of
the type so far. A root that names nothing, or a simple type name
declared twice, gives no row. The row is the mapper method, at the
marker's line in the XML, [resolved].
- bean_copies types each bare-name argument of a reflective copier
(copyProperties, copyToList, toBean, fillBean, beanToMap, convertValue,
copyBean) by its declaration in the calling method, or by a field of the
caller's type. The row is the caller, [by name].
- Both are per-query facts (mapper_param, bean_copy) that dl/impact.dl
joins as direct uses, so the closure and the tests start from them. The
SQL port takes the same rows. They are part of the solve cache key, so no
IMPACT_VERSION bump is needed.
- A field target's bound keys (ext_config_binding) add their settings lines
to the "bound from outside the source" rows, as a config target's do.
Test: tests/cases/java/field-read-by-name-outside-the-source. The near
miss is a same-named field on another type, with its own mapper statement
and copy. The control is the key form of the question. 4 of its 5 checks
fail on the release branch tip, and all 5 pass with the change, with the
rules and with the SQL port.
Smoke, on a multi-module shop project:
- `impact` on a product entity's stock field went from 1 to 3 readers. The
new rows are its mapper statement's `#{...}` line and the controller
that copies the entity to a DTO.
- `impact` on a @ConfigurationProperties field now lists its settings
line (0 before, 1 after).
- Over all 1254 fields: 74 mapper-parameter rows on 63 fields, 186
bean-copy rows on 128 fields, and 17 bound-key rows.
On a smaller web app: 52 mapper-parameter rows on 28 fields, and no
copies or bound keys. Nine rows sampled across both were checked by hand;
each marker is typed to the right parameter and field.
Not yet measured on the full corpus or on held-out projects; the smoke
numbers above are the only corpus numbers.
…oad it A servlet filter has no caller in the source. The container calls doFilter or doFilterInternal on every request, and a MockMvc test sends its requests through the same chain. So a body edit to a filter's token parsing selected no test. `path <web test> <filter>.doFilterInternal` said the two were independent. Yet the filter is added with `http.addFilterBefore(tokenFilter(), ...)` in a security configuration that every @WebMvcTest of the application @imports, and those tests run it on each request. The change: ax_registration.filter_links. It is kept narrow, and each link needs three things. - The filter. A client type whose ancestors include a servlet or Spring filter base (javax/jakarta Filter, OncePerRequestFilter, GenericFilterBean, the authentication filters). Its entry methods are doFilter, doFilterInternal, shouldNotFilter and attemptAuthentication. - The context holding it: - a filter instance handed to HttpSecurity addFilter / addFilterBefore / addFilterAfter / addFilterAt. It can be a @bean factory's return, a `new`, or a field of the filter's type, written inside that call. It is held by a test that loads the configuration declaring the call: @import, @ContextConfiguration, @SpringJUnitConfig, @SpringBootTest(classes = ...), or a @SpringBootTest with no classes. - a filter that is itself a @component. It is held by @SpringBootTest, by a @WebMvcTest slice and by an import. - A @WebMvcTest alone is not credited with a configuration's filter. - The test methods that send a request. They write a path-shaped literal or call a request method (MockMvc perform, a test client's exchange or getForEntity). A test method of the same class that sends nothing is not credited. impact.dl walks it as fw_edge "filter" (rung registered), and the filter method's own answer lists those tests as framework-mediated dependents. The export writes it as filter_run, so IMPACT_VERSION is 61. The SQL fast path declines on a graph that has a link, as it does for key edges. path adds the same hops as [framework] and verifies them by running the join again. Test: tests/cases/java/servlet-filter-runs-for-the-tests-that-load-it. The near misses are a @WebMvcTest without the import, and a test method that sends no request. The controls are a component filter, held by both slices, and a plain unit test. 4 of its 5 checks fail on the release branch tip, and all 5 pass with the change. Smoke, a small Spring Boot web app whose 8 @WebMvcTest classes import its security configuration: after a body edit to the filter's token parser, test-impact went from no test to 35 tests in those 8 files. Every @test method of those classes is selected. None of the other 96 test-tree methods is selected, and none of them sends a request. `path` from one of those test classes to the filter went from "independent" to one verified [framework] hop. A multi-module project with two filters and no tests gets no link. Not yet measured on the full corpus or on held-out projects; the smoke numbers above are the only corpus numbers.
…aration
`export const TOPICS = { orderEvents: '…' } as const` names topics, routes,
event types and DI tokens, and `TOPICS.orderEvents` is how every user reads
one. The keys were declared nowhere: `impact TOPICS.orderEvents` answered
"nothing named", and the readers of one key could not be told from another's.
- parser: an unannotated module-level `const` whose value is an object
literal (through `as const`, `satisfies`, parentheses, `Object.freeze`)
emits each data key as an OBJECT_LITERAL_PROPERTY field owned by the
variable; a nested literal's keys are owned by the key that holds it.
Function-valued keys stay methods.
- field_access.dl: `X.a` resolves to that field when X is the variable, an
import of it, a namespace import's export of it, or a key of an outer
table, and only when the typed lookup found nothing (`satisfies T` keeps
T's member). A read inside a method's decorator is that method's.
- index: a field whose owner is no type is displayed after the module
(`ROUTES.admin.users`).
- impact.dl: for a module-owned key, a line declaring another field of the
same name is not a read (two route tables in one file with the same key).
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
`TOKENS.Relay` (a key of a module-level const table) also matched class Relay by dropping the table's name, and impact answered 'more than one kind'. A field whose display is the spelling now wins over a type found only by dropping the leading segment, as a method already did. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
`constructor(@Inject(TOKENS.Store) store)` binds the constructor to the token, but the read was credited to the module that evaluates the decorator, so `impact TOKENS.Store` named the file instead of the class. A parameter decorator's owner is the parameter; its method is the reader, as for a method's own decorator. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
`constructor(topic = TOPICS.payments)` evaluates the default on every call that omits it, but the read was placed in the module initializer, so the constructor was missing from the key's readers. A parameter's default expression is now its method's, unless a function written as the default already owns the read. Reads in a decorator no longer also add a module row. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…the compiler names it
The fields scorer labelled a key of a module-level `const X = { a: … }` as
`X#a` (its owner is the variable, which is no type). The compiler side names
the nearest enclosing named declaration and the module otherwise, so every
correct read scored as one wrong plus one missing. Label it by its module.
- 78-cross-process-destinations: fields 0/1 -> 1/1 correct, 0 wrong
- 80-object-literal-member-receivers: fields 0/9 -> 3/9 correct, 0 wrong
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…eclaration landed The index declared data keys of TypeScript const literals too, so after merging, an annotated const's keys were declared a second time beside the type's member. The parser now owns TypeScript's keys; the index keeps them for JavaScript. - index: no TypeScript consts predicate (the parser declares those keys) - parser: a const annotated with a type that names no member (Record<K, V>, through Readonly/Partial/Required, or index signatures only) declares its literal's keys, as an unannotated one does - impact.dl: keep both the key-declaration-line and other-table-line rules - suite: fixture 86's const-table reads now resolve (fields recall 0.50 -> 0.92) Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
… 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 result (#1892) A site is file:line:col (the callee's name); two calls of one name on a line are never chosen between. link --not rejects a by-name or one-of-a-set lead at a site (never an edge the engine resolved); the walks skip it, nothing is deleted. AXIOMCODE_LINKS_PREFER=1 skips a linked site's own guesses. Unknown sites carry ranked candidates from what the graph knows (the engine's set, values passed in, a computed name's prefix, values registered in the file, the name called). A link whose target has a declared, JSDoc or inferred return type resolves the calls chained on its result, on a local assigned from it, awaited, or on each element it yields. Front-door answers list confirmed places before leads. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…cts a lead; candidates ranked by the name called (#1892) A decorator factory's call and the decoration applying its result are one call at one column. Stress harness scenarios S1-S13 pass in all five languages where the subject can exhibit them. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…oads past an override Four call shapes a C# runtime trace showed the graph missing: - A property, indexer or event read through an interface, abstract or virtual property bound only to the declaration. Accessors are now looked up per runtime type (nearest along the class chain, parameter count separating indexers), the property's virtual/abstract/override modifier makes its accessors dispatchable, and the bodiless declaration keeps its reader as a bodiless method does. - An explicit implementation of a generic interface (`IOpt<T, P>.Dep`) carries the interface's type arguments in its written name and was never paired with the member; the name is now compared up to its `<`, and an explicit property's accessors pair with the interface's accessors. - `using` runs Dispose, `foreach` runs GetEnumerator and a collection initializer runs Add per element; none has an invocation in the IR, so each gets a synthesised edge (using_dispose, foreach_enumerator, collection_add) to the member lookup finds on the static type in the project. - Member lookup stopped at an override and hid the base type's other overloads; it now continues past a type whose only declarations of the name are overrides, a same-signature declaration still hiding. Cases: an-accessor-dispatches-like-a-method, a-statement-runs-the-method-it-implies, an-override-keeps-the-base-overloads (red on the base, each with controls). C# case suite 265/265, C# engine suite green. Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…o fix/js-impact-f1 # Conflicts: # plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact
# Conflicts: # plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact
# Conflicts: # plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact # plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path
# Conflicts: # plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact
…operator arguments in overload choice - impact: a type's static initializer is reached from what initializes the type (JLS 12.4.1: new, a static method call, a static field use); an instance initializer from the type's constructors. No `defines` hop out of an initializer: a lambda or anonymous class written in it is not run by it. - engine: a pinned local of an unstaged platform type takes its declared type; a static call on an unstaged type name is a library boundary rather than an unresolved site. - overload resolution: a numeric/boolean operator expression argument rules out reference-typed overloads. 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>
fix(impact): Python transitive reach — two over-reach sources, Optional class-object params
javascript: a test that never loads the change is not selected; a mocha load-time throw selects the whole run
Agent-asserted call edges: list the sites an answer stops at, link them, walk them as [asserted] (#1892)
TypeScript: multi-line test registrars, runner set-up files, Object.assign function objects, overload implementations (stacked on #1882)
…on initializer's lambda
delegates.dl followed a function stored in a field or property and named two
shapes it did not handle: a function that reaches a member from a parameter
(`_fn = fn`, a primary constructor's `fn` read in a field initializer) and a
parameter of delegate type called directly (`act(1)`, `handler.Invoke(x)`,
a parameter captured by a lambda and called there). Both are how C# hands
behaviour to a library, and in both the function that runs is written at a
call site no member lookup sees.
resolution/delegate-params.dl gives each such parameter the member's
envelope: what is passed at its ordinal to a call resolved to its method (a
constructor too; a parameter or a function-holding member passed on is
followed), stored members gain what their parameters hold, and a call
through the parameter reaches one generated node per parameter whose
dispatch candidates (basis `value`) are those functions. The resolved site
target is untouched.
A lambda element of a collection initializer (`new Rules { v => ... }`) now
takes the parameter type of the Add it runs, as an argument lambda takes its
callee's, so calls on `v` resolve.
Case: a-function-handed-to-a-parameter-runs-there (red on the base; control:
a parameter that is never called runs nothing). The engine suite's delegate
envelope test now expects the parameter node it used to list as unhandled.
C# case suite 273/273, C# engine suite green.
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
TypeScript test selection: leave out tests that never load the change, type tests, package-imported names (stacked on #1888)
…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
swapnilpaliwal-sd
requested review from
JaredHLZhang,
Whua689 and
suyashpaliwal26
as code owners
October 10, 2026 20:27
This was referenced Oct 10, 2026
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.
Summary
Test-selection recall rises in every language (held-out repositories, never used while tuning, in brackets):
Precision and call-mapping accuracy rise without giving recall back:
Agents can now fill in the calls the graph could not resolve:
axiomcode link(#1895).Python parse stage 2.6–3.2x faster on large projects (#1853).
New
axiomcode link <file:line> <target>records where a call lands; impact, path and tests walk it, labelled[asserted]--notrejects a wrongby nameorone of a setlead--library autostages the project's dependencies in all five languages:Improvements
params=and@parametrizevaluesrepr/len/strreach the operand's dunder; property setters and deleters are callspkg.mod.Base, through a star re-export or an alias, are recognisedgetattr(self, f"visit_{…}")dispatch,python -m pkgspawns,with … as, dict.items()loops, Optional/union locals and default-valued parameters are typedwrapper(impl)results are followedrequire('..')) and computed imports are read; a mocha load-time throw selects the whole run (javascript: a test that never loads the change is not selected; a mocha load-time throw selects the whole run #1894)JSON.parse,Promise.resolve) are no longer by-name callersit(/test.each(, vitest/jest set-up files,Object.assignfunction objects and overload implementations (TypeScript: multi-line test registrars, runner set-up files, Object.assign function objects, overload implementations (stacked on #1882) #1888)import.meta.glob, tsconfig paths,#imports and workspace packages; vitest type tests are tests (TypeScript test selection: leave out tests that never load the change, type tests, package-imported names (stacked on #1888) #1893)equals/hashCode/toStringand library overrides are reached through constructorsnew, a static call, a static field use), and does not run the lambdas it defines (Java reach: narrower initializer hop, platform boundaries, operator overloads #1898, closes Java: transitive reach over-reported through type initializers, unstaged platform receivers and operator-argument overloads #1902)base(), static members through the type name, generic receivers, and extension methods on types outside the project?.chains andforeachover a project iterator resolve (fix(csharp): reach loop — accessor dispatch, implicit calls, delegate parameters #1896, closes C#: property and indexer accesses with no call edge (interface/virtual accessors, object initializers, ?. chains, foreach over an iterator) #1899)using→Dispose,foreach→GetEnumerator, collection initializer →Add) and a function handed to a parameter have edges (fix(csharp): reach loop — accessor dispatch, implicit calls, delegate parameters #1896, closes C#: compiler-inserted calls (using, foreach, collection initializer) and functions handed to a parameter have no edge #1900)Bugs
if __name__ == "__main__":was taken as run on importx.testing) resolved into the projectPerformance
linkProjectlookups are maps (perf(python): one-pass mirror of the parsed tree; map lookups in linkProject #1853)Tracking: #1904