You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix three extraction gaps found by widening the benchmark corpus
All three were invisible to the fixtures, because a fixture only encodes the
forms its author already knew about. Adding public repositories for languages
the corpus had no coverage for surfaced them within minutes.
- Retrofit `@GET(value = "…")`. Kotlin allows any single-argument annotation
to be written with its argument named, and real Android code does. Matching
only the positional form yielded no client routes at all — not wrong routes,
none — so no mobile-to-backend edges existed, silently.
- Axum `.route(p, get(h).layer(mw))`. A non-verb method in the MethodRouter
chain terminated the walk, dropping the route entirely with the verb in
plain sight. Non-verb methods are now transparent decorators. Unchanged and
still deliberate: `.route(p, handler_var)` emits nothing, because there is no
verb to infer and a guessed one could false-match another repo's endpoint.
- TypeScript path aliases. Overlapping prefixes were resolved by map
iteration, taking the first match rather than the longest — wrong by tsconfig
semantics, and different between runs. It was the only reproducibility
failure in the corpus, and it made the gate report edge churn on a tree
nobody had touched. Longest prefix wins, ties broken on the prefix string.
cacheVersion v144 and v145, each with its cachecov entry. Five tests; the alias
test repeats every resolution 50 times so it is a regression test rather than a
coin flip that happened to land.
Not a language model, and not embeddings. enola parses your source with tree-sitter and language-specific extractors, normalizes it into a typed fact model, links it into a directed graph, and runs real graph algorithms over it — Tarjan's SCC for cycles, cycle-safe longest-path for dependency depth, mean+2σ outlier tests for the statistical findings.
121
121
122
-
That means the same commit yields the same answer, every time — measured, not asserted: across 30 open-source repositories indexed three times each, all 30 produced a byte-identical snapshot ID and a byte-identical fact file, over 3.9 million facts with zero parse errors ([BENCHMARKS.md](docs/BENCHMARKS.md)). Every snapshot carries a **receipt**: enola's version, the git ref and whether the tree was dirty, the extractors used, and a snapshot ID that's a `sha256` fingerprint of the facts rather than a random UUID. Before trusting a comparison, enola checks the two snapshots were even built the same way — a different extractor set or changed ignore rules makes a diff meaningless, and it says so instead of reporting churn as if it were your change.
122
+
That means the same commit yields the same answer, every time — measured, not asserted: across 38 open-source repositories indexed three times each, all 38 produced a byte-identical snapshot ID and a byte-identical fact file, over 4.2 million facts with zero parse errors ([BENCHMARKS.md](docs/BENCHMARKS.md)). Every snapshot carries a **receipt**: enola's version, the git ref and whether the tree was dirty, the extractors used, and a snapshot ID that's a `sha256` fingerprint of the facts rather than a random UUID. Before trusting a comparison, enola checks the two snapshots were even built the same way — a different extractor set or changed ignore rules makes a diff meaningless, and it says so instead of reporting churn as if it were your change.
123
123
124
124
Nothing leaves your machine. It's a local binary reading local files.
142: {"TestDecoratorRoutes_NestObjectForm", "TestDecoratorRoutes_NestStringFormAndBareVerb", "TestDecoratorRoutes_Inversify", "TestDecoratorRoutes_RequiresControllerDecorator", "TestDecoratorRoutes_VocabulariesDoNotMix", "TestDecoratorRoutes_DecoratorsDoNotCarryAcrossMembers", "TestDecoratorRoutes_TestFileEmitsNothing", "TestDecoratorRoutes_CommentBetweenDecoratorAndMethod", "TestGolden"}, // TypeScript's first server-side route DSL: @Controller/@controller classes emit one server route per verb-decorated method, both argument forms, gated on the controller decorator and on IsTestPath // a nested type argument (fetch<ApiResponse<Foo>>) no longer defeats client-call detection, and lowercase verb calls (axios.get('/x')) are detected when the argument is a "/"-rooted literal — the condition that keeps map.get('key')/cache.delete(id) out // a directory without __init__.py starts a new source root, so bare-name sibling imports inside it resolve (while a like-named third-party dir whose parent IS a package stays excluded); and a function passed to a decorator as a value is recorded as a reference instead of reading as dead
175
175
143: {"TestServerRoutes_ExpressApp", "TestServerRoutes_UnmountedRouterEmitsNothing", "TestServerRoutes_SameFileMountComposes", "TestServerRoutes_DoNotStealClientCalls", "TestServerRoutes_NoDoubleEmission", "TestServerRoutes_OtherFrameworks", "TestServerRoutes_TestFileEmitsNothing", "TestGolden"}, // call-registered server routes (Express/Fastify/Hono/Koa), separated from v141 client calls by receiver binding; an unmounted sub-router and a bare catch-all emit nothing
139: {"TestLooksGenerated", "TestApplyDecoratorProps_FrameworkRegistered", "TestApplyDecoratorProps_ModalNeedsImportGuard", "TestGolden"}, // facts from files carrying a codegen banner gain generated=true (language-agnostic, matched against the file head), and Python decorator-registered handlers (FastAPI exception_handler/middleware/on_event/websocket, Modal local_entrypoint and — gated on a modal import — function/cls) gain framework_registered=true, so the dead-code detector can drop findings it can never act on
177
179
138: {"TestResolveImports_NestedLookalikeDoesNotCaptureThirdParty", "TestResolveImports_MultiSourceRootSurvivesPackageBoundaryRule", "TestResolveImports_SubpackageNotReachableByBareName", "TestBuildSuffixIndex_NoPackageDirsStaysPermissive", "TestResolveCallTargets_NestedLookalikeThirdPartyDropped", "TestResolveCallTargets_ClassQualifiedChainResolves", "TestResolveCallTargets_ClassQualifiedUnconfirmedStaysDotted", "TestResolveCallTargets_ClassQualifiedThroughReexport", "TestResolveCallTargets_SingleSegmentNeedsNoConfirmation", "TestGolden"}, // Python: (a) a directory is only a top-level package if its parent is not one, so an internal dir sharing a third-party name no longer captures its imports; (b) call-target resolution walks the module/symbol split leftwards with an exact module lookup, so a class-qualified chain binds to module.Class.method instead of being silently rewritten to module.method — multi-segment symbols must be confirmed against real symbol names // Python: a call target imported through a package __init__.py re-export resolves to the module that defines the symbol instead of dangling as a dotted string that matches no node; exact module resolution still wins and an ambiguous re-export stays dotted rather than binding arbitrarily // Python implements plugin.TestRefExtractor (which now also receives the production file list, needed to resolve dotted absolute-import targets); a symbol exercised only by a pytest file stops reading as dead, while the pass emits ONLY KindTestRef facts so a fixture's include_router cannot re-enter the production route graph // "**/testdata/**" joins the default ignore globs, and the two extractors that walk the repo themselves — OpenAPI (Extract) and gRPC (Detect) — repeat it in skipDir, which the globs cannot reach; Go fixture repos are miniature codebases whose routes and client call sites were being attributed to the host repo's service, manufacturing a cross-repo coverage gap
0 commit comments