Skip to content

v0.2.3

Choose a tag to compare

@github-actions github-actions released this 15 Aug 12:27
· 65 commits to main since this release

Changed

  • One route registration mints one Route node. @app.post('/x') used to
    satisfy both the flask method-shortcut detector and the fastapi holder
    detector, and framework is part of the Route id — so every such registration
    produced twin Route nodes. Framework is now claimed by per-file import
    evidence (files importing fastapi give it the app holder; .route
    stays flask; no-evidence @app.<verb> defaults to flask). On a real FastAPI
    repo every prior graph carried doubled routes.
  • codingest build fails loudly on an empty result. A build whose graph
    contains no File and no Doc node now exits non-zero and writes NO
    artifact — previously it exited 0 and wrote a .kgl, the silence that once
    masked a walk-root bug. And a build rooted at a dot-prefixed directory
    (.hidden/) no longer derives module ids with an empty leading segment.
  • Java line comments and Go interface methods are extracted again. Two
    match arms had gone silently dead under grammar renames (comment
    line_comment/block_comment in tree-sitter-java 0.23; method_spec
    method_elem in tree-sitter-go 0.25) — found by the new grammar-drift
    guard's first run. Java doc-comment gating and Go interface-method
    extraction resume on every Java/Go repo.
  • Two new languages: Julia and R (seventeen total). Julia: functions in
    every definition form incl. multiple dispatch, structs with EXTENDS, nested
    modules, include("path.jl") file edges, using/import deliberately
    edge-free (namespace-shaped). R: both assignment shapes plus lambdas,
    conservative S4, source("path.R") file edges with .R/.r both
    registered, library()/require() deliberately edge-free. Each ships with
    a corpus, an additive golden, grammar-guard coverage, and collision-bait
    tests proving the namespace mechanisms abstain.
  • Real-repo acceptance hardening across all languages. A five-agent sweep
    over real repositories (then a four-agent sweep for the long tail) produced
    three same-day fixes: Rust bare use paths resolve under the crate root and
    never reach the language-blind fallback (killing a false edge into a
    same-named Python package stub, and resolving pub use re-exports);
    multi-line route decorators — the dominant FastAPI style — no longer
    silently produce zero Route nodes; and the generic import fallback now
    claims File targets only for languages whose module coordinates name exactly
    one file (python/agc/dart) — namespace languages abstain, eliminating
    measured wrong-edge families (Java 438/438 false, PHP 146 src→tests
    inversions, C# 118 arbitrary picks).
  • File→File import edges exist for Rust, Python, C/C++ and Dart. A
    five-defect family (independently reported by mcp-servers, 2026-08-14,
    upstream lead natashahirt/kglite PR #4) left the file-level dependency graph
    near-empty outside JS/TS: import strings were written in coordinate systems
    the resolver never converted from. Now: Rust crate::/super::/self::
    paths rewrite into the module coordinates files are stamped with (a 41-file
    scan that produced 0 File→File edges and 49 edges to one Module "crate"
    now resolves per-file); use foo as bar and use a::{b, c} are extracted;
    Python relative imports resolve against the importing file's package,
    import a, b/aliased/single-name-from origins all survive, and imports
    under if TYPE_CHECKING:/try:/function bodies are seen; Dart package:
    URIs keep their directory structure (a/x.dart and b/x.dart no longer
    collide) and relative URIs resolve file-relative; C/C++ angle includes are
    structurally excluded from file edges (an angle include naming a real
    project file no longer manufactures one — quoted-include resolution was
    already correct since 0.2.2). CALLS edges over these routes gain
    import_backed=true. Six goldens moved deliberately (four new import
    corpora + regenerations), each with its reason recorded per commit; a
    Python-ast oracle (machinery sharing nothing with the parsers) verifies
    the Python edge set at 7/7 recall.
  • Engine floor moves to kglite 0.16.1. Two things reach us. (1) The wire
    break: kglite_value_to_json now emits real JSON for nine Value variants
    that previously leaked Rust Debug syntax — codingest query --format json
    returning a node/relationship/path/temporal now prints a structured object
    ({"id":…,"labels":[…],"properties":{…}}) instead of a quoted Debug string.
    Verified live against a built graph; anything parsing the old strings must
    move. (2) The docs-pass column_value copy only converts List/Map of
    scalars, and every parity corpus proves the nine variants unreachable there —
    goldens are byte-identical across the bump. Also in 0.16.1: all four
    NodeData-sentinel documentation asks codingest filed on 2026-08-14 shipped
    (rustdoc corrected, get_node contracted as topology-only, [0.16.0]
    changelog amended, fields sealed pub(crate)), so the footgun class this
    migration fixed is now unrepresentable from outside the engine.
  • Engine floor moves to kglite 0.16.0, whose .kgl container v6 is a one-way
    format break: files codingest now writes cannot be read by kglite 0.15.14 or
    earlier
    (an old reader refuses by version number with FileFormatError
    rather than misreading). The Python requirement widens to
    kglite>=0.16.0,<0.17 — the wheel's compiled writer and the installed
    reader must sit on the same side of the break. v6 also shrinks files
    (upstream: 0.93×/0.79×/0.43× on their three size fixtures).
  • The save path uses 0.16.0's kglite::api::io::prepare_kgl_write — the one
    published route for pre-write consolidation, replacing the open-coded
    prepare_save + enable_columnar pair (retired upstream). Also preserves
    copy-on-write lineage across the mutation, which the old spelling did not.

Fixed

  • Multi-name from-imports expand per name. from pkg import sub, helper
    previously recorded one bare-module import (the whole statement landed on
    the package, and a call reached only through the submodule name read
    import_backed=false). Each name now records its own import: submodule
    names resolve to their files, symbol names fall back to the module, and
    import_count counts names — uniform with import a, b.
  • Docs-pass regression under kglite 0.16.0: MENTIONS/DOCUMENTS edges were
    silently lost.
    0.16.0 made every graph columnar from its first node, so
    the docs symbol index — which read node ids/titles via the raw
    DirGraph::get_node route — got Null sentinels, matched nothing, and
    dropped the edges with no error. Reads go through node_view now; every
    frozen parity golden is byte-identical again (verified across all 15
    corpora, goldens NOT regenerated).