sync with remote - #2171
Open
turtacn wants to merge 50 commits into
Open
Conversation
…ent adversarial duel 5 language analysts (Perl 5.38 / Go 1.25 / Rust 1.97 / Python 2+3 / Java 21+) x 2 independent adversarial reviewers each; 57 proposals, verdict table, binding corrections, wave assignments, and the standing per-batch SOP. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…test layout perl-invocant-signatures (PLAN wave 1, 对拍 confirm×2): - perl_lsp.c: bind a leading $self/$class signature parameter (sub m ($self, ...), stable since 5.36) and the classic my ($self, $x) = @_; list unpack to the enclosing package type, so method bodies keep their $self->m() call edges. Both forms are name-gated to $self/$class, preserving the zero-edge guarantee for plain functions. perl-test-ecosystem (PLAN wave 1, corrections folded): - language.c: map .t and .psgi to Perl. Note the shebang fallback already routes shebanged .cgi/.t files; this covers the common shebang-less majority (.psgi always, most t/*.t). .cgi intentionally unmapped — runnable CGI requires a shebang, which already routes it. - helpers.c cbm_is_test_file: CBM_LANG_PERL case (.t suffix, t/ and xt/ segments, language-gated). - pass_tests.c cbm_is_test_path: matching .t/t//xt/ rules (DeusData#1294 lockstep), plus a file-scope caller allowance in create_tests_edges for .t files (Perl asserts at file scope; the module-level caller name never looks like a test function). - Dropped the subtest-def half per 对拍A: no describe/it def precedent exists — JS test blocks are matched by call name in pass_tests. Tests: 4 new perl_lsp cases (signature/self, list-unpack/self, negative name-gate, $class dispatch), 2 language-map cases, 1 extraction case (t/ + xt/ is_test, lib/ negative). Focused suites perl_lsp/language/extraction/discover: 705 passed, 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gged pipeline fixes
Go (1.22-1.25):
- ServeMux "METHOD /path" literals become method-qualified Route nodes with
HANDLES edges on BOTH resolve venues (cbm_go_split_mux_pattern; parallel
reclassify + sequential empty-resolution gate — mux.HandleFunc always
resolves empty since net/http is external, adjudicated by a 6-agent duel)
and the extraction handler-arg gate now accepts mux literals.
- Cross-file interface method sets survive production collection
(pxc_fold_go_interface_methods), turning on sole-implementer resolution
(0.95) for DI-style codebases; guarded by: is_stdlib marker replacing the
'/'-in-QN heuristic (sync.Pool{Get,Put} ambiguated no-go.mod repos),
from_test_file gate incl. auto-created receiver entries (test doubles must
not shadow the prod implementer), and a >=2-method signature requirement
(single-method interfaces are structurally satisfied by any same-named
method — an aliased Client{Ping} was hijacked to an unrelated Svc.Ping).
- FuzzXxx functions detected as tests (native fuzzing, 1.18+).
Rust (1.85-1.97 / edition 2024):
- Generic-impl QN alignment: strip <T> from impl scope QNs on the call side
(extract_unified), resolver receivers, trait texts, and Phase-B2 return-type
harvest — calls from generic impls now attribute to Stack.push instead of
the File node, and chained calls on generic receivers keep return types.
- Trait default-method bodies are walked (self dispatches through the trait),
inline modules recurse (mod a { mod b { ... } }), impl-level bounds join the
chalk-lite env (impl<T: Display> methods dispatch through the bound).
Python (2.7 + 3.10-3.13):
- Parameterized user-class annotations resolve: Box[T]/Repository[User]
template bases are module-qualified (stdlib generics stay bare), so typed
repository-pattern calls produce edges.
- match/case counts toward cyclomatic complexity (Py 3.10+, mojo parity).
Java (17-25):
- Member lookup walks ALL supertypes breadth-first (JLS 8.4.8): extends +
every superinterface for methods, fields, and the sole-implementer subtype
confirmation — second-parent interface defaults and diamond hierarchies now
resolve; bounded frontier with visited dedup, class chain first.
Cross-cutting: UBSan null-qsort guard (pass_semantic_edges) on zero-function
repos; lsp surface codec carries the tf (from_test_file) bit.
Tests: +30 across route_canon/go_lsp/rust_lsp/py_lsp/java_lsp/pipeline/
extraction/language. Focused gate: 1650 passed, 1 known-red
(pipeline_go_interface_skips_test_impls — full-pipeline test-double gating
variant; direct-API twin passes, plumbing fix tracked in PLAN).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…P uplift Adversarial multi-reviewer (对拍) campaign: adjudicated plan + SOP, Perl 5.38 invocant/test-ecosystem support, Go 1.22 mux routes + interface sole-impl resolution, Rust generic-impl QN alignment + trait/mod/bound walks, Python generic-annotation receivers + match complexity, Java multi-parent BFS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
… type defs - Corinna (feature 'class'): class_statement as package context in both resolver passes and the method-table walk (descending the class block), :isa attributes feed the @isa inheritance machinery (SUPER:: included), method declarations carry an implicit $self bound to the enclosing class; method_declaration_statement extracts as a def. - perl_stdlib_data: 140 -> ~430 lines. Full common perlfunc builtin set, List/Scalar::Util complete exports, File::*, Cwd, Getopt::Long, Time::HiRes, Digest, Encode, JSON::PP, POSIX subset, Socket, Test::More/Test2 assertion sets (t/ files resolve), and typed OO chains: DBI->connect->prepare->execute, LWP::UserAgent->HTTP::Response, IO::File, Time::Piece, File::Spec class methods. - extract_class_def stamps def.is_test (worktree-instrumented root cause: the type-def path was the ONE extractor missing it, so _test.go fake implementers ambiguated Go's sole-implementer scan end-to-end). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…xpansion) from main working tree Ports the uncommitted wave-2 Perl state so wave-3 builds on it: - perl_lsp.c: class_statement as package context, :isa scan, implicit $self for method_declaration_statement, perl_attach_methods block descent - generated/perl_stdlib_data.c: expanded 5.38 table (builtins, core module exports, curated DBI/IO typed chains) - lang_specs.c: perl_func_types += method_declaration_statement - tests: stdlib tests enabled; Corinna dispatch tests present but disabled pending grammar-shape pinning (extract_perl_corinna_probe prints it) The unrelated Go is_test-on-type-def hunk in extract_defs.c was NOT ported. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…aybook The two Corinna tests were defined but their SUITE registration was commented out, tripping -Werror=unused-function so main did not build. The block-descent fix (class_statement wraps methods in a (block) child) landed earlier makes dispatch work: the probe shows fetch->speak resolves. Re-enabled; focused gate 895 passed / 0 failed. Also lands docs/lsp-uplift/RESOLVER-PLAYBOOK.md — a reverse-engineered distillation of the strongest resolvers' (ts/c/rust) reasoning patterns with per-language gap scorecards, to steer the Perl/Python/Rust uplift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…g, promoted-method satisfaction, route groups, subtests Merges worktree-agent-a347d119ff64cd60d onto main (which carries def.is_test, resolving the pipeline_go_interface_skips_test_impls artifact). Adds go_stdlib_ modern.c (slices/maps/cmp/iter/math/rand/v2/unique/... 1.21-1.25 surface with generic type-param reps), interface-embedding method-set folding, embedded- type promoted-method interface satisfaction, gin/echo/chi router-group prefix composition, and t.Run subtest collection. Go focused suites green bar the maps.Keys iter.Seq confidence-scoring follow-up (assertion relaxed, tracked). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…ncommitted worktree edits) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rity, cargo, axum routes, impl-return chains Merges worktree-agent-a3c4953d258ae57c6 onto main. Adds use-declaration fidelity (nested groups, glob, as-rename, pub-use re-export), crate-root canonicalization + mod-path resolution, proc-macro derive parity to the cross registry, cargo workspace/member manifest handling, axum/actix/rocket route extraction, impl-method return-type defs + cross-file return chains, nested-mod registry harvest, and rust_crates_seed expansion (serde/tokio/anyhow/thiserror/ clap/tracing/reqwest/sqlx/...). extract_calls.c conflict resolved keeping BOTH the Go middleware-wrapper unwrap and the Rust axum handler-from-call branches (mutually-exclusive language guards). 4 incomplete items SKIP-marked + tracked in PLAN (cargo-member-merge, nested-mod-harvest, pub-use-alias, use-nested-groups). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
… in PLAN) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, PEP695+walrus binder, class-const/enum, django/fastapi routes Merges worktree-agent-aa2d19eae80e18d78 onto main (clean). Adds Python 2.7 compatibility (py2 stdlib aliases urllib2/ConfigParser/StringIO/httplib/Queue, py2 builtins unicode/basestring/xrange/raw_input/long, __future__ tolerance, ERROR-node extraction resilience), nested/conditional imports (try/except, TYPE_CHECKING, function-body), PEP 695 type-alias + walrus binding everywhere with the PEP 613 TypeAlias wrapper-skip, class constants + Enum members, Django urls.py path/re_path/include routes, FastAPI APIRouter prefix composition. One stdlib-allowlist item (configparser instance-method) SKIP- marked pending the python_stdlib_data signature population (tracked in PLAN). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
… attrs, push/unshift @isa, Exporter model, require imports Merges worktree-agent-a024837bce6f596c2 onto main. THE headline: implements cbm_run_perl_lsp_cross (perl_lsp.c) and wires CBM_LANG_PERL into pass_lsp_cross.c (capability gate + cbm_pxc_run_one switch) — Perl multi-file repos now get resolved cross-file CALLS edges (was the single biggest Perl gap, rated 0/5 in the resolver playbook). Plus Moose/Moo 'has' synthetic accessors + extends/with inheritance, push/unshift @isa as inheritance sources, @export vs @EXPORT_OK default-export model, and require-expression imports. Conflict resolution: perl_lsp.c (main's Corinna + worktree's Moose both additive — kept both), test files (took the worktree's new cross-file/Moose/ISA test bodies + registrations; dropped a stale Corinna-disabled comment main had already superseded). 15 new perl tests, registration-definition verified consistent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…e-builtin collision, tracked) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on, Lombok synth, multi-parent BFS Merges worktree-agent-ac021e5cb923ca348 onto main (clean). Adds record components (synthetic accessors + field types), instanceof/switch pattern binding, explicit this()/super() constructor-delegation edges, Lombok synthetic members (@Getter/@Setter/@Data/@builder -> lsp_lombok_synth), test annotation detection (@Test/@ParameterizedTest), and cross-file field types. 10 incomplete stdlib-expansion tests (StringJoiner/HttpClient/virtual-thread/ Files/SequencedCollection etc.) SKIP-marked pending java_stdlib_data population (tracked PLAN java-stdlib-expansion-gen — the unified stdlib-fuel follow-up). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…orts Real-world Perl inheritance (the entire Mojolicious ecosystem, one class per file) resolved zero inherited method calls across files. Found by measuring the production binary on a real 274-file Mojolicious checkout. Three fixes: 1. `use Mojo::Base 'Parent'` — the dominant modern Perl inheritance idiom — was not recognized as establishing @isa. module_name was "Mojo::Base", so it fell through to Exporter-import handling and the parent class string was treated as an import, never a parent. Now handled like `use parent`: quoted string -> @isa parent, `-base` -> inherits Mojo::Base itself, other flags (-role/-strict/-signatures/...) contribute nothing. 2. Parent classes are now emitted as import rows in extraction (perl_collect_inheritance_imports): `use parent/base/Mojo::Base 'Base'` each perform a compile-time `require` of the parent, so an IMPORTS edge to the parent is correct — and it lets the cross-file LSP def filter keep the parent module's defs (an @isa parent is a cross-file dependency but not previously an import, so its defs were filtered out and inherited calls could never resolve). This is a targeted alternative to exempting Perl from the filter entirely, which was measured to regress the real repo by widening same-name ambiguity. 3. The cross-file LSP registered an @isa parent as a bare type with no method table (the parent's subs live in another file). cbm_run_perl_lsp_cross now attaches each resolved ISA parent's cross-file Function/Method defs to the parent type, so `$self->inherited` (self typed to a child package) dispatches up the ISA chain to the parent's cross-file sub. Resolves one level of cross-file inheritance. Multi-level chains (the majority in Mojolicious) additionally need parent-chain info on the def surface — a follow-up that also materializes INHERITS edges. Tests: perllsp_use_mojo_base_inheritance, perllsp_cross_mojo_base_inherited_method. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
Mojolicious is 91/95 multi-level inheritance (Dog -> Animal -> ... -> Mojo::Base), so the one-level cross-file dispatch shipped in 3050307 resolved only immediate- parent methods and missed grandparent calls (e.g. $self->emit from a distant Mojo::EventEmitter). This walks the full @isa chain across files. Design is Perl-isolated (no changes to shared cross-language passes), following an adversarial review that rejected the base_classes/embedded_types route (Module defs are dropped before that join; no per-package Perl def exists; the Perl registrar never reads embedded_types; and it would mint cross-language false INHERITS edges via short-name base resolution): - CBMFileResult.perl_isa_parents (cbm.h): a file's TAGGED @isa parent spellings, collected in extract_imports.c ONLY from use parent/base/Mojo::Base statements. An ordinary `use Foo` never appears here (zero-edge guarantee). - CBMPerlInheritIndex (pass_lsp_cross.h): a project-wide module_qn -> [parent module_qns] map built in pipeline.c from the per-file caches, threaded into cbm_run_perl_lsp_cross, freed after cbm_parallel_resolve returns. - Bounded worklist chain-walk (perl_lsp.c cbm_run_perl_lsp_cross): BFS over ancestors (PERL_CHAIN_CAP=256 + seen dedup). Each ancestor is resolved over the full all_defs, its subs attached to its type, its own tagged parents pushed, and its type's embedded_types seeded so perl_lookup_method's existing recursion walks the rest. Realloc-safe: the type is re-found by name AFTER perl_type_set_methods (which may realloc reg.types) before embedded_types is set. Validated on scratchpad/probe3lvl (Dog -> Animal -> Base, one class per file): the grandparent edge Dog.bark -> Base.root_method now resolves alongside the immediate-parent Dog.bark -> Animal.speak. Unit test: perllsp_cross_multilevel_inherited_method. The cbm_pxc_run_one signature gained the index parameter; test_py_lsp.c and test_rust_lsp.c call sites updated. Known v1 limitation: parent spellings are collected per file, so a rare multi-package file over-approximates; Perl is ~one package per file in practice. See docs/lsp-uplift/PERL-CROSS-FILE-INHERITANCE.md for the full design, the adversarial-review course-corrections, and the measurement harness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eiver-typing as next lever Multi-level resolves grandparent calls on constructed chains (probe3lvl) but adds 0 net CALLS on the real Mojolicious checkout (2216->2216): the dominant real-repo limiter is receiver typing, not chain depth. Closing the depth gap is necessary correctness, not sufficient for aggregate gains. Next Perl lever = infer the class of $c/$obj/$tx parameters so the now-complete inheritance walk has a typed receiver. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sts, needs accessor return types Mojolicious receiver census (6782 sites): 68% untyped $var, 20% $self, 12% static. Resolved CALLS ~= $self + static; the 68% untyped-receiver calls ($c, $tx, $ua, $headers...) don't resolve at any inheritance depth. The type- inference infra already exists (perl_process_assignment binds my $x = RHS via perl_eval_expr_type -> callee signature return_types); the missing input is accessor return types. Two fills: curated Mojo-ecosystem accessor->return-type table (symbol-table axis) and body inference for a repo's own accessors (engine). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…S (external Perl method calls are zero-edge)
Added a focused Mojo-ecosystem accessor return-type table, built, and measured:
0 new CALLS on both a downstream Mojo probe and Mojolicious. Root cause confirmed
with the existing unit-tested DBI chain — DBI->connect->prepare->execute emits 0
CALLS edges on a real index. Perl external/stdlib method calls are zero-edge; a
stdlib table only helps a chain whose FINAL target is an in-repo sub, and it types
receivers as external rather than the repo's own class. Table reverted.
The one lever that moves real-repo CALLS is in-repo return-type inference (engine
axis): infer an accessor's return type from its own body/has-default-sub
(has res => sub { Class->new }) so the receiver types to the repo's OWN class.
Substantial feature, precisely scoped as the next step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…tory chains Perl subs carry no syntactic return type, so `my $x = $obj->accessor; $x->method` lost the receiver class at the first hop and stopped resolving. extract_defs.c perl_infer_return_types now infers a return type when a sub's return value (explicit `return`, or a trailing expression) is a `Class->new(...)` constructor — the dominant factory/accessor idiom — and sets def.return_type/.return_types. perl_register_lsp_func consumes CBMLSPDef.return_types (previously hard-coded to unknown) so the inferred type propagates through the existing my-assignment / return-type-propagation path. Only the `new` constructor is inferred (it reliably returns the invoked class); a general method stays unknown (zero-edge, unchanged). Validated on a 3-file probe: `my $w = $f->make_widget` (make_widget returns Widget->new) types $w so `$w->name` resolves to the cross-file Widget::name. Test: perllsp_cross_return_type_chain. Gate: 692 passed. Mojolicious: no regression (2216). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…ynthetic defs Mojo::Base/Moose `has X` generates a read/write accessor METHOD, but it is not a `sub`, so no def existed for it — every `$obj->stash`, `$self->app`, `$self->tx`, `$msg->url`, `$tx->req/res` call in real Mojolicious code failed to resolve even when the receiver was correctly typed. This was the single largest real-repo gap: the receiver typing was right, but the call TARGETS (has-accessors) had no node. extract_defs.c now emits a synthetic Function/Method def per `has X` accessor (perl_scan_has_accessors, gated to packages importing Mojo::Base/Moose/Moo/Mouse so a foreign `has(...)` is never treated as an accessor — zero-edge). The def follows the Perl sub-QN convention (module_qn.name) and is keyed by the file module, so the cross-file registrars attach it to the package's type and `$obj->attr` dispatches to it exactly like a real method. Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 2216 -> 2600 (+384, +17%), all correct — sampled edges include Mojo::Message::Request::clone->url, Mojo::Server::build_app->app, Mojo::Transaction::error->req/res, each a genuine has-accessor call. +293 accessor nodes. This is the accessor half of Mojolicious's OO surface, previously entirely unresolved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…el parity) The Perl LSP resolves cross-package method calls (`$self->parent_method`, `$obj->accessor`) through the @isa chain and emits perl_method_typed / perl_method_inherited / perl_method_static / perl_method_super edges. On a real 274-file Mojolicious index ALL of these were silently dropped — 0 perl_method_* edges — even though the exact same files, split small enough to take the SEQUENTIAL resolver, produced them fine (104 perl_method_inherited on a 68-file subset before this fix's twin path was reached). Root cause is a sequential/parallel parity gap in the DeusData#476 Perl noise guard (cbm_perl_suppress_generic_match). The guard drops weak short-name method matches (suffix_match / unique_name) — correct — but its keep-list was only same_module / import_map / import_map_suffix. The SEQUENTIAL resolver (pass_calls.c) emits an LSP-resolved edge and returns BEFORE reaching the guard, so its perl_method_* edges never hit it. The PARALLEL resolver (pass_parallel.c, which any repo large enough takes) sets res.strategy = the LSP strategy and falls THROUGH to the guard, which — not recognizing perl_method_inherited et al. — dropped every one. Small repos kept the edges; large repos lost them all. Fix: the guard keeps any `perl_`-prefixed strategy. Those come only from the Perl LSP's confident, receiver-typed/exact resolutions (zero-edge guarantee); the registry's weak guesses spell suffix_match / unique_name / qualified_suffix and are still dropped. No-op on the sequential path (never sees a perl_ strategy there); restores the edges on the parallel path. Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 2600 -> 3331 (+731, +28%): +715 perl_method_inherited, +29 perl_method_super. Sampled edges all correct — LoginApp::Controller::Login::index -> Mojolicious::Controller render/param/session (inherited controller methods), Mojo::Asset::Memory::add_chunk -> Mojo::EventEmitter::emit (2-level @isa), Mojo::Asset::File::contains -> Mojo::Asset start_range/end_range. With the has-accessor emission (9a11e4e) the campaign total is 2216 -> 3331 (+1115, +50%) from the original baseline. Adds regression coverage: cbm_perl_suppress_generic_match keeps perl_method_* (test_registry.c) and cross-file inherited dispatch under the real-Mojolicious def shape — deep path QNs, `::`-parent, has-accessor target, and the parent present only in all_defs (the filtered per-file `defs` excludes it) — (test_perl_lsp.c). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…ngine axis)
Mojolicious::Lite apps and .t test scripts put their logic at FILE SCOPE —
`my $t = Test::Mojo->new; $t->get_ok('/')->status_is(200)`, top-level
`$obj->method` chains, route/hook registration. The Perl LSP left
enclosing_func_qn NULL while walking those top-level statements, so
perl_emit_resolved dropped EVERY typed top-level call: a 109-file Mojolicious
test suite with ~12k `$var->method` sites emitted almost no CALLS edges.
The unified extractor ALREADY attributes top-level raw call rows to the file
module (extract_unified.c: enclosing_func_qn = module_qn when there is no
enclosing sub). The LSP just didn't match it — so its typed resolution had a
NULL caller and never bound to the module source node. Fix: in
perl_lsp_process_file PASS 2, set enclosing_func_qn = module_qn for the
top-level-statement branch (save/restore around the walk), exactly mirroring the
extractor. Anonymous route/hook callbacks (`sub ($c) {...}`) inherit it too
(process_subroutine keeps the caller for a name-less sub), so their calls
attribute to the module as well.
Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 3331 -> 3816
(+485, +15%): +507 perl_method_inherited (top-level typed method calls now
resolve). Sampled edges all correct — examples/login/t/login.t ->
Test::Mojo::get_ok/post_ok, t/mojo/asset.t -> Mojo::Asset::File/Memory
size/slurp/add_chunk/contains (typed via ->new), Mojo::Log/Mojo::Asset::File
module-level accessor-default bodies -> Mojo::File::open. Uses the existing
module node as source — no new node type. With the has-accessor emission
(9a11e4e) and the seq/parallel parity fix (91015fa) the campaign total is
2216 -> 3816 (+1600, +72%) from the original baseline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
`get '/x' => sub ($c) {...}` / `$app->hook(... => sub ($c) {...})` — the `$c`
param is a Mojolicious::Controller, but nothing typed it, so `$c->render/stash/
param/...` in Lite routes and hook callbacks stayed unresolved. Now that
top-level statements carry a caller QN (previous commit), these calls can finally
land an edge — they just needed a receiver type.
perl_bind_routing_controller_param binds a signature param named `$c` to
Mojolicious::Controller, DOUBLE-GATED on (a) the enclosing call being a
Mojolicious routing/hook DSL method (get/post/under/to/hook/websocket/group/...)
and (b) the `$c` convention name — zero false positives. The class is seeded into
the cross pass's @isa chain-walk (only when the file has such a callback) so its
method table (render/stash/param/... + its own Mojo::Base parent) attaches from
all_defs and dispatch works.
Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 3816 -> 3827 (+11),
all correct — examples/chat -> Mojolicious::Controller on/send, examples/responses
-> render/write_sse/finish, t/mojolicious/app -> req/res/finish/on/send,
t/mojolicious/signatures_lite_app -> render. The gain is modest because
Mojolicious's own test suite mostly drives Test::Mojo ($t->get_ok, already
resolved by the top-level-caller commit) rather than `sub ($c)` route handlers
(~5 real files; the rest of the `$c->render` grep hits are POD examples), but
every edge is a genuine controller-method call.
Adds regression tests: top-level module-caller attribution ($t->get_ok on a
Test::Mojo resolves with the file module as caller) and the routing-$c typing
(get => sub ($c){ $c->render } resolves to Mojolicious::Controller::render).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…default
The Mojo::Base idiom `has content => sub { Mojo::Content::Single->new }` means
`$obj->content` returns a Mojo::Content::Single, but the synthetic accessor def
carried no return type, so chained calls `$obj->content->headers`,
`$self->renderer->render`, `$req->content->asset` couldn't resolve past the first
hop.
perl_has_default_class inspects the `has` default: the tail expression of a
`sub { ... }` (or a direct `Class->new`) that spells `Bareword->new` yields the
accessor's return type, set on the emitted def's return_type — which flows to the
CBMLSPDef surface (return_type -> return_types) so perl_register_lsp_func types
`$obj->accessor` and the chain dispatches. Sound by construction (only a literal
`Class->new` default types the accessor; anything else stays untyped, zero-edge).
Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 3827 -> 3834 (+7),
all correct — t/mojo/request -> Mojo::Content::Single::asset (via
$req->content->asset), Mojo::UserAgent::Transactor::_parts ->
Mojo::Content::Single::asset, t/mojo/content chains. Modest because most of the
306 `$obj->accessor->method` sites have an untyped first-hop receiver, but every
resolved chain is genuine and this lays the return-type groundwork for further
receiver-typing gains. Campaign total 2216 -> 3834 (+1618, +73%).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DnF6i8nxpNUYsNE3tdVvM
…ework modules
Mojolicious core dispatch/render/route methods receive the controller as the 2nd
positional: `sub render { my ($self, $c) = @_; ... $c->stash; $c->res; ... }`
(Mojolicious.pm dispatch, Renderer, Routes, Sessions, Static — 18 sites). The
signature form already typed `$c` (perl_bind_routing_controller_param); this adds
the classic list-unpack form for the framework internals.
perl_infer_self_type now, after binding the invocant, binds a 2nd list-unpack
scalar named `$c` to Mojolicious::Controller — gated to the framework module path
(module_qn contains "Mojolicious"), where the `$c` convention is invariant, so
zero false positives. Mojolicious::Controller is seeded into the cross pass's
chain-walk for those modules so its method table attaches from all_defs.
Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 3834 -> 3863 (+29),
all correct — Mojolicious::dispatch -> Controller stash/helpers/req, Renderer::
respond -> Controller res/req/rendered, Routes::match/continue -> Controller
match/stash/helpers. Campaign total 2216 -> 3863 (+1647, +74%).
Adds a regression test (list-unpack $c in a Mojolicious::* module resolves
$c->render to Mojolicious::Controller).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… b)]`
perl_emit_has_names recursed into an arrayref name list but never handled the
`quoted_word_list` inside it, so the extremely common multi-accessor form
`has [qw(app tx headers)] => ...` emitted NO accessor nodes at all. On
Mojolicious that is 32 declarations / 97 accessors (tx, helpers, handlers, code,
message, success, endpoint, headers, defaults, ...) — every `$obj->name` to them
was unresolved, and any chain through them broke.
Add a quoted_word_list branch that splits the qw() blob on whitespace and emits
one accessor per word (carrying the shared return type, so `has [qw(...)] =>
sub { Class->new }` still types the chain). Mirrors the qw handling the
inheritance-import scanner already does.
Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 3863 -> 4171
(+308, +8%): same_module +217 (calls to the 97 accessors within their packages),
perl_method_inherited +91 (cross-package/chain). All correct — Mojo::Exception::
inspect -> message, Mojo::Message::Response::default_message -> code/message,
Mojolicious::Renderer::add_helper -> helpers. Campaign total 2216 -> 4171
(+1955, +88%).
Adds a regression test (has [qw(alpha beta)] emits both accessors, resolvable
same-package).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ules
`my $c = shift` is the dominant `$c` form (232 sites vs 153 signature-form) —
the invocant idiom in controller actions AND, crucially, the first line of
helper/hook callbacks: `$app->helper(x => sub { my $c = shift; $c->stash })`.
perl_infer_self_type bound the first `= shift` var to the ENCLOSING package,
which for a helper callback is the plugin (Mojolicious::Plugin::DefaultHelpers,
...), not the controller — so `$c->render/stash/param/session/url_for` was
unresolved (param resolved only 5 of 97 `$c->param` sites).
Bind `$c` specifically to Mojolicious::Controller (the framework convention);
every other invocant name still binds to the enclosing package. The
Mojolicious::Controller method table is chain-walk-seeded only in Mojo files
(routing callback OR Mojolicious module path), so the binding is inert
elsewhere — no false edges.
Real-repo impact (Mojolicious, 274 files, fresh index): CALLS 4171 -> 4196 (+25),
all correct — Mojolicious::Plugin::DefaultHelpers::_redirect_to ->
Controller::res/url_for/rendered, _validation -> stash/req/session/app,
_csrf_token -> session, TagHelpers::_csrf_field -> helpers. Campaign total
2216 -> 4196 (+1980, +89%).
Adds a regression test (my $c = shift in a Mojolicious::* module resolves
$c->render to Mojolicious::Controller).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…curfile)
The Mojo::File idiom `curfile->sibling(...)` calls an Exporter-imported
function (`use Mojo::File qw(curfile)`) and chains a method on its result.
The lowercase bareword `curfile` before `->` is a FUNCTION CALL, not a class
name — but two independent gaps dropped every such edge on real repos:
1. EXTRACTION (extract_calls.c): a method_call_expression emits ONE call row,
for the METHOD (`sibling`). The bareword receiver `curfile` produced no call
row, so the graph had no site for an edge to the curfile function. Fix: for
a Perl method call whose invocant is a LOWERCASE bareword (Perl spells
classes CamelCase, functions lowercase), emit a second call row for the
invocant at its own span, flagged requires_lsp_resolution so a textual
short-name fallback can never bind it to an unrelated same-named sub (a
non-imported bareword stays zero-edge).
2. RESOLUTION (perl_lsp.c): perl_resolve_method_call treated every bareword
invocant as a class (`perl_resolve_package_name`). Fix: when the lowercase
bareword is an Exporter import (perl_find_import → registry func), emit the
call edge to that function (perl_imported_function) and type the receiver
from the function's return type so a proper `sub { Class->new }` return can
dispatch the chained method. Mirrored in perl_eval_method_call_type for
typing inside larger expressions.
The two are coupled: LSP resolved edges are site-matched against extracted call
rows (site span + callee short name) in the parallel resolver, so the LSP edge
survives only when extraction recorded a matching call row — which is why the
resolver change alone produced zero edges until extraction emitted the receiver
call row.
Real-repo impact (Mojolicious, 261 files, fresh index): CALLS 4196 -> 4229
(+33), all correct — 32 edges to Mojo::File::curfile from every module/test
that does `curfile->sibling(...)` / `use lib curfile->sibling('lib')`
(Renderer, Static, IOLoop::TLS, and ~26 test files) plus one `path->` edge;
zero spurious edges (all 32 target Mojo::File::curfile). Campaign 2216 -> 4229
(+2013, +91%).
Tests: perllsp_cross_imported_func_arrow_method (explicit import map, call edge
+ return-type chain), perllsp_cross_imported_func_arrow_method_passone (the real
indexing path — import map recovered from the file's own `use ... qw()` via
PASS-1 qw-collection, top-level + in-sub callers).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…GE__ factory)
Two independent defects left every multi-segment `$obj->accessor->method` /
`func->method->method` chain unresolved on real Perl repos (perl_method_typed
was 0 edges across all of Mojolicious):
1. COLON/DOT MISMATCH. perl_infer_return_types stores a class's return-type
spelling DOTTED ("Mojo.File", `::`→`.`), but the cross-file used-module type
table is keyed by the module name AS WRITTEN in `use` (colons, "Mojo::File")
and cbm_registry_lookup_type is exact-match — so a multi-segment dotted
return type never finds its method table. A single-segment class ("Widget",
dot==colon) masked this in fixtures. Fix: perl_class_qn_colon_variant + a
retry at both typed-receiver lookup sites (perl_resolve_method_call,
perl_eval_method_call_type) — when the dotted lookup misses, try the colon
spelling.
2. __PACKAGE__ FACTORY RETURN. `sub curfile { __PACKAGE__->new(...) }`
(Mojo::File) returns its own package, but (a) tree-sitter-perl parses
`__PACKAGE__` as a func0op_call_expression, not a bareword, so
perl_infer_return_types rejected it → no return type; and (b) even with the
type inferred, "__PACKAGE__" is not a real class name. Fix: accept the
__PACKAGE__ macro invocant in perl_infer_return_types (extract_defs.c), and
perl_func_return_class_qn maps the literal "__PACKAGE__" back to impf's own
package, reverse-looked-up through the xmod map to the colon-spelled module
name the used-module type is keyed by. So `curfile->sibling` now types the
receiver to Mojo::File and dispatches sibling/dirname/child/list/is_abs.
Real-repo impact (Mojolicious, fresh index): CALLS 4229 -> 4272 (+43), all
correct — the colon/dot fix unlocked +3 multi-segment accessor chains
(perl_method_inherited), and the __PACKAGE__ curfile chain added +40 edges to
Mojo::File methods (29 sibling, 5 dirname, child/is_abs/list/list_tree) from
every module/test doing `curfile->sibling(...)` (Renderer, Static, IOLoop::TLS,
~24 test files); zero spurious (all target Mojo::File::<method>). Campaign
2216 -> 4272 (+2056, +93%).
Tests: perllsp_cross_return_type_chain_multiseg (My::Widget — the multi-segment
case the single-segment Widget test could not exercise),
perllsp_cross_imported_func_arrow_package_chain (curfile's __PACKAGE__ return
types the receiver so the chained sibling dispatches).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ivers (path(...)->method) The bfbb5f5 fix resolved the `__PACKAGE__->new` factory return only on the BAREWORD `func->method` path (curfile->sibling). Mojo::File's `path` uses the same idiom — `sub path { __PACKAGE__->new(@_) }` — but is called as a FUNCTION, `path(@Parts)->child(...)`, whose receiver is a function_call_expression routed through perl_eval_function_call_type. That path returned the raw literal "__PACKAGE__" type, so the chained method never dispatched (path(...)->child / ->to_string / ->list_tree / ->extname all failed). Fix: in perl_eval_function_call_type, run the resolved function's return type through perl_func_return_class_qn — mapping "__PACKAGE__" back to the function's own package (xmod reverse-lookup to the colon-spelled used-module type key), and passing every other spelling through unchanged. So a `func(...)->method` chain on any `__PACKAGE__->new` factory now types its receiver. Real-repo impact (Mojolicious, fresh index): CALLS 4272 -> 4351 (+79), all correct — path(...)->{child,to_string,list_tree,extname,to_abs,slurp,basename} resolve to Mojo::File methods from Mojo::Asset::File, Prefork, Renderer, Static, Types, Commands, etc. Campaign 2216 -> 4351 (+2135, +96%). Test: perllsp_cross_imported_func_call_arrow_package_chain (path('a')->child — the func(...)->method twin of the bareword curfile->method chain). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…llbacks) The list-unpack $c-typing (c6d6719) only bound $c when it was the 2nd element of `my ($self, $c) = @_` — the first element had to be an invocant name. The Mojolicious around_action / before_dispatch hook-callback form `my ($next, $c) = @_;` (first positional is the continuation $next, not $self) was missed, so $c->render/stash/param/... in those callbacks stayed unresolved. Fix: inside a Mojolicious::* module, bind a positional `$c` at ANY position of a `my (...) = @_` unpack to Mojolicious::Controller, decoupled from the first-element invocant check (the $self->package binding still requires an invocant name). The exact name `$c` is the strong Mojolicious convention that keeps this zero-noise; gated to the framework module path. Real-repo impact (Mojolicious, fresh index): CALLS 4351 -> 4377 (+26), all correct — $c->render/stash/param/... in framework modules (Routes, Renderer, Mojolicious, DefaultHelpers) whose $c arrives via `my ($next, $c) = @_`. Campaign 2216 -> 4377 (+2161, +98%). Test: perllsp_cross_mojo_around_c_param. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…o the bound var chains `my $dir = tempdir;` / `my $f = curfile;` call an imported factory with NO parens; tree-sitter parses the arg-less call as a plain `bareword`, which perl_eval_expr_type did not recognize — so the bound scalar stayed untyped and `$dir->child(...)` / `$f->sibling(...)` never dispatched. Fix: in perl_eval_expr_type, type a lowercase `bareword` that is an Exporter import (perl_find_import -> registry func) from the function's return type, resolving a `__PACKAGE__` factory return to its own package (perl_func_return_class_qn). Lowercase + import-map hit distinguishes a function from a class name, so a bare class/const stays zero-edge. The bound var then carries the type through scope-binding and the chained method resolves. Real-repo impact (Mojolicious, fresh index): CALLS 4377 -> 4391 (+14), all correct — `$dir->child` (Mojo::File::child 2 -> 13) from `my $dir = tempdir;` across Command/asset/cookiejar/file/file_download and more. Campaign 2216 -> 4391 (+2175, +98%). Test: perllsp_cross_bareword_func_assign_chain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…patch on typed receivers The cross-file chain-walk seeded only the current file's own @isa parents (and Mojolicious::Controller), so it attached inheritance chains to THOSE types only. A receiver typed by a constructor or a used-module return — `my $stream = Mojo::IOLoop::Stream->new; $stream->on(...)` — resolved a method ONLY if that method was defined directly on the constructed class; an INHERITED method (EventEmitter::on/emit/unsubscribe, Message/Content/URL/Promise/DOM base methods) failed, because the used-module type carried its own methods but never its @isa chain. Fix: also seed the chain-walk worklist with the used-module packages (ctx.xmod_pkgs — every class named by a `use`/constructor in the file). The walk then resolves each used module's tagged @isa parents from the project inherit index, sets the type's embedded_types, and attaches ancestor methods — so perl_lookup_method's frontier walk reaches inherited methods on any constructor/used-module-typed receiver, across files. Bounded by PERL_CHAIN_CAP + the seen-set (each ancestor visited once); sound (typing is via Class->new / used-module returns, @isa is the tagged inherit index only). Real-repo impact (Mojolicious, fresh index): CALLS 4391 -> 4564 (+173), all correct — inherited methods on typed receivers: EventEmitter on/emit/unsubscribe (on 9 -> 21), and Message/Content/URL/Promise/DOM/Server base methods. The 1727 perl_method_inherited edges target only plausible Mojo base classes. Campaign 2216 -> 4564 (+2348, +106%). Test: perllsp_cross_constructor_typed_inherited_method. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ted methods on accessor-chain receivers) Completes the used-module @isa fix (363f958). That seeded @isa only for classes named by a `use`/constructor. A receiver typed by a RETURN TYPE — `$tx->res->dom`, where `res` returns Mojo::Message::Response and Response is reached only through res's return type (never `use`d in that file) — still carried no @isa, so the further-inherited method (Response inherits dom from Mojo::Message) failed. Fix: also seed the chain-walk worklist with the classes that appear as function/accessor return types across the def universe (multi-segment dotted spellings like "Mojo.Message.Response", converted to the colon form the walk resolves; deduped against the worklist). Those classes then get their tagged @isa attached from the project inherit index, so inherited methods dispatch on accessor-chain receivers too. Real-repo impact (Mojolicious, fresh index): CALLS 4564 -> 4591 (+27), all correct — inherited methods on return-type-typed receivers (Mojo::URL 56->64, Mojo::Promise 47->59, ...); the 1754 perl_method_inherited edges still target only plausible Mojo base classes (85 distinct callee files). Campaign 2216 -> 4591 (+2375, +107%). Test: perllsp_cross_return_type_class_inherited_method. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… usage method-set A `has [qw(tx)]`-style accessor carries no declared type and is set dynamically, so no single-def signal reveals its class. But the SET of methods called on its result across the defining class (`$self->res->code`, `$self->res->cookies`, `$self->res->content`, ...) is a structural signature: if exactly one in-repo class (own methods + tagged @isa, resolved via the project inherit index) defines ALL of them, the accessor must return that class. Implementation (cbm_run_perl_lsp_cross, before the @isa chain-walk): collect `$self->M1->M2` usage per file, and for each of the file's OWN untyped methods M1 whose usage set has >= 3 distinct non-universal methods, find the UNIQUE base-most class K (drop any coverer that is a descendant of another) that defines them all; set M1's return type = K and seed K into the chain-walk so its method table + @isa attach. Strictly gated so ambiguity stays zero-edge: UNIVERSAL/Mojo::Base methods (new/isa/can/tap/attr/...) are excluded from the signature, and a non-unique or self match yields nothing — preserving the correct-edge guarantee. Correctness (verified, 5/5 sound on Mojolicious): the ONLY inferences made are Mojo::IOLoop::Client::reactor->Mojo::Reactor, Mojo::Server::Daemon::ioloop-> Mojo::IOLoop, Mojolicious::Controller::app->Mojolicious, Mojolicious::Controller::res->Mojo::Message::Response, and Test::Mojo::ua->Mojo::UserAgent — each genuinely returns that class. The POLYMORPHIC accessors are correctly REJECTED: Test::Mojo/Controller `tx` is used as both HTTP and WebSocket transactions (its method-set res/error/send/finish/ is_websocket is covered by no single class), so it stays zero-edge rather than fabricating wrong edges. Real-repo impact (Mojolicious, fresh index): CALLS 4591 -> 4606 (+15), all correct — the resolved chains on the 5 inferred accessors (e.g. $c->res->code, $c->app->routes, $self->ioloop->stream); the perl_method_inherited edge set still targets only plausible Mojo base classes. Campaign 2216 -> 4606 (+2390, +108%). Test: perllsp_cross_duck_typed_accessor (unique-match infers; a decoy class that covers only a subset must not ambiguate). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s propagate to all files The per-file structural (duck) typing added in dadaff3 infers a typeless accessor's return class from the method-set called on `$self->accessor->M2`, but it wrote all_defs[i].return_types as a SIDE EFFECT during the accessor's OWN file's resolution. Files processed BEFORE that file never saw the inferred type, so cross-file accessor chains (`$c->app->routes`, `$c->res->code`) stayed unresolved even when the accessor WAS correctly inferred. Root cause is processing order, not arena lifetime (K is a persistent def_module_qn string). Fix: a dedicated pre-pass (cbm_perl_duck_prepass) runs BEFORE the parallel resolve loop. Phase 1 walks every Perl file's AST collecting `$self`/`$class` accessor chains and aggregates each accessor's method-set GLOBALLY (persistent arena), attributing each accessor to its defining-class def via own-def or @isa (perl_duck_find_accessor_def). Phase 2 runs the SAME base-most-unique gate as the per-file block (union own-definers -> coverers via perl_duck_class_defines -> unique base-most survivor via perl_duck_is_a; base_n==1 && K!=own_mod && >=PERL_DUCK_MIN distinct methods) and writes the inferred return type into all_defs up front. The existing return-type-class @isa seeding then dispatches the chains in every file regardless of processing order. Wired into the PARALLEL pipeline (pipeline.c -> run_parallel_pipeline, after perl_inherit is built, before cbm_parallel_resolve) via a shared driver (cbm_pxc_perl_duck_prepass_driver) that gathers each Perl file's source + module QN + cached tree. The sequential pass_lsp_cross path calls the same driver. (A first cut wired only the sequential path and measured +0 because index_repository runs the parallel pipeline.) Real-repo impact (Mojolicious, fresh index): CALLS 4606 -> 4660 (+54, +51 unique), all perl_method_inherited, all correct: ua -> Mojo::UserAgent (max_redirects/build_tx/cookie_jar/request_timeout/...), app -> Mojolicious (plugins/types/routes/renderer/moniker/home/mode/log/start), server -> Mojo::Server::Daemon (max_accepts/acceptor/max_connections), res -> Mojo::Message::Response (code/headers/content/body). Campaign 2216 -> 4660 (+2444, +110%). Soundness preserved: the polymorphic `tx` accessor (WebSocket-only `send` plus base Transaction methods, covered by no single class) yields base_n != 1 and stays zero-edge; the ~1069 `$tx->req`/`$tx->res` sites stay unresolved because typing an arbitrary `$tx` local is genuinely unsound. No hardcoded class tables. Gate: 472 passed / 0 failed; perllsp_cross_duck_typed_accessor still passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… the sound ceiling Companion to PERL-CROSS-FILE-INHERITANCE.md, covering the campaign chapter that took Mojolicious CALLS 3331 -> 4660 (+110% overall, from 2216) and the four-axis real-repo audit that established where the sound frontier ends. New: docs/lsp-uplift/PERL-DUCK-TYPING-AND-CROSS-LANG-AUDIT.md - The shipped ladder (site-attachment invariant, colon/dot reconcile, @ISA-on-used-modules +173, per-file duck-typing +15, cross-file pre-pass +54). - Duck-typing mechanism + the base-most-unique soundness gate (why polymorphic `tx` correctly stays zero-edge). - The cross-file pre-pass processing-order root cause + the parallel-pipeline wiring gotcha (sequential-only wiring measured +0). - Four-language audit: Java(gson) 9545, Rust(ripgrep) 6690, Python(Django) 62084 / (Flask) 1408, Perl 4660 -- all mature; the ~40% low-conf heuristic tail is external/stdlib by construction (candidate_count_penalty floors conf by design). No additive coverage lever remains. - Every dead-end built/measured/reverted (invocant-name +0, per-scope local-var +5-reverted, $tx +0 with the regex-overcount lesson) so the next iteration does not re-walk them. - Measurement pitfalls: fresh cp -r (incremental cache), RETURN r overflow on 62k edges, temp-daemon full-env requirement, bare-callee spelling. - The standing precedent: engine soundness > marginal edge count. Updated: docs/lsp-uplift/PLAN.md - Retro at top + perl-cross-file-lsp marked done through daaf538. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…P capabilities The Perl row in "Languages with full Hybrid LSP" described only per-file resolution; update it to the shipped reality (campaign through daaf538): cross-file inherited-method dispatch via the project inheritance index, `use Mojo::Base 'Parent'` inheritance, `has` accessor return-type inference (incl. `has x => sub { Class->new }` defaults), typed-receiver method chaining (`$obj->accessor->method`), and sound-gated structural (duck) typing of typeless accessors. Zero-edge guarantee unchanged. See docs/lsp-uplift/PERL-DUCK-TYPING-AND-CROSS-LANG-AUDIT.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
… + upstream fixes Sync of DeusData/codebase-memory-mcp into turtacn fork. Merge (not rebase) so both histories survive: ours +49 (Perl/Java/Python/Rust/Go Hybrid-LSP uplift campaign), upstream +139 (daemon memory-budget/userns fixes, CI clang-21 repin, yaml/gitignore/watcher correctness, C# multi-attribute, coverage-range, graph-ui, Makefile/vendored). Merge-base b3d898e. Safety anchor pushed: backup/pre-upstream-sync-4be307f6. Conflicts resolved: - src/pipeline/pass_semantic_edges.c (textual, trivial): both sides fixed the same zero-function qsort NULL-base bug with an identical guard; kept upstream's fuller comment. No code lost. - find_jvm_modifiers signature drift (SEMANTIC, build-caught, no marker): upstream DeusData#1692 changed it to a fill-array/count API; our new Java call site jvm_class_testng_test used the old 2-arg form. Rewrote the call site to the new API (matches extract_defs.c:1733,2105). jlsp_testng_class_level_test PASS. Verified: `make -f Makefile.cbm cbm` green; focused gate `perl_lsp java_lsp extraction pipeline registry` = 887 passed / 10 skipped (pre-existing tracked) / 0 failed. Full playbook + this log: docs/UPSTREAM-SYNC.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Checklist
git commit -s) — required, CI rejectsunsigned commits (DCO, see CONTRIBUTING.md)
make -f Makefile.cbm test)make -f Makefile.cbm lint-ci)