Skip to content

Apps/integration 0.1.9 - #1890

Merged
swapnilpaliwal-sd merged 193 commits into
0.1.9from
apps/integration-0.1.9
Oct 10, 2026
Merged

swapnilpaliwal-sd merged 193 commits into
0.1.9from
apps/integration-0.1.9

Conversation

@swapnilpaliwal-sd

Copy link
Copy Markdown
Contributor

Summary

  • Test-selection recall rises in every language (held-out repositories, never used while tuning, in brackets):
    • Python 0.540 → 0.851 (0.47 → 0.83)
    • Java 0.930 → 0.982 (0.95 → 0.99)
    • TypeScript 0.74 → 0.84
    • C# 0.462 → 0.624 (0.57 → 0.60)
    • JavaScript 0.441 → 0.553 (0.73 → 0.75)
  • Python parse stage 2.6–3.2x faster on large projects (perf(python): one-pass mirror of the parsed tree; map lookups in linkProject #1853)

Improvements

  • Libraries (--library cannot stage a project's installed dependencies and does not follow dependency changes #1889, Skill does not explain --library: what a root is, comma-separated entries, what staging buys #1887)
    • --library auto stages the project's dependencies in all five languages:
      • Python packages from the virtual environment
      • JavaScript / TypeScript packages from node_modules
      • Java dependencies from their sources jar, or the class jar decompiled
      • C# NuGet packages, decompiled
    • Each library is compiled once into a cache and reused; unused ones are pruned after 30 days
    • With libraries on, a dependency change (manifest or lockfile edit, pip install, npm install, dotnet restore, a Maven fetch) rebuilds the graph
    • The skill explains when and how to enable libraries, and how to turn them off
  • Python
    • A library calling back into project code is followed, from summaries of the installed library
    • Test parameters are typed by their pytest fixture, fixture params= and @parametrize values
    • Operators, truth tests and repr/len/str reach the operand's dunder; property setters and deleters are calls
    • Library base classes written as pkg.mod.Base, through a star re-export or an alias, are recognised
    • getattr(self, f"visit_{…}") dispatch, python -m pkg spawns, with … as, dict .items() loops, Optional/union locals and default-valued parameters are typed
    • The dispatch cap is off by default, so calls with many candidate targets are no longer dropped
  • test-impact: src-layout packages are imported by package name; a test file imports the conftest.py files above it
  • context: a task whose title names no code takes its scope from the body
  • JavaScript: imports resolve past a hand-written .d.ts; callbacks through test-hot functions and wrapper(impl) results are followed
  • TypeScript
  • Java: type initializers count as run by users of the type; equals/hashCode/toString and library overrides are reached through constructors
  • C#: namespace-relative names, using resources, implicit base(), static members through the type name, generic receivers, and extension methods on types outside the project

Bugs

  • Python: an import of a module with a .pyi beside it resolved to the stub, so tests reached nothing in the package
  • Python: a call under if __name__ == "__main__": was taken as run on import
  • Python: an import whose last segment matched a project module (x.testing) resolved into the project
  • Java: a field initializer written after a comment was dropped, with any anonymous class it created
  • C#: path refused every .cs file as an endpoint
  • TypeScript: path did not find a library method by its member name

Performance

swapnilpaliwal-sd and others added 30 commits September 30, 2026 11:25
…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>
…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>
…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>
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
swapnilpaliwal-sd and others added 26 commits October 9, 2026 15:58
…rgument does

`def getter(val, field_obj=field_obj): return field_obj.deserialize(val)` -- the closure
idiom that pins a loop variable -- is called with one argument, so field_obj only ever
holds its default, and no call site passes it: the parameter was untyped and the call on
it unresolved. The default is a value the def statement writes once (the parser links it,
param_default_expr); value-flow.dl now lets it reach the parameter exactly as a call-site
argument does -- an instance types it, a class object makes it that class, a function
makes it callable as that function -- alongside whatever callers pass. A parameter
defaulted to a name from an enclosing scope appears in fifteen of sixteen public
repositories (sentinels and constants included, which type nothing callable).

Mutation oracle, sixteen repositories: one tuning repository +13 failing test files
selected (16 added files do not fail), none lost, every other repository unchanged. Case
parameter-default-types-it fails 2 of 3 on the base; control: an argument passed at a call
site still reaches the parameter.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…o it only where the module sits under the dropped segments

findModule dropped leading segments of an import it could not match exactly and then matched what was left
exactly or by suffix. `from clikit.testing import CliRunner` dropped `clikit` and found the project's own
`testing` package (or `app.testing` by suffix); `from fw.db import models` found the project's
`models.py`. A dependency's module whose last segments collide with one of the project's resolved INTO the
project, the import bound nothing, and every call through it was unresolved instead of a named boundary.

The drop exists for an import more qualified than the module (`import myproject.framework` naming a
`framework` in a `myproject/` directory with no __init__.py). The analyzer now records the directories above
each module's top package, and a dropped prefix must be what the module actually sits under.

Python engine goldens: 33-url-view-forms, 37-model-signals and 38-app-wiring move sites from
ambiguous_unknown to boundary_lib (`external:path`, `external:models.CharField`, `external:call_command`);
edges, framework edges and the torture harness are otherwise unchanged.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
… hands back to the objects the client gives it

The engine reads a dependency's signatures, never its bodies, so a hop the LIBRARY makes back into client code
was invisible: a test client's get() runs the open() a client subclass overrides and then calls the application
it was built around; a CLI runner's invoke(cli) runs cli.main(), which runs the command's callback; a decorator
wraps a def into a library object that later calls it; ExitStack.enter_context(cm) runs cm.__enter__. On a
16-repository Python oracle a library frame was the first broken hop behind most test-impact misses of the
web-framework subject, and every one of them stopped at the library.

graph/python/libsum/libsum.py derives the hand-backs from the library's SOURCE (the project's own environment,
its stdlib through pyvenv.cfg, or AXIOMCODE_PY_SITE): a flow-insensitive pass per function records which
parameter-rooted value meets which call or protocol syntax, composed to a fixpoint across the library's own
calls (self-calls, typed parameters and fields, constructors, closures, decorator factories). It writes, for
the library classes and functions the client can name, five tables beside the client IR: the hand-backs
(callee, root, position, path, member, via, declared type), constructor stores, re-exports, what a decorator
turns a def into, and class ancestors. Cached by the installed distributions and the client's imports, so a
refresh that adds no import reuses them. Staged through a new client-extra.map (facts beside the IR that are
not parser schema); absent = empty = no change.

framework-behavior/library-callbacks.dl joins them to the client: a member a client type inherits from its
library base, a super() past the client classes, a library function or class the client imported, a member of
a library object the client built (followed through locals, helpers' returns and fixtures) or one a library
decorator made of a def. Each hand-back resolves to the client member of the object that arrives -- the
receiver, an argument, a field the library constructor filled, a field the client set -- and only when none
answers, to the client subclasses of the type the library declares there. It ADDS lib_callback_edge
(caller, target, callee, member, via, how) and lib_callback_site, and leaves call_chain_edge alone. No library
or framework is named in a rule.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
… hop `library callback`

impact reads the Python engine's lib_callback_edge as fw_edge "library callback": a test that drives a library
now reaches the client member the library hands back to, with the rung `library callback` (ranked with
`registered`: a library's behaviour joined by a member name, never a resolved call). lib_callback_site marks a
call site the engine knows enters a library callable as a library receiver, so it is never a by-name seed: a
test client's `client.put()` no longer reaches the project's own `put` by name.

tests/cases/python/library-calls-back: a fake site-packages with a test client, a CLI runner and command
decorator, a template environment whose loader arrives through **options and a function calling a member on its
argument; each positive check fails on the base engine. Controls: the same member name on a class never handed
to a library, an object handed to a library function that never calls that member, a same-named member on a
class that is not a subclass of the declared library type.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…ependent impact names

path adds lib_callback_edge to the hops no call site expresses, worded `library_callback via <callee> -> <member>`
and verified against the engine's table, so a test reaches the application its test client calls; impact lists
the client method that calls the library as a [framework] dependent of the member handed back
("a library it calls hands this back (<callee> calls <member>)"), which is what path's note points at.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
# Conflicts:
#	graph/python/souffle/decls_all.dl
#	parser/src/parsers/python/extractors/python-resolution-linker.ts
#	parser/src/workflows/python/python-project-analyzer.ts
#	plugins/axiomcode/skills/axiomcode/scripts/axiomcode-impact
… the f-string golden

A Python call site with more candidate targets than the cap was refused outright, so every test
reached only through it was dropped from a selection. For test selection a missed test costs more
than an extra one, so Python solves uncapped unless --dispatch-cap is given; every other language
keeps 20. The protocol-fan check tests the cap mechanism itself and now pins it explicitly.

The parser's Python golden records an f-string's leading text (literalValue), as the getattr
dispatch change made it do; only that column moved, on 14 rows.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
`a == b`, `a | b`, `x in c`, `-a`, `if x:`, `not x`, `x or y` compile to no call, so the
client __eq__, __or__, __contains__, __bool__ or __len__ they run had no caller: impact listed
nothing that compares, composes or truth-tests the object, and a test doing exactly that was
not selected. Two new protocol edges on the existing channel, each its own kind:

  OPERATOR_PROTOCOL  the left operand's slot and the right operand's reflected one (a
                     comparison's mirror, `a < b` -> b.__gt__), `!=` falling back to __eq__,
                     `in` running the right operand's __contains__ (or __iter__), and the
                     unary -, +, ~. A chained comparison matches no catalogue row and emits
                     nothing.
  TRUTH_PROTOCOL     if / while / assert conditions, a conditional or comprehension
                     condition, `not x`, and the operands of `and`/`or` -- the right one only
                     when the whole expression is tested (`return a or b` hands b back
                     untested). __bool__, or __len__ when the class has none.

Operators and dunders are catalogued in builtins.dl (the data model's tables).

Mutation oracle, sixteen repositories: +5 failing test files selected (one tuning, four
held-out), 9 extra, none lost; empty answers 96 -> 92; impact's one-hop callers src recall
0.707 -> 0.714 (tuning 0.726 -> 0.736); a failing test's path to the change found 0.528 ->
0.541. Edges +0.8%, index time flat. Case operator-runs-the-dunder fails 6 of 8 on the base;
controls: a class with its own __bool__ is never tested through __len__, and the untested
right operand of `or` reaches nothing.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…xport or a generic alias is that class

A client class whose base is a library class was recognised only when the base was a bare
name or a subscript. Three spellings of the same base left it a plain unresolved class, so the
library's own methods never called back the overrides it defines:

  * a DOTTED base, `class Command(clikit.core.Command)` / `class Store(abc.Mapping)`: the
    base list's DOTTED_NAME slot is read like NAME (138 such classes across the sixteen
    repositories, every one of them);
  * a name a library re-exports with `from M import *` (`collections.abc.MutableMapping` is
    `_collections_abc.MutableMapping`): libsum now loads every module first and expands star
    imports (M's __all__ when it declares one, else its public names) before analysing any
    body, so the alias table has the row;
  * a module-level generic alias built around a class, `Mapping = _alias(collections.abc.
    Mapping, 2)`: followed only when the first argument resolves to a library CLASS, so a
    `partial(f, x)` wrapper around a function is not taken for f.

Mutation oracle, sixteen repositories: tests recall 0.786 -> 0.851 (tuning 0.884 flat, +1
file; held-out 0.713 -> 0.826, +536 files on a CLI subject whose commands subclass the
library's by dotted name), precision 0.431 -> 0.417, empty answers 92 -> 83; a failing
test's path to the change found 0.541 -> 0.559. Two tuning files lost to a by-name match
the new library site suppressed are restored by the next commit. Case library-star-reexport
fails 4 of 5 on the base; control: a library base whose method hands nothing back never
reaches the client's __getitem__.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…s a hand-back from it is summarised

A call the engine knows enters a summarised library callable (ext_lib_callback_site) was made a
library receiver outright, which drops its by-name callers. Where the summary does say what the
library hands back from that call (a lib_callback_edge from the same caller through the same
callable), that is right: the hand-back is the answer and a project method merely named like
the call is not. Where it says nothing -- the library reaches the project through a method's
return, a registry, anything the summary cannot follow -- knowing the call enters a library is
no evidence that nothing in the project runs behind it, and the name match it had before the
library was read is kept.

Found when naming more library bases (previous commit) turned a test client's
`super().__init__(...)` into such a site and two failing test files lost the only route the
graph had to them. Mutation oracle, sixteen repositories: both restored, +17 extra files, 0
lost; empty answers 83 -> 80. IMPACT_VERSION 69 and path EXPORT_VERSION 5, since the staged
facts change. Case library-site-without-summary: the base fails the name-match check; control:
a call whose hand-back is summarised still reaches no project method merely named like it.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
… from the body

A scope-less context call ranks directories by where the HEADLINE's words land, and refuses
with a menu when they land nowhere. A report titled in prose ("Release 8.4.2", "Disable when
developing?", "Make unimported utilities private") lands nowhere by its headline while its body
names the code outright (`@retry(wait=wait_fixed(1))`, `LazyFile`, `make_short_help`), and the
refusal answered NOTHING. The whole report's words now rank the directories when the headline's
have no evidence; the pick stays an offered scope (it neither filters nor weights), and a report
whose words land nowhere at all still refuses.

Issue-to-fix oracle (92 tasks, sixteen repositories): empty answers 6 -> 0 (three repositories),
recall@5 0.846 -> 0.891, recall@10 0.881 -> 0.933, MRR 0.703 -> 0.744; tuning 0.799 -> 0.837
recall@5, held-out 0.894 -> 0.946. No task lost a gold file. Case context-body-names-the-code:
the base refuses ("--in <path> is required"); control: a headline that lands still chooses the
place by itself.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
0.1.9: impact and test-selection fixes across Python, JavaScript, TypeScript, Java and C#
Python test selection: library callback summaries, seven recall fixes, no dispatch cap
…ated, and what staging buys

Closes #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…es), made once per dependency

The entry the skill led with was a dependency's source directory, which index re-parses; the reusable
form is the CSV IR `axiomcode parser <source> <ir dir> --library` writes. Lead with that, keep the
source directory as the accepted fallback.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…comma, unresolved vs external

Every claim in the --library section was exercised: two IR entries stage two roots; a space after a
comma is refused as "not a directory"; a relative entry resolves against the repository; a source
directory is parsed under .axiomcode/out/.intermediate/lib/; AXIOMCODE_LIBRARY works the same; a bare
index keeps the library graph. A `~` after a comma is refused (a leading one is the shell's), and
without libraries a dependency call is unresolved or an external boundary, not always unknown.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…orts; a source entry is compiled once

Libraries are opt-in: the graph is built without them unless --library is given. `--library auto`
finds the packages the project's source imports, in its virtual environment or under node_modules,
compiles each once into ~/.cache/axiomcode/libir with `bin/axiomcode parser --library`, and stages the
compiled tables. A named source directory goes through the same cache, so a rebuild the refresher starts
after an edit no longer parses it again (a large dependency was re-parsed on every edit). A library IR
entry passes through unchanged.

The skill says when to do this: for better coverage, compile the dependencies and enable them.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…ases for `--library auto` in JS and TS

TypeScript names a library method module#Member (`index#Greeting.shout`); the library endpoint lookup
matched only a `.`-separated tail, so `path welcome Greeting.shout` said nothing of that name was
declared although the call resolved into the library. Cases cover discovery from node_modules and a
call typed through the package in both languages; each fails without the build change.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…ough their sources jars

auto reads the dependencies pom.xml (a ${property} version resolved) and build.gradle declare, finds
each one's -sources.jar in the Maven repository (.mvn/maven.config's maven.repo.local, else ~/.m2) or
Gradle's module cache, unpacks it once and compiles it like any source library. A dependency with no
sources jar is named, with the command that fetches it.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…by decompiling them

NuGet packages ship assemblies, not source. auto reads the PackageReferences each .csproj declares
(a version Directory.Packages.props sets centrally too), finds the package in the folder NUGET_PACKAGES,
nuget.config's globalPackagesFolder or ~/.nuget/packages names, decompiles its assembly once with
ilspycmd and compiles the C# like any source library. A package never restored is named, and a
missing ilspycmd is reported with the command that installs it; CI installs it for the C# leg.

With this, auto covers all five languages, and the skill says so.

Closes #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
… no sources jar

A dependency with only a class jar was reported and left out. It is now decompiled with Vineflower
(found in the Maven repository, or AXIOMCODE_JAVA_DECOMPILER) once into the cache and compiled like a
source library; with no decompiler the dependency is named with the commands that fetch sources or the
decompiler. CI fetches Vineflower for the Java leg.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…y changes; old compiled libraries are pruned

Only source files were compared, so a dependency added, removed or upgraded without a source edit
(`pip install -U`, `npm install`, `dotnet restore`, a manifest or lockfile edit) left the graph on the
libraries it was built with. The file table of a graph built with --library now also records the
manifests and lockfiles and what is installed (a virtual environment's dist-info names, npm's install
record, .NET's restore output); a difference marks the graph stale and the usual background rebuild
runs, which re-discovers `auto` and compiles only what changed. A graph built without libraries is
unaffected and never gains them by itself.

A compiled library no build has used for 30 days is removed from the cache, with what was unpacked or
decompiled for it; one in use is never removed.

The skill states both, and how to turn libraries off again.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
…brary graph stale

Fetching a missing Java dependency (`mvn dependency:resolve`, a Gradle build) writes only to ~/.m2 or
Gradle's cache, which no file in the project records, so the graph stayed without that library until
the next source or pom edit. The dependency fingerprint now includes which declared dependencies are
present in the Maven repository or Gradle's cache; one appearing marks the graph stale, and the
refresh stages it.

Refs #1887.

Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
Python recall (operators, library bases, context) and --library auto for every language
@swapnilpaliwal-sd
swapnilpaliwal-sd merged commit a963360 into 0.1.9 Oct 10, 2026
12 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.

2 participants