name: cross-language-impact-coverage-2026-06-04 date: 2026-06-05 14:57 project: codegraph branch: feat/cross-language-impact-coverage
routes![]/catchers![] macro extractor (only the crate-root lib.rs remains). Six engine improvements en route (3 Rust: self-relative + multi-segment a::b::c() module calls + Rocket route-macro extraction; 1 Swift: Fluent @Siblings(through: Pivot.self) metatype refs; 1 SvelteKit: +page.server.js load→+page.svelte synthesizer; 1 Nuxt: nested auto-imported <MediaCard>→media/Card.vue resolution). The static-member-pass-for-TS/JS/Python lever was measured & rejected (e7b86df — 0 coverage gain, the import edge already covers it, + graph noise). Then the 4 niche README languages were knocked out: Lua 31.6%→84.2% + Luau 12.5%→92.2% (new require resolver, 4155609); Liquid 39.1%→73.8% (Shopify OS 2.0 JSON-template section parsing, 2f57119); Pascal 73%→75.7% (.dfm/.fmx form↔code-behind pairing, 2f30a3b) — so ALL 22 README "Full support" languages + all 14 README frameworks now have coverage validation (full README parity). Branch 41 commits ahead of main, 3 behind, not merged.Current state: Branch feat/cross-language-impact-coverage — now 41 commits ahead of main, 3 behind (behind = 3 README-waitlist doc commits on main), tip 2f30a3b, all pushed to origin=colbymchenry/codegraph. NOT merged (review branch). FULL README PARITY: all 22 "Full support" languages + all 14 frameworks now have coverage validation. Two arcs are done: (1) per-language cross-file coverage for ALL 15 README "Full support" langs + the static-member pass; (2) cross-language RN/Expo at 95%+ FAIR (gate hole fixed 082353e; same-dir include + KMP import 529d822). Since the 2026-06-04 save a 12-commit ROUTE-FRAMEWORK front landed (61a993a→a3f59fb) — see the "Route-framework headroom map" below; that map is the live edge. Working tree: clean except one unrelated untracked file (assets/generate-waitlist.py, README-waitlist tooling, not this campaign). Full suite green (1187 passed | 2 skipped, 59 files).
Immediate next step: THE README SWEEP IS COMPLETE — all 22 "Full support" languages + all 14 frameworks have coverage validation. Per-language DONE, RN/Expo DONE, route-framework + component-node front DONE, the 4 niche langs (Lua/Luau/Liquid/Pascal) DONE; 10 engine improvements shipped this run (3 Rust + 1 Swift + 1 SvelteKit + 1 Nuxt + 1 Lua/Luau require resolver + 1 Liquid Shopify-JSON + 1 Delphi form pairing; the static-member-for-TS/JS/Python lever was measured & rejected). Recommended: (A) ship it — open the PR to main for the 41 commits; everything actionable is done. Optional follow-ups only: (B) build a convention/reflection lever if desired (Drupal services.yml DI, ASP.NET/Spring markup/reflection modeling) — each a large per-framework feature. The convention/reflection frameworks (ASP.NET 83.9%, Spring 83.3%, Drupal 78.9%, Django 74.1%, actix 65.4%) sit at a genuine sub-95% static-analysis ceiling — don't chase 95% there without large reflection/markup modeling (metric-gaming otherwise). The TS/JS/Python static-member pass is measured-&-rejected (e7b86df), don't re-try.
Suggested next message: "Open the PR to main for the cross-language-impact-coverage branch (41 commits — full README parity: all 22 'Full support' languages + all 14 frameworks now have coverage validation)."
529d822) — RN/Expo multi-platform reposGoal (from user): bump async-storage (75.0%) and rn-device-info (72.4%) to 95%+. Two parts — real engine fixes + an honest fair-metric (the original 75/72 counted generated/build/config/entry files as if they were source). Engine fixes (real coverage, generalizable):
#include — #include "Foo.h" had no directory awareness, so on a module with a same-named header per platform (windows/code/RNCAsyncStorage.h vs apple/) the includer landed on an arbitrary one (then the 082353e gate nulled the wrong-family match → real local header had 0 deps). Fixed C's quoted-include rule: resolve relative to the including file's OWN dir FIRST (resolveViaImport C/C++ branch in import-resolver.ts), plus a same-dir/proximity preference in matchByFilePath's basename fallback (pickClosestFileNode).expect decl + its actuals share one FQN across source sets; resolveJvmImport took candidates[0], so one platform actual absorbed every common-side import and the expect looked unused. Now the same-FQN candidate CLOSEST to the importer (shared dir prefix, expect tiebreak) wins (pickClosestJvmCandidate). Both are the same "prefer the closest declaration on a name collision" principle as 082353e.
Honest fair metric (/tmp/faircov.cjs, prints every exclusion): denominator = authored source that can have an in-repo dependent. Excludes (per methodology, all auditable): structural (generated .g.h/codegen, pch.*, *.gradle*, CMakeLists, eslint/jest/babel config), see-through barrels (0 real symbols — web re-export files + umbrella/SDK headers ONLY; a 0-symbol source impl is counted as a real frontier zero, never hidden), and entry points (package src/index, platform web/windows entries, RN ReactPackageProvider).
Before/after:
| Repo | FAIR coverage before→after | residual zero (frontier) |
|---|---|---|
| async-storage | 75.0% → 97.4% (37/38) | DatabaseFiles.kt (KMP expect-decl side, no in-repo caller) |
| rn-device-info | 72.4% → 95.2% (20/21) | RNDeviceInfoCPP.cpp (REACT_METHOD macro methods not extracted) |
No regression (same metric, before→after): okhttp 75.9%→76.4%, kotlinx.coroutines 89.7% (neutral), leveldb 78.0% (neutral), redis 89.7%→89.9%, fmt 77.3% (neutral); cross-family false edges still 0 everywhere. 2 regression tests in extraction.test.ts ("Same-directory include + KMP import resolution"), both fail without the fix. Full suite 1169.082353e) — cross-family references/importsSymptom (was): in react-native-async-storage, a TS type TestRunner and a Kotlin class TestRunner collided — TS references/imports resolved onto the Kotlin class (web→jvm false match). Plus import React↔Swift React and a C++ #include "RNCAsyncStorage.h"↔iOS ObjC header (basename collision).
Root cause: the false edges came from the FRAMEWORK strategy — React's resolveComponent (frameworks/react.ts) name-matches getNodesByName with NO language check; its COMPONENT_KINDS includes class, so it returned the Kotlin class @0.8 (the TS type_alias filtered out), outranking the cross-lang-penalized (0.5) TS name-match. AND imports were never gated (only references was). NOTE: this.frameworks in resolveOne is NOT language-filtered per-ref (getApplicableFrameworks is unused there), so react.resolve runs for EVERY ref — its languages field is dead in that path.
Fix: new crossesKnownFamily(a,b) (both in a known family jvm/apple/web/c AND different) wired into gateFrameworkLanguage (NEW — gates the framework strategy, refs+imports), gateLanguage (extended to also gate imports), and applyLanguageGate (name-match candidate filter — re-points instead of dropping). KEY RULE (non-obvious): the references gate stays STRICT (!sameLanguageFamily); imports + the framework gate use the WEAKER both-known rule, so config↔code bridges (yaml/blade side not a known family) and .vue/.svelte→.ts imports survive. calls bridges are never gated.
Before/after — precision fix (coverage HELD/up, false edges → 0):
| Repo | FAIR coverage before→after | cross-known-family false refs/imports |
|---|---|---|
| async-storage | 75.0% (39/52) → 75.0% (39/52) | 22 → 0 |
| rn-device-info (control) | 69.0% (20/29) → 72.4% (21/29) | 5 → 0 |
Coverage held on async-storage (no recall lost) and ROSE on rn-device-info (re-pointing gave a real same-family file a correct dependent). Legit JS↔native calls bridges intact (rn-device-info: 91 JS→Java, 37 JS→ObjC, full Java↔ObjC↔C++ pairing). 2 regression tests in extraction.test.ts ("Cross-language type/import gate"), both fail without the fix. Full suite 1167. Measure: /tmp/faircov.cjs <repo> (fair coverage + false-edge count) and /tmp/xlang.cjs <repo> (cross-lang edges by src→tgt × kind).
d06a5ec, 74b599c, 2026-06-04)(1) RCT_EXPORT_METHOD EXTRACTION (d06a5ec): RN bridge resolver now implements extract() for .m/.mm (added 'objc' to languages), reuses parseObjcRNExports to emit a method node per RCT_EXPORT_METHOD/REMAP (id rn-export:, named the JS-visible name). The macro parsed as ERROR before → iOS methods invisible. rn-device-info JS→objc 7→37, java↔objc pairs 22→29. (2) RN EVENT WRAPPER (74b599c): RN_NATIVE_SENDEVENT_RE catches sendEvent(ctx,"X",body) wrappers (inner .emit uses a variable) → native java/swift events now connect to JS hooks. Synth tag is rn-event-channel. VALIDATED async-storage (pairing + JS→native work; found the precision bug above).
4a64ca5, 2026-06-04)rnCrossPlatformEdges (callback-synth): a native method (java/kotlin/objc/cpp) with a JS-side calls edge = confirmed bridge method → link to same-norm-name native method in another language (getFreeDiskStorage:→getFreeDiskStorage, first selector keyword), both directions. Skip RN_INFRA names (addListener/getConstants/getName/…). rn-device-info: 152 pairs (Java↔ObjC↔C++). FOLLOW-UP: RCT_EXPORT_METHOD isn't a node (macro/ERROR parse) → only regular - (void) ObjC methods pair today.
dbc4862, 2026-06-04)NEW direction: RN/Expo repos where JS↔native crosses LANGUAGE boundaries. Existing bridge support is RICH (legacy NativeModules, TurboModule, Expo Modules extractor expo-module:-prefixed nodes, Fabric, rnEvents, swift-objc) — don't rebuild; validate + extend. Classic RN bridge WORKS (rn-device-info: 118 JS→Java + JS→ObjC calls). THREE Expo gaps fixed: (1) generic AsyncFunction<Float>("x") — regex didn't allow <…> so all Android Expo methods dropped; (2) cross-platform pairing — expoCrossPlatformEdges links Swift↔Kotlin impls of the same JS method (JS resolves to one platform only); (3) cross-lang type-ref precision — gated references edges to same language-family (name-matcher.ts applyLanguageGate/sameLanguageFamily + index.ts gateLanguage), so native BatteryManager.EXTRA_LEVEL doesn't falsely match a TS BatteryManager; framework resolvers NOT gated (keep config↔code bridges). Measure: /tmp/xlang.cjs. Detail in memory.
33ce431, 2026-06-04)WORST README language at baseline. FOUR fixes (3 in tree-sitter.ts, 1 in name-matcher.ts): (1) SINGLE-ARG SELECTOR — [c storeImage:k] was named storeImage (no colon) at the call site, never matching storeImage:; add : when the message has a : token. (2) CLASS-MESSAGE RECEIVER REF — [Foo sharedCache]/[[Foo alloc] init] now emits a references edge to the capitalized class (covers the header). (3) #IMPORT BASENAME — #import "Foo.h" resolves to the header via matchByFilePath relaxed to accept bare filenames w/ short ext. (4) CLASS-METHOD COLON — Foo.storeImage: now resolves (broadened matchMethodCall method regex to allow colon selectors). AFNetworking 50%→90%, SDWebImage Core 33.8%→91.6%. GOTCHA: SDWebImage include/SDWebImage/*.h are SYMLINKS to Core/ — measure Core/ only. Residual = public-API category methods called by app code (frontier). Detail in memory.
Dart was in TYPE_ANNOTATION_LANGUAGES but produced ZERO references edges, AND mixins were dropped. (NOTE: dio raw 67.8% was example-dir pollution — real 86.4%.) Two gaps, gated language==='dart': (1) MIXINS — with mixins live in a mixins CHILD of superclass; generic path read namedChild(0) as base + dropped mixins (and class C with M misread mixins as superclass). Dart branch in extractInheritance: extends base + implements per mixin. (2) METHOD TYPE REFS — method_signature wraps the real function_signature (params/return there) + return is a bare type_identifier not a type field. Dart branch in extractTypeAnnotations: descend to inner signature → extractTypeRefsFromSubtree. flutter/packages 88.8%→92.4%, dio 86.4%→87.9%. Residual = export barrels + platform-conditional files + enum-value access (Enum.value — value-read frontier; a Dart Capitalized.member→ref pass would be precise, the top follow-up). Detail in memory impact-coverage-findings.md.
857baf7, 2026-06-04)The deferred cross-language lever, now DONE. A type used only via a static member / enum VALUE (MediaKind.video, Colors.red, JsonScope.NAME, Foo::BAR) recorded no edge (body walker only did CALLS + new). extractStaticMemberRef (tree-sitter.ts, in visitFunctionBody) emits a references edge to the CAPITALIZED receiver of a member-access value read (per-lang node in MEMBER_ACCESS_TYPES: field_access Java / member_access_expression C# / navigation_expression Kotlin+Swift / field_expression Scala / class_constant_access_expression+scoped_property_access_expression PHP / qualified_identifier C++; Dart = identifier + sibling value-read selector). Skips call callees; gated to STATIC_MEMBER_LANGS={java,csharp,kotlin,swift,scala,dart,php,cpp} — TS/JS/Python EXCLUDED (high coverage + retrieval-perf-sensitive). flutter/packages 92.4%→93.2%; additive elsewhere; nodes stable. Detail in memory.
ec8fe3f, 2026-06-04)C/C++ were already HIGH (name-matching resolves cross-file calls across the .h/.c split). NOT an import gap. The systematic gap was a C++ EXTRACTION BUG in languages/c-cpp.ts: extractCppQualifiedMethodName/extractCppReceiverType BFS'd the whole declarator INCLUDING parameter_list + trailing_return_type for a qualified_identifier → a free function std::string TableFileName(const std::string& dbname) was named string (from the param type), auto f() -> std::string named string (trailing return). Calls never resolved; defining file looked dependent-less. Fix: shared findDeclaratorQualifiedId skips parameter_list + trailing_return_type; plain names fall back to default extraction. leveldb 91.7%→94.8%, fmt 32 mis-named→1, redis (C, unaffected) 92.2% at ceiling. Residual = generated tables, macro-reached, function-pointer dispatch (MAKE_CMD(...,sortCommand,...) — deferred, broad/risky), C++ namespaces (deferred). Detail in memory impact-coverage-findings.md.
44fb978 + 5bccab6, 2026-06-04)TWO gaps. (1) MIXINS (44fb978): include/extend/prepend Mod parsed as a bare call to method include → ZERO edges. Fix in languages/ruby.ts visitNode: detect bare include/extend/prepend (guard !receiver so arr.include?(x) is safe) → emit implements edge class/module→module. (2) REQUIRE RESOLUTION (5bccab6, bigger than expected): require "lib/foo" → emit imports ref lib/foo.rb (load-path, suffix-matched by matchByFilePath); require_relative "../foo" → resolve vs requiring file's dir (path.posix.normalize); bare require "json" skipped. Resolves to the FILE node. sidekiq 71%→76.8% (mixins)→100% (requires); activerecord 84.8%→93% (mixins)→96.8% (requires) — Rails autoloads but still has explicit requires for sub-components. Residual = constantize class-string instantiation (associations/arel), generators, version files. Detail in memory impact-coverage-findings.md.
acfb444, 2026-06-04)ROOT CAUSE: PHP ignored NAMESPACES — every class qn was the bare simple name, so laravel's 7+ same-named Factory interfaces across namespaces collapsed to one arbitrary match, and use imports never resolved. Fixes (gated language==='php'): (1) namespace capture — packageTypes:['namespace_definition']+extractPackage in languages/php.ts → classes scoped to Foo\Bar::Class; (2) use-import resolution — emitPhpUseRefs emits an imports ref in Foo\Bar::Baz form, matched precisely by the resolver's resolveQualifiedName (THE big lever, 80.5%→94.9%); (3) type-hint refs — PHP-aware extractPhpTypeRefs (PHP types are named_type/union_type wrapping name, not type_identifier). guzzle 95.2%→100%, laravel 80.5%→94.9%. Residual = class-string/reflection wiring (service providers, facades, middleware) — genuine frontier. Detail in memory impact-coverage-findings.md.
b5489d9, 2026-06-04)Scala was the WORST starting point — extraction made nodes but almost NO edges for typeclass code (cats 1.66 edges/node). Not one gap but a family, all gated to language==='scala' in extraction/tree-sitter.ts (+ languages/scala.ts): (1) parameterized extends — extends A[X] with B packed all supertypes in one extends_clause; generic path took only namedChild(0) w/ full text A[X] so no typeclass matched → new shared scalaBaseTypeName unwraps generic_type, iterate all supertypes (cats 48.9%→77.2% from THIS alone); (2) type refs (Scala had ZERO references) — added scala to TYPE_ANNOTATION_LANGUAGES + walk EVERY curried parameters list (trailing (implicit M: TC[A])!) + type_parameters context bounds ([A: Monoid]) + val/var types from scala.ts (77.2%→89.2%); (3) instantiation new T[...] = instance_expression. cats 48.9%→89.2% fair (82.1% raw — scalafix/bench excluded), gatling 76.3%→91.2%. Residual = cross-build variants/laws/wildcard-barrels (frontiers). Detail in memory impact-coverage-findings.md.
d8a2e91, 2026-06-04)Systematic Kotlin gap = Kotlin Multiplatform expect/actual (the only Kotlin-unique construct). OkHttp (the README Kotlin benchmark) was ALREADY 96.2% out of the box; kotlinx.coroutines (KMP) was 76.8% → 93.5%. Fix: new generic extractModifiers hook captures expect/actual (from modifiers > platform_modifier) onto the node's decorators list (wired once in createNode); kotlinExpectActualEdges in callback-synthesizer.ts links common decl → each platform actual as a heuristic calls edge (matched by qualified_name + the actual marker; decl side = non-actual same-qn node, which also gates out plain overloads; kind-widened so expect class ↔ actual typealias links). Node count stable. Residual = genuine frontiers (expect-decl sides, ServiceLoader/agent SPI, test infra). Full detail in memory impact-coverage-findings.md.
Make the engine's cross-file dependency graph complete for every README "Full support" language, so impact/affected/callers/callees/explore all see real dependencies. Definition of done per language: a real repo's symbol-bearing files mostly have correct dependents; residual is only genuine frontiers (no-symbol files, entry points, value-reads, macros). Each language: audit → fix → validate → commit to the branch.
/tmp. Index with CodeGraph.initSync(repo,{config:{include:['**/*.<ext>'],exclude:[]}}) + indexAll() + resolveReferences() via a node -e against dist/index.js.target of a non-contains edge whose source is in another file. EXCLUDE from the denominator: files with no non-file node (package-info.java, doc.rs, __init__ umbrellas), tests, entry points (main/bin/examples/benches/fuzz/samples), and miscounted other-language files (e.g. .kt under a Java repo).npm run build (tsc must pass) → npm test (expect ~1151 passing) → add a test in __tests__/extraction.test.ts → CHANGELOG [Unreleased] → Fixes bullet.git add <files> + commit (Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com) + git push origin feat/cross-language-impact-coverage. Do NOT commit .claude/handoffs/*.16b5633): imports edges are same-file (file→local import node), so the old getFileDependents returned 0 for every file. Added getDependentFilePaths/getDependencyFilePaths in src/db/queries.ts (indexed JOIN, all kinds except contains); src/graph/queries.ts delegates.src/extraction/tree-sitter.ts): emitImportBindingRefs (TS/JS named/default/namespace), emitReExportRefs (TS export {X} from), emitPyFromImportRefs (Python from m import X), emitRustUseBindingRefs (Rust use/pub use, emits FULL path). All gated by language in extractImport.src/resolution/import-resolver.ts): resolvePythonModuleMember + resolveModuleImportToFile (Python+TS namespace), resolveGoCrossPackageReference (Go, pre-existing), resolveRustPathReference+resolveRustModuleFile+rustCrateRootDir/rustSelfModuleDir (Rust crate::/self::/super::). Resolve a path's module PREFIX to a file, find the leaf there — fixes common-name collisions.INSTANTIATION_KINDS in tree-sitter.ts now includes composite_literal (Go) + struct_expression (Rust). extractInstantiation keeps the package qualifier for Go (cross-pkg resolve); strips for others. Also normalizes parenthesized type conversions (*T)(x).IFACE_OVERRIDE_LANGS in src/resolution/callback-synthesizer.ts now includes go and rust. Needs the interface/trait's METHODS extracted: Go via extractGoInterfaceMethods (tree-sitter.ts), Rust via adding function_signature_item to rust.ts function/methodTypes. goImplementsEdges synthesizes Go implicit implements edges (method-set match) and must insertEdges FIRST in synthesizeCallbackEdges.extractDecoratorsFor): it now (a) descends into modifiers nodes (Java/Kotlin/C#), (b) recognizes Swift attribute + user_type. Java needed annotation_type_declaration added to interfaceTypes (java.ts). C# needed record_declaration/record_struct_declaration (csharp.ts). Swift needed a dispatcher branch running extractDecoratorsFor+extractVariableTypeAnnotation on property_declaration inside a type (Swift instance props aren't nodes).visitFunctionBody now extracts variable_declarator type annotations (const x: Foo).| Language | Repo | Before | After | Key fix |
|---|---|---|---|---|
| TypeScript/JS | codegraph (this repo) | 62.5% | 95.8% | import + re-export + namespace linking; in-body type annotations |
| Python | requests | 54.1% | 100.0% | from x import linking; from . import sub + sub.f() module-member resolution; relative-dot path fix |
| Python | flask (src) | 66.7% | 87.5% (true ceiling — residual all correct-0) | (same) |
| Go | gin | 62.7% | 96.6% | composite literals → instantiates; package-level var registries; (*T)(x) conversions; implicit interface satisfaction (#584) |
| C# | MediatR (library) | 81.5% | 85.2% | record / record struct indexed (#237) |
| Rust | ripgrep | 63.4% | 86.7% | struct literals; trait dispatch (trait methods + #584); use/pub use linking; module-path resolution for pub use self::x::y |
| Rust | tokio (src) | 70.0% | 81.9% | (same — number is honest/precise; earlier leaf-only match had inflated it) |
| Java | gson | 78.2% | 85.1% (raw) · 93.3% fair | annotations: index @interface defs + link @Foo usages (in modifiers) |
| Java | retrofit | 80.5% (raw) | 94.9% fair | (same) |
| Swift | Alamofire | 93.0% | 95.3% | property wrappers / attributes (@Argument/@Published/@objc) |
| Swift | swift-argument-parser | 84.6% | 96.2% | (same) |
| Kotlin | OkHttp | 96.2% | 96.2% | already at ceiling (JVM, barely uses KMP) — no change needed |
| Kotlin | kotlinx.coroutines | 76.8% | 93.5% | Kotlin Multiplatform expect/actual linking (incl. actual typealias) |
| Scala | typelevel/cats | 48.9% | 89.2% fair (82.1% raw) | parameterized extends + type refs (implicit/context-bound) + new |
| Scala | gatling | 76.3% | 91.2% | (same) |
| PHP | guzzle | 95.2% | 100.0% | namespace capture + use-import resolution |
| PHP | laravel/framework | 80.5% | 94.9% | namespace capture (disambiguates same-named contracts) + use-imports + type-hints |
| Ruby | rails/activerecord | 84.8% | 96.8% | mixin edges (include/extend/prepend) + require resolution |
| Ruby | sidekiq | 71.0% | 100.0% | mixins + require/require_relative → file resolution |
| C++ | google/leveldb | 91.7% | 94.8% | fix free-function name extraction (was named after param/return type) |
| C | redis | 92.2% | 92.2% | already at ceiling (C unaffected; residual = generated/macro/fn-ptr) |
| Dart | flutter/packages | 88.8% | 92.4% | with mixins + method type references |
| Dart | dio | 86.4% | 87.9% | (same; raw 67.8% was example-dir pollution) |
| Obj-C | AFNetworking | 50.0% | 90.0% | single-arg selectors + class-receiver refs + #import + class-method resolution |
| Obj-C | SDWebImage (Core) | 33.8% | 91.6% | (same; include/ dirs are symlink dups — measure Core/) |
| Lua | nvim-telescope | 31.6% | 84.2% | require() module resolution: dotted a.b.c→a/b/c.lua + instance-path leaf, path-suffix match w/ same-dir preference (4155609). Residual = telescope's dynamic setmetatable lazy-require pickers (frontier). |
| Luau | dphfox/Fusion | 12.5% | 92.2% | (same require resolver — require(script.Memory.deriveScope)) |
| Liquid | Shopify/dawn | 39.1% | 73.8% | Shopify OS 2.0 JSON-template section parsing: index templates/*.json + section-group sections/*.json (incl. nested templates/customers/), link each "type"→sections/X.liquid (2f57119). Snippet {% render %} already worked. Residual = preset/theme-editor sections (no static ref) + dynamic {% render block %}. |
| Pascal/Delphi | PascalCoin | 73.0% | 75.7% | uses-resolution ALREADY worked (73%); + .dfm/.fmx form ↔ same-basename .pas code-behind pairing (2f30a3b). Residual = vendored third-party libs (src/libraries/* internal units, ≈node_modules) + dynamic form/RPC instantiation. |
"raw" vs "fair": "fair" excludes files that structurally can't have dependents (no-symbol files like package-info.java/doc-only, entry points, tests, and other-language files miscounted by the include glob). For Java the raw numbers were heavily polluted (gson had many package-info.java; retrofit had .kt + samples), so the fair number is the real one (~93–95%). The other languages' numbers above are already on symbol-bearing source files (effectively "fair"). C# MediatR's 85.2% is the library-only figure; a package-info-excluded "fair" wasn't separately computed but is higher.
| Framework | Repo | Before | After | Key fix |
|---|---|---|---|---|
| React Native / Expo | react-native-async-storage | 75.0% | 97.4% fair (37/38) | cross-family gate (082353e) + same-dir C/C++ #include + KMP commonMain import (529d822) |
| React Native | react-native-device-info | 72.4% | 95.2% fair (20/21) | cross-family gate (082353e) + honest fair metric (its 529d822 engine-fix targets are excluded entry files) |
Metric note (read before trusting the "Before"): the "Before" 75.0%/72.4% used an under-exclusive denominator — it counted generated codegen (.g.h), build scripts (pch.*, *.gradle.kts), tooling config (eslint/jest/yarn), and platform/registration entry points as if they were source. The "After" uses the honest fair metric the per-language table uses: excl. structural (generated/build/config/test), see-through barrels (web re-export files + umbrella/SDK headers — but NOT a 0-symbol source impl, which is a real frontier), and entry points (package src/index, platform web/windows entries, RN ReactPackageProvider). Apples-to-apples (fair metric held constant, isolating just the 529d822 engine fixes): async-storage 92.1% → 97.4% (+RNCAsyncStorage.h via same-dir include, +Platform.kt via KMP import); rn-device-info 95.2% → 95.2% (neutral — its same-dir/KMP targets are excluded entry headers, so its lift to 95.2% was the metric correction + the 082353e gate). Residual zeros (real frontiers): async-storage DatabaseFiles.kt (KMP expect-decl side, no in-repo caller); rn-device-info RNDeviceInfoCPP.cpp (REACT_METHOD macro methods not extracted). Measure with /tmp/faircov.cjs <repo> --list. No regression on controls: okhttp 75.9→76.4, kotlinx.coroutines 89.7 (neutral), leveldb 78.0 (neutral), redis 89.7→89.9, fmt 77.3 (neutral); cross-family false edges 0 everywhere.
Measured 2026-06-04 (commit 61a993a) on a canonical real app for each README route framework. This is the active front of the campaign — the unmeasured frameworks have the real headroom.
| Framework | App repo | FAIR coverage | Status / next |
|---|---|---|---|
| Express (TS) | express-realworld | 70.4% → 100% ✅ | DONE (2a0b6e0): renamed default-import → module file (route controllers export default router). |
| FastAPI (Py) | fastapi-realworld | 78.6% → 98.0% ✅ | DONE (2835623): source-aware from pkg import submodule (router aggregator). 1 residual = aliased sub-aggregator. |
| Flask (Py) | flask (lib) | 100.0% ✅ | DONE (entries/barrels excluded) |
| requests (Py) | requests (lib) | 100.0% ✅ | DONE |
| NestJS (TS) | nestjs-realworld | 93.8% → 96.8% ✅ | DONE (main.ts entry excluded) |
| Gin (Go) | gin (lib) | 96.5% ✅ | DONE (faircov Go _test.go exclusion) |
| Laravel (PHP) | laravel (lib) | 92.0% | done (per-language; app not separately measured) |
| Rails (Ruby) | rails (lib) | 89.6% | done (per-language) |
| Django (Py) | django-realworld | 45.9% → 74.1% | PARTIAL (58dc463): abs-module-import + include('app.urls') done. Ceiling ~83% w/ entries excluded. FRONTIERS: signals via in-body ready(): import myapp.signals (Python in-body imports NOT extracted — visitFunctionBody walks calls but not import_statement); DRF/string-config exception classes (EXCEPTION_HANDLER: '...'). |
| ASP.NET (C#) | eShopOnWeb | 59.3% → 83.9% | chained extension calls (4c14413) + framework-entry exclusions (b) + Razor/Blazor markup parser (59b8de2 tags/@model + 90c5f39 @code) + C# namespaces (dc7d033) + Razor @using disambiguation (9e5a951) — DTOs now resolve to BlazorShared.Models::CatalogBrand not the same-named entity. C# constructor DI / interface→impl ALREADY worked. Residual ~24 = reflection/proxy (AutoMapper profiles / Swagger filters / middleware / health checks — invoked by reflection, a separate modeling feature) + a few C# static-const reads (Constants.X — extend the static-member pass to C#). |
| Spring (Java) | spring-petclinic | 65.2% → 83.3% ✅ | DONE — convention/reflection ceiling, on par with ASP.NET. 30 main java = 15 covered + 7 entry (1 *Application main + 6 *Controller) + 5 barrel (package-info.java) + 3 zero. 3 residual zeros all reflection-registered: CacheConfiguration/WebConfiguration (@Configuration, component-scanned — WebConfiguration is even @SuppressWarnings("unused")) + PetClinicRuntimeHints (@ImportRuntimeHints(X.class) class-literal = the documented Foo.class→Class frontier). faircov fix = barrel-exclude package-info.java/module-info.java shells. No samples-dir exclusion ever existed in the script — that handoff note was inaccurate. |
| Axum (Rust) | realworld-axum-sqlx | 72.7% → 100% ✅ | DONE (a3f59fb) — import/aggregator style, confirmed in Rust. REAL engine miss found+fixed: bare Rust submodule::fn() calls (the X::router() router-assembly pattern) resolved crate-relative only → now self-relative FIRST (current module), then crate fallback. + main.rs/src/bin/*.rs faircov entry exclusion. Clean A/B (same faircov, engine ±fix): axum +2 → 100%, ripgrep neutral (66/79), tokio +3 (260/321); cross-family false edges 0. Regression test fails without the fix. |
| Rocket (Rust) | TatriX/realworld-rust-rocket | 62.5% → 68.8% → 93.8% ✅ | DONE — TWO engine wins. (1) 7bb958b: a 3-segment database::profiles::find() call (inside db.run(\|c\| …)) was dropped by the resolver PRE-FILTER (leaf never checked) → +database/profiles.rs. (2) 6d214cd: NEW routes![]/catchers![] macro extractor — the handler paths live in a raw token-tree, so the 4 routes/*.rs handler modules (mounted at runtime) looked uncalled; now reconstructed from the macro + resolved via the Rust path resolver → all 4 covered. Only lib.rs (crate-root/launch hub, see-through) remains. No control regression; false edges 0; nodes unchanged (edges only). |
| actix-web (Rust) | fairingrey/actix-realworld-example-app | 65.4% | DONE (genuine ceiling). actix 1.x ACTOR style: routing resolves fine (.route(web::post().to(users::register)) → handlers covered), but the DB layer is reached via actor message dispatch (db.send(RegisterUser) → impl Handler<RegisterUser> for DbExecutor) — a DYNAMIC runtime boundary, no static edge (the actix analog of the MediatR/reactive runtimes the engine deliberately leaves uncovered). 9 zeros = 5 db/*.rs (actor dispatch) + models/mod/utils/mod/prelude (glob pub use self::x::* re-export roots) + utils/hasher (reached only via that glob). Bridging needs an actor-message synthesizer (dynamic-dispatch feature), not a static-resolution fix. |
| Vapor (Swift) | vapor-til (canonical) | 85.7% → 100% ✅ | DONE — import/aggregator confirmed in Swift. Controllers covered via app.register(collection: X()), models via controller queries + migrations. REAL miss found+fixed (bb7659e): the many-to-many pivot model was referenced ONLY via @Siblings(through: Pivot.self) — a metatype arg inside a property-wrapper attribute that wasn't walked → now routed through extractStaticMemberRef → pivot covered. + faircov excl Package.swift (SPM manifest) & Public/ (static assets). A/B (same faircov): vapor-til +1 → 100%, Alamofire neutral (44/50); false edges 0. |
| Vapor (Swift) | penny-bot (real prod, 166 files) | 73.2% | SECONDARY — a serverless/DI architecture, NOT the canonical route→controller→model shape. 37 zeros = AWS Lambda handlers (*Handler/*Lambda, invoked by the AWS runtime → entry points, no in-repo caller) + exports.swift re-export barrels (see-through, like Rust mod.rs roots) + Swift extension files (+X.swift) + DTOs/services reached via DI / JSON-decoding (genuine frontiers). Excluding the Lambda entries + exports barrels (faircov gaps) → ~80%; genuine residual is the DI/serialization architecture. NOT chased — vapor-til is the canonical result. |
| SvelteKit (Svelte) | sveltejs/realworld (official) | 35.9% raw → 100% fair ✅ | DONE — characterization, NO engine miss (first framework that needed none). The .svelte import resolution ALREADY connects the whole component graph (page→component→lib: ArticlePreview←ArticleList, Nav←+layout, ListErrors←4 pages — imports+references+calls all resolve). Low RAW = the file-convention shape: 25/39 files are SvelteKit convention ENTRIES (+page/+layout/+error/+server/hooks — loaded by the framework BY PATH, no in-repo caller = route leaves, like route handlers). Excluding those (new faircov ENTRY patterns) → 14/14 = 100% of the coverable core. ONE framework-mediated gap: +page.server.js load → +page.svelte data is NOT a static link (runtime data prop) — was bridged with a SvelteKit convention synthesizer (sibling files by path, like Rocket routes!) — impact-granularity, not coverage (both files are entries). BUILT (3ea03e5): svelteKitLoadEdges links each page component → its OWN-dir loader's load/actions (same for +layout); path-deterministic (19 links / 0 cross-dir mislinks on realworld), provenance heuristic, nodes unchanged. getImpactRadius(load) now surfaces its page. |
| React Router (React) | gothinkster realworld | 100% ✅ | DONE — characterization, NO engine miss. The CONFIG-based component-node sub-shape: route components are NAMED in source (<Route path='/login' component={Login}/> → App.js imports + references Login), so they resolve cleanly — verified Login/Editor/Profile all covered BY App.js's route config (imports+references). 29/29 (only index.js CRA entry + 8 anonymous-default-export reducers [0 named symbols → barrels] excluded). CONTRAST with SvelteKit (file-convention, needs entry-exclusion): the component-node category has TWO sub-shapes, both handled by the engine as-is. (App is old v4/v5 component={X}; modern v6/v7 element={<X/>} + data-router {element, loader} are also source-referenced → same conclusion.) No commit (nothing to fix). |
| Nuxt (Vue) | nuxt/movies (official demo) | 47.6% → 93.5% fair ✅ | DONE — file-convention component framework (like SvelteKit) but with an AUTO-IMPORT twist that was a REAL miss (1dec765). Nuxt auto-imports a NESTED component by a DIR-PREFIXED name: components/media/Card.vue → <MediaCard/>, but the node is named Card → the PascalCase template usage never resolved (the synth only matched kebab tags; the extractor's PascalCase ref name-matched MediaCard→nothing). Fix in vueTemplateEdges: match PascalCase tags + a nuxtComponentName map (media/Card.vue→MediaCard, incl. Nuxt dir de-dup) → +9 nested components. + faircov Nuxt entry exclusions (pages/, app.vue, error.vue, layouts/, plugins/, middleware/, server/). 2 residual zeros = genuine frontiers (unused <CarouselItems> variant + unimported constants/images.ts). Composables auto-import (useTmdb()) already resolved by name-match. false edges 0, nodes unchanged. vs SvelteKit: SvelteKit needed NO component fix (svelte imports resolve); Nuxt DID (its auto-import dir-prefix naming is unique). |
| Drupal (PHP) | token (contrib module) | 57.1% raw → 78.9% fair | DONE — the MOST reflection-heavy framework, a genuine sub-95% ceiling (≈ASP.NET 83.9%, Django 74.1%). Static parts WORK: *.routing.yml→controller (drupal.ts resolves it — TokenTreeController covered via the route ref), PHP class refs (namespaces/use/type-hints). 4 residual zeros all DI/reflection-wired: 2 services in services.yml (TreeBuilder = @token.tree_builder, TokenFieldRender), a DYNAMICALLY-routed controller (TokenDevelController via RouteSubscriber, not static YAML), a field-plugin class (MenuLinkFieldItemList list_class). + faircov excl JS libraries + convention entries (.install/.module, src/Plugin/Element, Drush, *ServiceProvider, Routing/*Subscriber). LEVERS (drupal.ts TODOs, large per-mechanism features, NOT chased): model services.yml DI (→ covers the 2 services), plugin annotations + modern #[Hook] attributes. No commit (no simple miss). |
RESULT: all import/aggregator-style frameworks are at 95%+ (Express 100%, FastAPI 98%, Flask/requests 100%, NestJS 96.8%, Gin 96.5%, Axum 100%).
Option (b) DONE (metric-only — framework-entry exclusions in /tmp/faircov.cjs): added convention-entry patterns (*Controller.cs/java, *.cshtml.cs, *Endpoint.cs, EF Data/Config/*.cs, Program/Startup.cs, *Application.java, Django admin.py/apps.py). Result — convention frameworks rise but still cap well below 95%: ASP.NET 65.3% → 77.2% (50 entries excluded), Spring petclinic 65.2% → 83.3% (after the package-info.java shell-exclusion fix below), Django 74.1%. The import-style frameworks are unaffected (Express 100%, FastAPI 98%, NestJS 96.8%, Gin 96.5% — the C#/Java/Django entry patterns don't touch them).
WHY (b) doesn't reach 95% — the honest ceiling: after excluding routed/reflection-registered entries, the residual zeros are markup-driven code-behind (Blazor .razor / Razor .cshtml / Thymeleaf reference the .cs/.java, but the markup isn't parsed → ViewModels, DTOs, components look unused) and reflection/proxy code (Spring Data repository proxies, AutoMapper profiles, Swagger filters, DI/middleware registration, Django signals/string-config). These are genuine static-analysis frontiers — reaching 95% needs (1) parsing template markup to link markup→code, or (2) per-framework reflection/proxy modeling — both large features. Excluding markup-driven business code (DTOs/ViewModels) from the metric to fake 95% would be gaming — NOT done. Note: business LOGIC (services, repos) IS covered in all three; the residual is leaf views/DTOs/configs whose impact is captured the other direction (route→handler).
Generalizable engine fixes shipped this campaign (all benefit beyond their trigger framework): Python absolute import a.b.c (61a993a); source-aware from pkg import submodule (2835623); Django include('app.urls') claim (58dc463); chained method calls a.b.Method() incl. C# extension methods (4c14413); renamed default-import → module file (2a0b6e0); Rust bare submodule::fn() calls resolved self-relative — current module first, then crate fallback (a3f59fb); multi-segment Rust a::b::c() module calls no longer dropped by the resolver pre-filter — the leaf name is now checked (7bb958b).
KEY REALITY (honest): apps dominated by convention/reflection-driven code (ASP.NET MVC/Razor/Blazor, EF config, reflection DI; Django signals/DRF; any framework whose handlers are discovered by routing/DI container, not called by in-repo code) have files with NO static in-repo caller. Those are genuine static-analysis frontiers — literal 95% is not reachable on such apps without either (a) excluding all framework-entry conventions from the fair denominator (defensible per methodology but extensive + per-framework), or (b) modeling each framework's convention routing + DI container (large per-framework engine work). The DI-heavy/convention-heavy frameworks (ASP.NET, Spring, MVC) are this category; the import/aggregator-style ones (FastAPI, Flask, Express, Gin) reach 95%+ with tractable resolution fixes.
SWEEP COMPLETE — every README framework measured. Route frameworks: Express 100%, FastAPI 98%, Flask/requests 100%, NestJS 96.8%, Gin 96.5%, Axum 100%, Rocket 93.8%, Vapor 100%, Laravel 92%, Rails 89.6% (import/aggregator) · ASP.NET 83.9%, Spring 83.3%, Drupal 78.9%, Django 74.1%, actix 65.4% (convention/reflection/actor ceiling). Component-node: React Router 100% (config-based) · SvelteKit 100% fair, Nuxt 93.5% fair (file-convention). Component-node category fully characterized: config-based (route components named in source → 100% raw) + file-convention (discovered by path → entry-exclusion; SvelteKit needed NO component fix, Nuxt needed the dir-prefix auto-import fix). Convention/reflection frameworks (ASP.NET/Spring/Drupal/Django/actix) are at a genuine sub-95% static-analysis ceiling — the levers are large per-mechanism features (markup/reflection/DI modeling), deliberately not chased. faircov exclusions added this session: language-aware test files (_test.go, test_*.py, *Tests.cs, *_spec.rb, …); generated migrations (Django/Alembic migrations/, EF Migrations/*.cs/*.Designer.cs/*ModelSnapshot.cs); Python entries (__main__.py, setup.py, conf.py, docs/) + __init__.py barrels. faircov now barrel-excludes package-info.java/module-info.java shells (package-declaration-only files — they carry a namespace node so realSyms !== 0, but nothing can import them, so they can never be a dependency target; the Java analog of __init__.py). This is what actually blocked an honest Spring number: petclinic's 5 package-info.java sat in the denominator as zeros, deflating 83.3% → 65.2%. There was never a samples-dir exclusion in the script — that earlier handoff note was inaccurate (the only similar rule is example[s]?, which can't match samples). Route-framework-front faircov ENTRY additions: Rust binary entries (main.rs, src/bin/*.rs); Swift Package.swift (SPM manifest) + Public/ static assets; SvelteKit file-convention entries (+page/+layout/+error/+server.*, hooks.*, service-worker.* — framework-discovered route leaves, no in-repo caller); Nuxt file-convention entries (pages/, app.vue/error.vue, layouts/, plugins/, middleware/, server/, proxy/routes/); Drupal convention entries (.install/.module/.profile/.theme hook files, src/Plugin/src/Element annotation-plugins, src/Drush, *ServiceProvider.php, src/Routing/*Subscriber.php) + js/ library assets.
The one big cross-language lever: a static-member / const value-read pass. Extract Type.MEMBER (capitalized/known-type receiver) as a references edge to Type. This is the universal deferred data-flow frontier and would lift C#, Java, Swift, TS, and Rust at once. Implement once in extraction with a heuristic (receiver resolves to / looks like a type → emit ref; skip lowercase obj.field). Trade-off = some instance-field-access noise; that's why it's been deferred. This is the highest-leverage single task remaining.
Per language — what's left and the action to improve it:
TypeForwardings.cs = assembly attrs only, package-info-equivalents) + benchmark mains → ~92%+. A fair re-measure was never run for C# — do it first; the "real" number is materially higher.BuildInfo.BuildDate, enum Edition? where a same-named property shadows the type) → the static-member pass.package-info.java (no symbols) + .kt/samples (already done for the fair number).X.FACTORY), Foo.class class literals (currently Foo.class references Class, not Foo), constant reads (JsonScope.X) → the static-member pass.mod.rs/lib.rs roots (correct-0), macro-reached code (log!, custom macro_rules!, derives — the big Rust frontier, hard), external-trait-only impls.//go:build alternates (appengine/jsoniter/go_json/sonic/nomsgpack) + external-API version.go.//go:build) so inactive variants are excluded from the denominator or all variants are linked (recall-first). Only matters for build-tag-heavy repos; niche.Bottom line: Python/TS/Swift/Go are effectively at ceiling. The two with real headroom are C# (mostly a fair-remeasure — do that first) and Rust tokio (macros — hard). The static-member/const pass is the one change that moves everything a few points; the rest is per-language frontier work.
It's a GRAPH-WIDE update (one shared edges table). getCallers/getCallees follow ['calls','references','imports']; getImpactRadius + getFileDependents/affected follow all except contains; codegraph_explore composes all of them. So instantiates/implements/decorates edges show in impact+explore but not callers/callees (a pre-existing edge-kind filter in getCallers/getCallees — could be broadened, deferred).
.kt leak into the index. Filter in the measurement SQL, not the config./tmp clones persist across turns — rm -rf <repo>/.codegraph before re-indexing or initSync throws "already initialized" and you measure a STALE index (this bit me ~3×; a stale index massively under-reports).npm test uses esbuild (no typecheck); npm run build (tsc) is what catches type errors. Always build before committing. Strict null on regex groups bit me — avoid m[1] indexed access.m[1]) is string|undefined; use guards.npm run build → tsc clean (must pass before commit).npm test → 1178 passed | 2 skipped (59 files, verified 2026-06-05). Per-language tests live in __tests__/extraction.test.ts (describe per language); route-framework/RN tests in __tests__/{react-native-bridge,expo-modules,rn-event-channel}.test.ts.node -e "...initSync...indexAll...resolveReferences..." → the fair-coverage SQL (see Methodology #2). Node count stable = no explosion.~/.claude/projects/-Users-colby-Development-CodeGraph-codegraph/memory/impact-coverage-findings.md.feat/cross-language-impact-coverage, last commit 2f30a3b feat(impact): pair Delphi forms with their .pas code-behind (.dfm/.fmx ↔ .pas).main, 3 behind (behind = 3 README-waitlist doc commits on main). All pushed to origin. NOT merged — branch is for review. Niche-lang commits 39–41: 4155609 (Lua/Luau require resolver), 2f57119 (Liquid Shopify-JSON sections), 2f30a3b (Delphi .dfm form pairing).16b5633→529d822): 16b5633 (foundation+TS/Py/Go/C#), b538aee + 2ac7df5 (Rust), badb124 (Java), d111f26 (Swift), d8a2e91 (Kotlin), b5489d9 (Scala), acfb444 (PHP), 44fb978 + 5bccab6 (Ruby), ec8fe3f (C/C++), 9487954 (Dart), 857baf7 (static-member pass), 33ce431 (Objective-C), dbc4862 (Expo bridges), 4a64ca5 (classic RN pairing), d06a5ec (RCT_EXPORT_METHOD nodes), 74b599c (RN event wrapper), 082353e (cross-family gate), 529d822 (same-dir include + KMP import).61a993a→b653688, added after the original save): 61a993a (Python absolute import a.b.c), 2835623 (source-aware from pkg import submodule — FastAPI), 58dc463 (Django include('app.urls')), 4c14413 (chained a.b.Method() + C# extension methods), 2a0b6e0 (renamed default-import → module file — Express), 59b8de2 (Razor/Blazor .cshtml/.razor markup parser), 90c5f39 (Blazor @code/Razor @{} → C# extractor), 4589cf9 (docs), dc7d033 (C# namespace extraction), 9e5a951 (Razor @using disambiguation), b653688 (handoff notes + docs). Commit 32 (a3f59fb): Rust self-relative submodule::fn() resolution — Axum realworld 72.7%→100%, controls neutral/+3, regression test added. Commit 33 (7bb958b): multi-segment Rust a::b::c() calls no longer dropped by the resolver pre-filter (leaf-name check in hasAnyPossibleMatch) — Rocket realworld 62.5%→68.8%, additive elsewhere, regression test added. Commit 34 (6d214cd): Rocket routes![]/catchers![] macro extractor (parse the handler paths out of the raw token-tree, emit references) — Rocket 68.8%→93.8%, nodes unchanged (edges only), no control regression, regression test added. Commit 35 (bb7659e): Swift property-wrapper attribute-arg type refs — route a property's attribute args through extractStaticMemberRef so a Fluent @Siblings(through: Pivot.self) links the model to the pivot — vapor-til 94.7%→100%, Alamofire neutral, regression test added. Commit 36 (3ea03e5): SvelteKit load→page synthesizer (svelteKitLoadEdges in callback-synthesizer.ts) — links each +page.svelte/+layout.svelte to its OWN-dir loader's load/actions; impact-granularity (coverage already 100%), 0 cross-dir mislinks, nodes unchanged, regression test added. Commit 37 (1dec765): Nuxt nested auto-imported component resolution — vueTemplateEdges now matches PascalCase tags + a nuxtComponentName map (<MediaCard>→media/Card.vue); nuxt/movies 47.6%→93.5%, +9 nested components, Vue-only (gated to .vue), nodes unchanged, regression test added.assets/generate-waitlist.py (unrelated — README-waitlist tooling; the .claude/handoffs/* files are committed on this branch).src/db/queries.ts, src/graph/queries.ts, src/extraction/{tree-sitter,tree-sitter-types,grammars}.ts, src/extraction/razor-extractor.ts (NEW — Razor/Blazor markup), src/extraction/languages/{rust,java,csharp,kotlin,php,ruby,scala,c-cpp}.ts, src/resolution/{import-resolver,callback-synthesizer,index,name-matcher}.ts, src/resolution/frameworks/{python,react-native,expo-modules}.ts, src/types.ts, __tests__/{extraction,graph,expo-modules,react-native-bridge,rn-event-channel}.test.ts, CHANGELOG.md.faircov.cjs (honest fair coverage + false-edge count, --list shows residual zeros + exclusions), audit.cjs (lists 0-dependent files by language), xlang.cjs (cross-lang edges by src→tgt × kind).d8a2e91) — gap was KMP expect/actual; coroutines 76.8%→93.5%, OkHttp already 96.2%. See "Kotlin result" above.b5489d9) — gap was a whole family of missing edges (parameterized extends, type refs, implicit/context-bound params, new); cats 48.9%→89.2% fair, gatling 76.3%→91.2%. See "Scala result" above.acfb444) — gap was NAMESPACES (not #608/#660); guzzle 95.2%→100%, laravel 80.5%→94.9%. See "PHP result" above.44fb978 + 5bccab6) — gaps were MIXINS + REQUIRE resolution; activerecord 84.8%→96.8%, sidekiq 71%→100%. See "Ruby result" above.ec8fe3f) — gap was a C++ free-function name-extraction bug; leveldb 91.7%→94.8%, redis (C) 92.2% at ceiling. See "C/C++ result" above.with) + method type refs; flutter/packages 88.8%→92.4%, dio 86.4%→87.9%. See "Dart result" above.@interface/@implementation split, #import, categories, protocols, @property). Niche after: Liquid, Pascal, Lua, Luau.857baf7) — Enum.value/Type.CONST/Foo::BAR → references; flutter 92.4%→93.2%, additive across Java/C#/Kotlin/Swift/Scala/PHP/C++. TS/JS/Python excluded.33ce431) — selectors + class-receiver + #import + class-method resolution; AFNetworking 50%→90%, SDWebImage Core 33.8%→91.6%. ← LAST README language.16b5633→529d822): all 15 README langs + static-member pass + cross-language RN/Expo at 95%+.61a993a→2a0b6e0): Express 100%, FastAPI 98%, Flask/requests 100%, NestJS 96.8%, Gin 96.5%. See the headroom map.4c14413,59b8de2,90c5f39,dc7d033,9e5a951): ASP.NET eShopOnWeb 59.3%→83.9% (Razor/Blazor parser + C# namespaces), Django realworld 45.9%→74.1%. At an honest sub-95% static-analysis ceiling (markup-driven code-behind + reflection/DI). Reaching 95% needs markup→code linking or per-framework reflection modeling (large features); faking it via metric exclusions = gaming, NOT done.package-info.java shells (5 in petclinic), not a samples-dir exclusion (which never existed in the script). Fixed → barrel-exclude package-info.java/module-info.java. 3 residual zeros = @Configuration beans + AOT RuntimeHints, all reflection-registered → the convention/reflection ceiling, on par with ASP.NET 83.9%.a3f59fb) — import/aggregator thesis confirmed in a 3rd language family. Found+fixed a REAL engine miss (not a metric issue): bare Rust submodule::fn() calls (the X::router() router-assembly pattern) resolved crate-relative only → now self-relative FIRST (current module), then crate fallback. Clean A/B: no control regression (ripgrep neutral 66/79, tokio +3 → 260/321); cross-family false edges 0; regression test fails without the fix. NOTE: actix/Rocket NOW MEASURED (below).7bb958b + 6d214cd) — TWO engine wins: (1) multi-segment a::b::c() calls were dropped by the resolver pre-filter (leaf never checked) → fixed → +database/profiles.rs; (2) built the routes![]/catchers![] macro extractor — parses handler paths out of the raw token-tree + resolves them via the Rust path resolver → all 4 routes/*.rs handler modules covered. Only lib.rs (crate-root/launch hub, see-through) remains → effectively at ceiling. No control regression, false edges 0, nodes unchanged (edges only).db.send(Msg) → impl Handler<Msg> for DbExecutor) — a DYNAMIC runtime frontier with no static edge (deliberately uncovered, the actix analog of MediatR/reactive runtimes). + glob pub use self::x::* re-export roots. Bridging needs an actor-message synthesizer (dynamic-dispatch feature), not a static fix.bb7659e), penny-bot (real prod, 166 files) 73.2% (serverless/DI, secondary). Import/aggregator confirmed in Swift: controllers via app.register(collection: X()), models via controller queries + migrations. REAL miss found+fixed: a many-to-many pivot model referenced ONLY via @Siblings(through: Pivot.self) (metatype arg in a property-wrapper attribute, not walked) → routed attribute args through extractStaticMemberRef → pivot covered. + faircov excl Package.swift + Public/. penny-bot's lower number = AWS Lambda entries + exports.swift barrels (faircov gaps, ~80% if excluded) + DI/serialization/extension frontiers (genuine); not chased..svelte import resolution ALREADY connects the whole component graph (page→component→lib — verified: imports+references+calls all resolve, e.g. ListErrors←4 pages). Low raw = the file-convention shape: 25/39 files are SvelteKit convention ENTRIES (+page/+layout/+error/+server/hooks — framework-discovered route leaves, no in-repo caller) → excluded in faircov → 14/14 = 100% of the coverable core. ONE framework-mediated gap: +page.server.js load → +page.svelte data (runtime data prop, not static) — bridged with a SvelteKit convention synthesizer (sibling-by-path, like Rocket routes!) — impact-granularity not coverage (both files are entries). BUILT (3ea03e5): svelteKitLoadEdges (callback-synthesizer.ts) links each page → its own-dir loader's load/actions + +layout; 19 links / 0 cross-dir mislinks on realworld, nodes unchanged, regression test (incl. does-not-cross-routes guard).<Route path='/login' component={Login}/>) → App.js imports+references each → all resolve (verified Login/Editor/Profile covered by App.js's route config). Only index.js (CRA entry) + 8 anonymous-default reducers (0 symbols → barrels) excluded. The component-node category is now fully characterized: config-based (React Router, source-referenced → 100% raw) vs file-convention (SvelteKit, path-discovered → fair-100% + synthesizer); the engine handles BOTH as-is. (Modern v6/v7 element={<X/>}/data-router {element, loader} also source-referenced → same.)1dec765) — nuxt/movies (official demo). File-convention component framework (like SvelteKit) but with an AUTO-IMPORT twist that WAS a real miss: Nuxt auto-imports a NESTED component by a DIR-PREFIXED name (components/media/Card.vue → <MediaCard/>), but the node is named Card → the PascalCase usage never resolved. Fixed vueTemplateEdges (match PascalCase tags, not just kebab + a nuxtComponentName map) → +9 nested components. + faircov Nuxt entry exclusions. composables (useTmdb()) already resolved by name-match. 2 residual zeros = genuine frontiers (unused <CarouselItems> + unimported constants/images.ts). KEY contrast: SvelteKit needed NO component fix, Nuxt DID — its dir-prefix auto-import naming is unique. The Vue PascalCase-tag change is gated to .vue files (suite green, false edges 0).*.routing.yml→controller (drupal.ts), PHP class refs. 4 residual zeros all DI/reflection: 2 services.yml services (TreeBuilder/TokenFieldRender), a dynamically-routed controller (TokenDevelController via RouteSubscriber), a field-plugin class. + faircov excl JS libraries + convention entries. Sits with ASP.NET 83.9% / Django 74.1% in the convention/reflection band. LEVERS = drupal.ts TODOs (model services.yml DI → +2 services; plugin annotations; modern #[Hook] attributes) — large per-mechanism features, NOT chased (same stance as ASP.NET/Spring/Django: don't fake 95% via reflection modeling). ← LAST framework; the sweep is complete.main (41 commits) — everything actionable is done. Deferred polish (genuinely optional): C function-pointer dispatch + C++ namespace capture; PHP IFACE_OVERRIDE_LANGS + type-hint disambiguation; Scala wildcard imports; ObjC type refs; engine symlink-dedup (SDWebImage include/ dup file nodes); a convention/reflection lever (Drupal services.yml DI / ASP.NET-Spring reflection modeling — large per-framework features). (Static-member pass for TS/JS/Python is NOT a lever — measured & rejected, e7b86df.)e7b86df) — the long-standing "one big cross-language lever." A/B (extend extractStaticMemberRef to ts/js/python): 0 coverage gain on excalidraw (94.3%→94.3%) AND requests (100%→100%) — in import-based languages a Type.MEMBER read requires importing the type, so the import edge already covers it (the static read is pure duplication) — while adding +1813 edges / +2448 references on excalidraw (the retrieval-perf benchmark), all pointing at already-covered types. Reverted; finding documented in the STATIC_MEMBER_LANGS comment so it isn't re-tried. The deferral was CORRECT — now proven with data.X.FACTORY, JsonScope.X, Foo.class) — the universal deferred data-flow frontier; would lift Java/C#/etc. ~5% more but risks noise. User aware; deferred.getCallers/getCallees edge-kind list to include instantiates/implements/decorates (offered, deferred — changes what "caller" means).Claude: Cloned ripgrep+tokio. Found struct literals (struct_expression) not in INSTANTIATION_KINDS, use bindings not linked, trait methods (function_signature_item) not extracted. Fixed all + added rust to IFACE_OVERRIDE_LANGS. ripgrep 63%→81%, tokio→83%. → commits b538aee, then 2ac7df5 (module-path resolution for pub use self::read::read collisions → ripgrep 87%).
Claude: Verified against tool code → graph-wide; mapped edge-kinds per tool (callers/callees = calls/references/imports; impact/explore = all-but-contains). instantiates/implements/decorates only in impact/explore.
Claude: Found Java annotation gap (usages in modifiers not descended; @interface not in interfaceTypes). Fixed both → gson 78%→85% (commit badb124). On re-push ask: pushed already. On "is it good": fair re-measure showed Java actually 93.3%/94.9% (raw was polluted by package-info/.kt/samples); residual = universal value-read frontier. Concluded Java is good.
Claude: Alamofire already 93%. argparser 84.6% — found property-wrapper gap (@Argument = Swift attribute→user_type, not recognized; Swift instance props not extracted). Extended extractDecoratorsFor + dispatcher branch. Alamofire→95.3%, argparser→96.2%. Commit d111f26. Completes README benchmarked 7.
Saved at commit 529d822 (per-language + RN/Expo campaign).
61a993a→b653688; reconstructed from commits)Measured a canonical real app per README route framework. Import/aggregator frameworks made reachable: Python absolute import a.b.c (61a993a), source-aware from pkg import submodule for FastAPI aggregators (2835623), Django include('app.urls') (58dc463), renamed default-import→module file for Express controllers (2a0b6e0) → Express 100%, FastAPI 98%, Flask/requests 100%, NestJS 96.8%, Gin 96.5%.
Convention/reflection (ASP.NET/Blazor): built a Razor/Blazor .cshtml/.razor markup parser (59b8de2), delegated @code/@{} to the C# extractor (90c5f39), added C# namespace extraction (dc7d033) + Razor @using disambiguation (9e5a951), resolved chained a.b.Method() incl. C# extension methods (4c14413) → eShopOnWeb 59.3%→83.9%, Django→74.1%. Concluded these hit a genuine static-analysis ceiling (markup/reflection); did NOT game the metric to fake 95%.
User: loaded the wrong handoff first (explore-overhaul-bench), asked about per-language coverage %, then switched to this branch to work on impact coverage.
Claude: sourced the coverage table from the impact-coverage-findings memory (corroborated by this handoff's own table); found this handoff committed on the branch + loaded it; flagged the branch had moved 11 commits past the handoff's stated tip; refreshed this handoff to current state (31 commits, route-framework front, fork of next steps; test count re-verified 1178). Then deleted the other 9 handoff files at the user's request, leaving this as the sole handoff.
Outcome: handoff is current + the only one left; awaiting the user's pick of fork (ship / route front / static-member pass).
a3f59fb)User: "unblock spring by fixing the faircov samples bug" → then "yes" to measuring an unmeasured framework.
Claude (Spring): there was NO samples-dir exclusion in faircov (the handoff note was wrong); the real deflation was 5 package-info.java shells (namespace-only → realSyms≠0) sitting in the denominator as zeros. Fixed faircov to barrel-exclude package-info.java/module-info.java. Spring petclinic 65.2%→83.3% (15/18); 3 residual zeros all reflection/DI wiring (@Configuration + AOT hints — verified honest, not missed edges) → convention/reflection ceiling, ≈ASP.NET 83.9%.
Claude (Axum): measured realworld-axum-sqlx → 72.7%, audited zeros → found a REAL engine miss (not a metric issue): bare Rust submodule::fn() calls (X::router() router-assembly) resolved crate-relative only. Fixed resolveRustModuleFile to try self-relative FIRST, then crate fallback; + main.rs/src/bin/*.rs faircov entry exclusion. Axum → 100% (10/10). Clean A/B (same faircov, engine ±fix): axum +2, ripgrep neutral 66/79, tokio +3 → 260/321; cross-family false edges 0; regression test fails without the fix; full suite 1179 green. Committed+pushed a3f59fb.
Outcome: Spring + Axum both measured; the import/aggregator → 95%+ thesis now holds in a 3rd language family (Rust) via a real engine fix, not a metric tweak. Remaining unmeasured: actix/Rocket (attribute-macro routing — likely convention/reflection shape), Vapor, React Router/SvelteKit/Vue-Nuxt, Drupal.
7bb958b)User: "rust frameworks to probe the ceiling" (actix + Rocket).
Claude: measured Rocket (TatriX/realworld-rust-rocket) 62.5% + actix (fairingrey/actix-realworld) 65.4%. Audited zeros → TWO findings. (1) Rocket's 3-segment database::profiles::find() calls weren't becoming edges — isolated via micro-tests to a RESOLVER PRE-FILTER bug (hasAnyPossibleMatch checked first-seg + the b::c remainder, never the leaf), NOT closures or extraction (both fine). Fixed (leaf-name check) → Rocket 68.8%, additive elsewhere, no control regression, false edges 0. Committed 7bb958b + regression test. (2) Remaining ceilings are GENUINE: Rocket's routes![] macro-mounted handlers (bridgeable via a Rocket extractor — deferred, framework-specific) + actix's actor message dispatch (db.send(Msg)→impl Handler<Msg>, a dynamic frontier like MediatR — not bridged).
Outcome: both measured; the "attribute-macro = ceiling" hypothesis was PARTLY right (genuine ceilings exist) but probing surfaced a real generalizable resolver bug that benefits all Rust a::b::c() calls. All Rust route frameworks done. Next options: Vapor / component-node frameworks / Drupal, or build the Rocket routes![] extractor (→~94%).
6d214cd)User: "build the Rocket routes! extractor".
Claude: probed the tree-sitter AST — routes![a::b::h, …] parses as macro_invocation > token_tree of FLAT raw tokens (identifier / :: / ,), so the handler paths were invisible to the call walker. Built extractRustRouteMacro (tree-sitter.ts, called from visitFunctionBody): for a routes/catchers macro, walk the token-tree, group identifier runs between commas into ::-joined paths, emit a references edge each; the existing Rust path resolver (self-relative + multi-segment fixes already shipped) links them to the handler fns. Rocket 68.8%→93.8% (all 4 routes/*.rs covered; only lib.rs root left). No control regression, false edges 0, nodes unchanged (edges only), regression test fails without it. Committed 6d214cd.
Outcome: Rocket effectively at ceiling. Handler names are explicit in source → precise static extraction, not a heuristic. Remaining route-front: Vapor (Swift), component-node frameworks (SvelteKit/React Router/Vue-Nuxt), Drupal — or ship the 34-commit branch.
bb7659e)User: "vapor next".
Claude: measured vapor-til (canonical Vapor tutorial app, kodecocodes) 85.7% + penny-bot (real prod, 166 files) 73.2%. vapor-til zeros: Package.swift (SPM build manifest → faircov excl), Public/cookies.js (static client asset → faircov excl), and AcronymCategoryPivot.swift = a REAL miss. Audited: the pivot model is referenced ONLY via @Siblings(through: AcronymCategoryPivot.self, …) in Acronym/Category — a metatype arg inside a property-wrapper attribute whose ARGS were never walked (only the wrapper type Siblings + the property's declared type were captured). Fix: route the property's attribute-arg subtree through extractStaticMemberRef (already handles Swift Type.self navigation, self-filters to capitalized receivers, skips \.$keypath). vapor-til 94.7%→100%. Clean A/B: vapor-til +1, Alamofire neutral (44/50); false edges 0; suite 1182. Committed bb7659e + regression test. penny-bot 73.2% characterized (serverless/DI: Lambda entries + exports barrels + DI/serialization/extension frontiers) — NOT chased (not the canonical pattern).
Outcome: Vapor DONE; import/aggregator confirmed in a 4th language family (Swift) via a real Fluent fix. Remaining route-front: component-node frameworks (SvelteKit/React Router/Vue-Nuxt), Drupal — or ship the 35-commit branch.
User: "component-node framework next".
Claude: measured sveltejs/realworld (official SvelteKit app) → 35.9% raw (14/39). Audited: ALL 25 zeros are SvelteKit file-convention files (+page/+layout/+error/+server/hooks) — loaded by the framework BY PATH, no in-repo caller. Probed + CONFIRMED the engine already resolves every .svelte component import (ArticlePreview←ArticleList, Nav←+layout, ListErrors←4 pages; imports+references+calls all resolve) — NO component is a zero, so NO engine miss (first framework needing none). Added SvelteKit convention-entry patterns to faircov (methodology-aligned, like route handlers) → 14/14 = 100% fair of the coverable core. Confirmed the one framework-mediated gap: +page.server.js load → +page.svelte data is NOT statically linked (runtime data prop).
Outcome: the component-node shape is "file-convention entries (the majority) + a fully-covered component/lib core" — the engine handles it as-is. No commit (nothing to fix). OFFERED a SvelteKit convention synthesizer (sibling +page.server.js↔+page.svelte link, like Rocket routes!) for impact granularity — not built. Branch stays 35 commits. Next: React Router (config-based variant — likely MORE covered) / Nuxt (file-convention, SvelteKit-like) / Drupal, or ship.
3ea03e5)User: "lets fix svelte with the synthesizer, then we can move onto react router".
Claude: probed the graph: +page.svelte→component node, +page.server.js→load/actions function nodes, pages pair with sibling loaders in the SAME dir. Built svelteKitLoadEdges (callback-synthesizer.ts, wired into synthesizeCallbackEdges after vueTemplateEdges): for each +page/+layout.svelte, link its component → the load/actions in <dir>/<prefix>.server.{ts,js} / <dir>/<prefix>.{ts,js} (same dir only), direction page→load so getImpactRadius(load) surfaces the page; provenance heuristic. Verified on sveltejs/realworld: 19 links, 0 cross-dir mislinks, false edges 0, nodes unchanged; getImpactRadius(login load) now returns login/+page.svelte. Committed 3ea03e5 + regression test (incl. a does-not-cross-routes guard). Suite 1183.
Outcome: SvelteKit fully done (component coverage 100% + the loader→page impact link). Next per the user: React Router (the config-based component-node variant).
User: "...then we can move onto react router" (continued from the svelte synthesizer).
Claude: measured gothinkster react-redux-realworld (38 files, react-router v4/v5) → 100% (29/29), false edges 0. The CONFIG-based component-node sub-shape: route components are NAMED in source (<Route path='/login' component={Login}/>), so App.js imports+references each → all resolve. Verified Login/Editor/Profile covered BY App.js's route config. Only index.js (CRA entry) + 8 anonymous-default reducers (0 named symbols → barrels) excluded. NO engine miss. (Modern v6/v7 element={<X/>} + data-router {element, loader} are also source-referenced → same conclusion.)
Outcome: React Router DONE. Component-node category now fully characterized — two sub-shapes (config-based React Router = 100% raw; file-convention SvelteKit = fair-100% + synthesizer), both handled by the engine. No commit (nothing to fix). Remaining: Nuxt (Vue, file-convention — would mirror SvelteKit), Drupal (PHP), or ship the 36-commit branch.
1dec765)User: "nuxt next".
Claude: measured nuxt/movies (official Nuxt 3 demo, 42 .vue + 37 ts) → 47.6% raw. Audited zeros: pages/app.vue/error.vue/server = file-convention entries (→ faircov Nuxt exclusions); NESTED components (components/media/*, components/carousel/*) = a REAL miss. Root cause: Nuxt auto-imports a nested component by DIR-PREFIX (media/Card.vue → <MediaCard/>), but the node is named Card; the synth vueTemplateEdges only matched KEBAB tags, and the extractor's PascalCase ref name-matched MediaCard→nothing. Fixed: added a PascalCase-tag regex to vueTemplateEdges + a nuxtComponentName map (media/Card.vue→MediaCard, Nuxt dir de-dup). nuxt/movies 47.6%→93.5% (+9 nested components). Vue-only (gated to .vue), false edges 0, nodes unchanged, suite 1183, regression test. Committed 1dec765. 2 residual zeros are genuine frontiers (unused <CarouselItems>, unimported constants). composables (useTmdb()) already worked.
Outcome: Nuxt DONE. The two file-convention component frameworks DIFFER: SvelteKit's imports resolve as-is (no fix), Nuxt's dir-prefix auto-import needed a fix. Only Drupal (PHP) left unmeasured — or ship the 37-commit branch.
User: "drupal to finish the sweep".
Claude: measured the token contrib module (58 PHP, modern Drupal 11) → 57.1% raw. Audited: drupal.ts ALREADY resolves *.routing.yml→controller (TokenTreeController covered via the route ref) and PHP class refs work; the zeros are ALL genuine reflection/convention — JS libraries, DI services (TreeBuilder = @token.tree_builder in services.yml, TokenFieldRender), a dynamically-routed controller (TokenDevelController via RouteSubscriber), plugins (Element/, Plugin/Derivative/), Drush commands, *ServiceProvider, .install hooks, field-plugin MenuLinkFieldItemList. NO simple fixable miss (verified TokenDevelController isn't in any routing.yml — genuinely dynamic). Added faircov Drupal convention-entry + JS-library exclusions → 78.9% fair (4 residual zeros = DI services + dynamic route + field plugin). Token uses modern #[Hook('...')] attribute OOP hooks (a drupal.ts TODO). NO commit (the levers — services.yml DI / plugin annotations / #[Hook] — are large per-mechanism features, same don't-chase-95% stance as ASP.NET/Django/Spring).
Outcome: THE SWEEP IS COMPLETE. Every README framework measured: import/aggregator + config-based-component + file-convention-component reach ceiling (95–100%) via 6 engine fixes; convention/reflection/actor frameworks (ASP.NET/Spring/Drupal/Django/actix) sit at a genuine sub-95% reflection ceiling. Branch 37 commits, ready to ship. Next: open the PR, or the static-member-pass TS/JS/Python lever.
e7b86df)User: "extending the static-member/const value-read pass to TS/JS/Python."
Claude: implemented (added member_expression/attribute to MEMBER_ACCESS_TYPES + ts/js/python to STATIC_MEMBER_LANGS), then ran a clean A/B (same faircov, engine ±change) on excalidraw (TS/React, the retrieval-perf canary) + requests (Python). Result: 0 coverage gain on BOTH (excalidraw 94.3%→94.3%, requests 100%→100%) because the import edge already covers every Type.MEMBER read (in import-based languages you must import the type first — the static read is redundant), while adding +1813 edges / +2448 references on excalidraw (all pointing at already-covered types — pure retrieval-graph noise). REVERTED the functional change; enhanced the STATIC_MEMBER_LANGS comment with the measured finding so it isn't re-attempted. Committed e7b86df (doc-only).
Outcome: the standing "one big cross-language lever" is CLOSED — the deferral was correct, now proven with data. The branch is 38 commits; everything actionable is done. Recommended next: open the PR to main.
2f57119 / 2f30a3b)User: confirmed only 4 README "Full support" languages lacked coverage validation (Lua/Luau/Liquid/Pascal); "knock out those 4 to close it out."
Claude: measured + fixed each. Lua (telescope) 31.6% + Luau (Fusion) 12.5%: NO require() module resolver existed — added resolveLuaRequire (dotted a.b.c→file + instance-path leaf, path-suffix match w/ same-dir preference; confidence 0.9 so it beats the import-node self-match) → Lua 84.2%, Luau 92.2% (4155609). Liquid (Dawn) 39.1%: snippet {% render %} already worked, but Shopify OS 2.0 sections are referenced from JSON templates (templates/*.json "type"), which weren't even indexed — made Shopify JSON indexable (isSourceFile + detectLanguage) + a Liquid-extractor JSON branch emitting sections/<type>.liquid refs (incl. nested templates/customers/) → 73.8% (2f57119). Pascal (PascalCoin) 73.0%: uses-resolution ALREADY worked; added a .dfm/.fmx↔.pas form-code-behind synthesizer → 75.7% (2f30a3b). Each: gated to its language, false edges 0, regression test fails without the fix, suite green (1187).
Outcome: FULL README PARITY — all 22 "Full support" languages + all 14 frameworks now have coverage validation. Branch 41 commits, ready to ship. 3 new generalizable resolvers (Lua/Luau require, Shopify-JSON sections, Delphi form pairing). Only remaining work is optional reflection/DI levers + the PR.