Repository navigation
Code Analysis Go Rust Investigation Batch
Draft, not merged: #1290, head 021a3898a, base codex/go-rust-batch-baseline (70bdf0227, merge of Go #1285 and Rust #1288). Review order: #1289 merges both baselines; this PR targets that merged branch. Started from the reviewed head ac36a4ab0. No merge, no labs/code-analysis update, no live installation.
This stage reproduces and fixes a wrong Rust target, extends generic field receivers and defaulted owner methods, keeps Go interface evidence for external embedded methods, and re-runs the same 20 real questions on both revisions. Every number below comes from the same query set, sample roots and call positions.
On real Go and Rust changes, does the normal change query answer four things: which definition changed, who directly calls it, which calls only prove an interface/trait declaration, and where can the reader verify the call in source?
| Line | Commit | Meaning |
|---|---|---|
| Batch base | 70bdf0227 |
merge of Go #1285 and Rust #1288 |
| Reviewed head / stage baseline | ac36a4ab0 |
Rust v7 / adapter 7, Go v3 / adapter 6 |
| Candidate | 021a3898a |
Rust v8 / adapter 8, Go v4 / adapter 6 |
Remote state was re-checked at the end of the stage: #1290 Draft, base #1289 still at 70bdf0227 and unmerged; origin/labs/code-analysis still bf0a29e76 (2026-11-04); origin/main advanced only with DSH docs (#1291/#1294) and has no archify/modules/code-analysis change since branch point 654da74e0.
Sample trees are independent git worktree checkouts at fixed base/head commits. No project build or test was executed. Go used Go 1.27.2, default GOOS/GOARCH, cgo disabled. clap, tracing, ripgrep and bytes were read with a generated Cargo.lock because the extractor uses --locked.
Twenty cases and 86 expected call positions: the earlier 12 (still exactly 73 positions, unchanged) plus 8 new/frozen cases (13 positions). New repositories relative to the 12-case batch: spf13/cobra, labstack/echo, urfave/cli, BurntSushi/ripgrep, tokio-rs/bytes. Thirteen new base/head groups plus two regression groups; two questions from one pair count once.
| Group | Cases |
|---|---|
certmagic 16c9db14→1a2275d5
|
certmagic-load, certmagic-store |
certmagic 2d114193→9a56fcd4
|
certmagic-interface, certmagic-interface-load (reserved Go) |
gin 8d0468f7→d75fcd4c
|
gin-close, gin-hijack |
clap b55ebc9f→67202405
|
clap-any-value-parser, clap-typed-value-parser (reserved Rust) |
tracing d3eb109e→f42e7e6d
|
tracing-layer-event-enabled, tracing-subscriber-event-enabled |
raft d3c91249→a2e87783
|
raft-stage-commit-index |
cobra f2878bab→746ef071
|
cobra-get-completions |
echo 4f7bea5d→29682401
|
echo-remove-custom-method (reserved Go) |
cli d854bb40→ca8f45a9
|
cli-wrap-line |
ripgrep 4c2362d3→7155f640
|
ripgrep-file-name |
ripgrep 1752fb78→6892bc2b
|
ripgrep-parent-key |
bytes 002df10b→d5c8ad32
|
bytes-truncate-zero (reserved Rust) |
bytes d5c8ad32→7930d93d
|
bytes-try-get-int |
http c6af28b→3dd9f5e
|
http-insert-occupied-mult (regression) |
rust-base64 a8a60f43→9e9c7abe
|
base64-inner-decode (regression) |
Reserved answers were frozen by reviewers reading only upstream source/diff, before any candidate run. echo-remove-custom-method and bytes-truncate-zero matched other frozen keys.
| Scope | Definitions | Baseline found/wrong/missed | Candidate found/wrong/missed/extras |
|---|---|---|---|
| All 20 cases | 20/20 | 66/1/20 | 78/0/8/2 |
| Go (10) | 10/10 | 57/0/5 | 62/0/0/0 |
| Rust (10) | 10/10 | 9/1/15 | 16/0/8/2 |
| New (14) | 14/14 | 47/1/18 | 58/0/7/1 |
| Regression (2) | 2/2 | 4/0/1 | 5/0/0/1 |
| Reserved Go (2) | 2/2 | 14/0/0 | 14/0/0/0 |
| Reserved Rust (2) | 2/2 | 1/0/1 | 1/0/1/0 |
+13 correct call positions, 1 wrong target removed, missed positions 20 → 8, no previously correct hit lost. Target display moved from 15 determined / 51 candidate / 0 unknown to 16 / 57 / 5; every candidate still carries runtimeTarget: "not-determined". The two extras are source-verified real calls omitted from the frozen keys, not false targets: base64 src/read/decoder.rs:146 calls through E: Engine; tracing tracing-subscriber/src/layer/layered.rs:295 calls through B: Layer<S>.
Remaining misses: clap type-erased parser and ok! argument (2), bytes default-method and &mut B forwarding (2), tracing macro body/closure/try_lock! (3), tracing feature!-gated fmt/mod.rs (1). None points at a wrong target.
fixtures/rust-local-asref is a cargo-checkable pair with a local trait AsRef<T> whose as_ref returns &Other and Wrap: AsRef<First>. The test proves rustc dispatches self.as_ref().enabled() to Other::enabled.
| Query |
ac36a4ab0 (v7) |
Candidate (v8) |
|---|---|---|
change Other::enabled
|
0 references | 2: src/lib.rs:32:9, 37:5 → line 11 |
change First::enabled
|
1 false reference: 32:9 → First::enabled:5
|
0 references |
The extractor now records trait method return hints, substitutes impl arguments, prefers a captured inherent accessor, accepts Deref::Target, and trusts std/core/alloc pointer semantics or aliases only when the path is proven. Otherwise the receiver stays unknown. Tests cover local same-name traits, std paths, aliases, inherent shadowing, Borrow/Deref, unresolved evidence, and renamed/swapped parameters.
-
Defaulted and unsupported generic owners. Impl where-clause bounds and default type parameters are recorded. Structs whose declarations cannot be modelled (defaults, where clauses, lifetimes) expose fields through
Binding::Fields, soHeaderMap<T = u8>andLayered<L, I, S = I>field receivers resolve. Tuple-variant bindings and inherent methods on defaulted owners resolve; direct-caller kind distinguishesfunction,methodandtrait-default-method. -
Go external embedded interfaces.
interfaceCompleteno longer rejects an interface because it embeds an external named interface. go/types still proves the implementation relation; the edge names the external package and method, and the query emits a candidate at each unresolved call site with no target and an explicit reason. Evidence modelcaptured-interface-implementations-v2;go-source-direct-v4/ revision 6. -
Coverage gates. v4/v8 models are accepted by the shared semantics, call-question and change-question gates; the schema accepts external interface edges and the
go-interface-external-methodreason.
-
Go, echo:
*routeMethods.setatrouter.go:226→ direct callrouter.go:860:2in(*node).setHandler(line 859), determinedgo-direct-method. The nil-producing(*DefaultRouter).Removecall atrouter.go:446is one indirect hop away; the tool does not expand transitive callers. -
Rust, bytes:
Bytes::truncateatsrc/bytes.rs:569→self.truncate(0)atsrc/bytes.rs:599:9inBytes::clear(line 598),rust-inherent-source-candidate. -
Go, gin interface:
*responseWriter.Hijackatresponse_writer.go:111→ test calls atresponse_writer_test.go:120:20,190:23,245:23; three interface candidates with no concrete target because the static method is externalnet/http.Hijacker.Hijack. -
Rust, AsRef:
Other::enabledat the fixturesrc/lib.rs:11←32:9,37:5; the baseline path pointed atFirst::enabled:5.
-
echo-remove-custom-method(reserved Go) matched exactly: definitionrouter.go:226, call860:2, callersetHandler:859method. -
bytes-truncate-zero(reserved Rust) matched exactly: definitionsrc/bytes.rs:569, call599:9, callerclear:598method. - Two readers who had not seen answer keys reproduced both keys from CLI output and source alone. Their reported gaps were display limits (no transitive callers, no argument analysis, tests outside the capture profile), not coordinate errors.
- A third reviewer, with no CLI and no answer key, re-froze the bytes reserved case from the two source trees alone: same definition
src/bytes.rs:569, same production call599:9, callerclear:598. Reports:evidence/readers.
-
node --test modules/code-analysis/test/*.test.mjs: 444 pass, 0 fail, 0 skipped. - Counterexamples: baseline 104 checks, 84 applicable and 82 passed; candidate 136 checks, 107 applicable and all passed, with all eight kinds covered. The 29 not-applicable candidate checks have no record for the mutation to act on (8 delete-target, 9 promote-candidate, 10 omit-target-file, 2 wrong-declaration); the baseline had 20.
- Canonical ZIP
/tmp/archify-stage2.zip, SHA2565b3ee9f516b19c20004b36f32313f3650a820a446e6ca9d9907f89cb7e18e58e, built with official Node 22 / zlib1.3.1-e00f703, committed asarchify.zipinc10ea384c. - Fresh unpack +
npm cireplayed the AsRef fixture,gin-hijack,echo-remove-custom-methodandtracing-subscriber-event-enabled. Identitiesrust-syn@2.0.119rev 8 /rust-source-direct-v8andgo-parser@1.27.2rev 6 /go-source-direct-v4; positions matched the batch runs.fmt/mod.rs:402remains the documented miss. - Evidence:
evidence/stage2-baseline,stage2-final,comparison,asref-local,stage2-replay,readers; README has per-scope tables and commands. - CI run 42502359214 for head
021a3898acompleted successfully; only deploy jobs were skipped. PR stays Draft and unmerged.
Draft, not merged: #1296, head a840c2d07, base codex/go-rust-investigation-batch at 021a3898a (Draft #1290, which depends on #1289). Started from 021a3898a. No merge, no labs/code-analysis update, no live installation.
The previous stage listed token scanning as the next step. This stage tested that premise: a macro can discard, duplicate or rewrite its argument, so a name found inside a macro is not by itself a call. The delivered mechanism therefore traverses a local macro_rules! argument in place only when all of the following are proven from captured source:
- exactly one definition of the name exists across the selected crates;
- the definition is textually visible at the callsite (same module and earlier, an earlier ancestor module, or an earlier sibling
#[macro_use] mod); - no import or glob between the callsite and the definition shadows the name, and no enclosing block does either;
- every rule matcher is a single
$x:exprand every expansion uses$xexactly once outside$(...)repetition and nested macro groups.
Accepted calls carry macroEvidence: [{name, definition, argumentUse: "once", expansion: "preserved"}]; everything else stays opaque. Model rust-source-direct-v9 / adapter revision 9. The first draft used a bare-name lookup; independent review found that an imported external macro could be attributed to an unrelated local definition of the same name, so scope, import and block shadow checks were added.
| Site | Frozen source answer | Result |
|---|---|---|
clap ok!
|
argument used once as the match scrutinee |
fixed: value_parser.rs:658:25 resolves with ok evidence |
tracing layer_impl_body!
|
one call expands into two generated impl methods | still unknown: macro-item expansion |
tracing try_lock!
|
method call is outside the macro; file not captured | still unknown: guard/deref receiver plus cfg-gated capture |
tracing feature!
|
cfg-transparent item wrapper around modules | still unknown: cfg-wrapper traversal |
Only the ok! class is claimed. The other three are recorded with the mechanism each needs instead of being promoted by token scanning.
Both clap changes were selected after the rule was designed, and their answers were frozen before the candidate ran.
| Case | Changed definition | v8 references | v9 references | Wrong targets |
|---|---|---|---|---|
| A |
Parser::parse_long_arg (763) |
0 | 1 at 149:44
|
0 |
| A |
Parser::parse_short_arg (882) |
0 | 1 at 219:44
|
0 |
| B |
Parser::parse_short_arg (831) |
0 | 1 at 185:44
|
0 |
| B |
Parser::is_new_arg (635) |
1 at 331:29
|
unchanged, direct | 0 |
All three added references carry macroEvidence naming ok at macros.rs:583:14 (case A) or 554:14 (case B) and resolve to the named declaration. Net: 3 new navigable positions, 3 newly resolved targets, no lost baseline reference, no wrong target. Case A reports partial only because the head commit edits the root Cargo.toml (resolution-settings-differ); every reference is valid.
- Original 20 cases, 86 expected positions: 79 correct (from 78), 7 missed (from 8), 0 wrong, 2 known extras, definitions 20/20. The only changed case is
clap-typed-value-parser, 0/1 to 1/1. Counterexamples: 144 checks, 114 applicable and all passing, 30 not applicable, all 8 kinds covered. -
fixtures/rust-macro-argscompiles withcargo buildandcargo build --features extra(cargo 1.89.0). Arguments that are discarded, used twice, nested in another macro argument or placed in a repetition stay opaque; the single-use argument resolves; a cfg-off caller stays opaque and resolves when enabled. Unit tests add shadowed-import,#[macro_use]ordering and cfg-gated-definition controls. -
node --test .../test/rust-calls.test.mjs: 44 pass. - Canonical ZIP
fa78fa4c…(Node 22.23.4 / zlib1.3.1-e00f703, 405 files) unpacked fresh withnpm cireproducedrust-syn@2.0.119revision 9. AsRef:Other::enabledatsrc/lib.rs:11, references32:9and37:5, noFirsttarget. Case B:185:44withok@554:14,is_new_arg:331:29direct. The same bytes are committed at the repository root forzip-freshness; the first CI run failed only because that file was still the v8 package, and the rebuild fixed the archive, website and regression checks without code changes. - Final CI 42571643030 for head
77d0aae23: 19 success, 2 deploy jobs skipped. - An uninvolved reader received only the case-B trees, entry file, question and CLI; it independently reported
831:5,185:44,ok@554:14and the direct331:29caller, and cross-checked every coordinate in source. - Evidence:
benchmarks/code-analysis-rust-macro-calls-20261109(answers,fixtures,evidence/{real-changes,final-v9,comparison,zip,readers}); the README carries per-scope tables and commands.
Only local macro_rules! arguments are traversed. Imported/exported macros, multi-segment paths, macro 2.0, token rewriting and cfg-gated definitions remain opaque; a name imported anywhere between the callsite and its definition is a deliberate miss even when it points at the same macro. macroEvidence proves argument preservation, not runtime evaluation or concrete dispatch.
Review found two false positives in the first macro implementation. Both had the same target function but a different visible binding at the call:
| Line | Binding | v9 | v10 |
|---|---|---|---|
| 7 | block-local ok! discards $e
|
known reference (wrong) | unknown |
| 10 | expansion uses $e only under #[cfg(any())]
|
known reference (wrong) | unknown |
| 13 | module ok! passes $e once |
known reference | retained |
The base/head pair differs only in the target body. The pre-fix normal CLI returned 7, 10 and 13; the fixed CLI returns only 13 (13:45, ok at 6:14). Root fixes:
- Resolve the
macro_rules!binding actually visible at the callsite. A preceding block-local definition shadows the module binding until the block ends; the outer binding is restored afterwards. A definition placed after the call does not shadow earlier calls. - Prove the active expansion keeps the argument. The expansion is parsed with the argument replaced by a sentinel, cfg attributes on statements, expressions, items, locals and match arms are evaluated against the selected feature/target profile, and exactly one active use is required. A use deleted by
#[cfg(any())]or a disabled feature stays unknown; an unknown cfg is never accepted.
Controls compile and run with cargo 1.89.0 under both feature profiles. The gated macro in rust-macro-args is the same source analyzed with the feature off (unknown) and on (resolved).
Retained results after the revision:
- Both clap changes keep all 3 passthrough positions (
149:44,219:44,185:44) withokevidence;is_new_argat331:29remains a direct call without macro evidence. - Original 20 cases: 79/86 correct, 7 missed, 0 wrong, 2 known extras; v9→v10 per-case outcomes are identical.
- Counterexamples: 144 checks, 114 applicable and all passing, 30 not applicable, all 8 kinds covered; totals are replayed from each check's
availableandpassedrecord. Module test suite 452 pass (46 Rust tests). - A fresh reader reproduced case B on v10:
831:5,185:44withok@554:14, direct331:29. - Canonical ZIP
5876a160…(Node 22.23.4 / zlib1.3.1-e00f703, 405 files) was unpacked fresh and replayed the scope/cfg counterexample and case B with revision 10; only line 13 is known in the counterexample. - Final CI 42575733695 for head
a840c2d07: 19 success, 2 deploy jobs skipped. - Evidence:
benchmarks/code-analysis-rust-macro-calls-20261109/evidence/revision-v10plusfinal-v10,comparison-v10.
Draft PR #1297 starts its product work from a840c2d07 and includes #1296's statistics-only aa080c89b; the statistics correction is not product benefit. The fixed change is tokio-rs/bytes d5c8ad32..7930d93d, Buf::try_get_int at src/buf/buf_impl.rs:2086.
| Call | Source | Enclosing method | Receiver | Proven | Not proven |
|---|---|---|---|---|---|
| A | 2158:13 |
Buf::try_get_int_ne default body |
self: &mut Self, Self: Buf
|
calls the trait declaration | concrete Self / override |
| B | 2836:13 |
try_get_int in zero-argument deref_forward_buf! (2461), used by impl Buf for &mut T / Box<T>
|
**self: T, T: Buf + ?Sized
|
calls the trait declaration | concrete T; call is macro-generated forwarding |
The baseline v10 CLI loses A as rust-trait-or-method-dispatch and does not see B at all. The old frozen record also had A as method, B at column 26 and both as determined targets. Correcting those answer keys is not removal of product wrong targets: v10 returned neither position. v11 added the two candidate references, but its caller identity still required the v12 attribution correction below.
v11 changes (rust-source-direct-v11 / adapter 11):
- A bare
self.method()in a default body binds to the enclosing trait declaration; a missing method stays unknown. - A zero-argument local
macro_rules!filling the entire impl body is expanded for inventory, inheriting self type, bounds and where clause. This is a bounded textual template; non-empty matchers, imported/ambiguous macros and mixed impl items stay unknown. -
*self/**selfkeep the captured trait bound; generic&mut TandBox<T>forwarding target the declaration, while a deref of a non-selfgeneric stays unknown. - Generated callers use
directCaller.kind = "macro-generated-method"; this label alone did not prevent v11 from retaining only the first impl's qualname after deduplication. - A plain local
impl Trait for Typewithout an override inherits the default; an override is excluded from the default's references. - A default body is inventoried once per declaration, and trait-dispatch callsites stay
runtimeTarget: not-determined.
Results:
- bytes: baseline 0/2 (2 missed) → 2/2, 0 wrong, 0 missed, 0 extras.
- tracing
Layer::event_enabled(independent frozen answer): 4/7 both; four declaration candidates (layered.rs 143, 293, 295;layer/mod.rs 1514) and three named unknowns kept. - Original 20 cases with the corrected bytes answer: 81/86 correct, 5 missed, 0 wrong, 2 known extras (v10: 79/86, 7 missed). Counterexamples 152 checks, 121 applicable and all passing, 31 not applicable, 8 kinds covered.
- Compilable controls:
fixtures/rust-trait-forwarding/{base,head}differ only in the default body;concrete_overrideresolves to the override andlocal_derefstays unknown. - Module suite 455 pass (49 Rust tests). Canonical ZIP
b8093e4f…(405 files, Node 22.23.4 / zlib1.3.1-e00f703) replayed from a fresh unpack: bytes 2/2, tracing 4/7, fixture outcomes unchanged. - Reader:
evidence/readers/tracing-reader.mdreproduces the four references and the unknown mechanisms from the change definition alone. - Final CI 42586227599 for head
70750e6ba: 19 success, 2 deploy jobs skipped. - Evidence:
benchmarks/code-analysis-rust-trait-forwarding-20261109/.
The revision stays on Draft #1297, with 70750e6ba as the fixed comparison base. It corrects ownership evidence, not the previously corrected answer keys:
- Combine outer impl, invocation, generated method and body cfg, including nested
cfg_attr. Disabled calls disappear; unknown conditions do not establish a known target. - Deduplicate physical template positions while retaining
macroTemplate.definitionand every provable physical expansion origin. The caller namesmodule::macro!::method, not the first impl. - Divergent targets stay unknown. Disputed caller identities are omitted separately, preserving an agreed target when one file is loaded under different modules.
- Unknown accessor return evidence and unknown generated trait implementations remain ambiguity blockers; discarding them must not select a different active implementation.
The genuinely independent same-rule change is futures-rs 446134c1..c0122993: deref_async_read! is the whole body of both AsyncRead for Box<T> and AsyncRead for &'a mut T. Source answers were frozen before baseline/candidate queries. The source-proven ReadHalf<R> closure call in split.rs:49 remains a miss, not a removed denominator. Both futures captures are partial because the historical head has a separate arc_wake.rs parse error; neither a modern upstream build nor complete caller coverage is claimed. Tracing 4/7 remains a regression case, not evidence of this bounded macro rule.
An independent reader, without answer keys or product diffs, navigated bytes from try_get_int:2086 to the ordinary call at 2158, template call at 2836, deref_forward_buf:2461, and expansions 2887 / 2891. In futures they found template call 259, deref_async_read:244, expansions 265 / 269, and identified the missing split.rs:49 relationship by source reading. Both paths establish trait declarations, not concrete runtime implementations. The reader run predates the final conservative ambiguity fixes and is reused at its original identity, not presented as a new final-head reader run.
Final local results:
- Original 20: 81/86 correct, 5 missed, 0 wrong, 2 known extras; 20/20 definitions, identical per case to v11. Counterexamples: 152 total, 121 applicable and all passing, 31 N/A, 8 classes.
- Bytes remains 2/2 and futures remains 1/2; both now retain the template identity and both real expansion origins. Tracing stays 4/7. Thus zero new real caller positions, zero real-case wrong-target removals and zero position regressions in this revision.
- The cfg control changes known references from 3→0 with the feature off and 6→5 with it on; unknown conditions are retained as unknown. The divergent control stays unknown instead of choosing a target, with both origins preserved.
- Both controls pass 364/364 assertions in source and independently in the fresh ZIP, with 8/8 Cargo builds per run. Full module: 461 pass, including 54 Rust tests, no skips.
- Final ZIP: 405 files, SHA256
a61b2328c6b88127a324384e9ef536f42282ca41d4cd2d93290d1e774da5e6d9, official Node 22.23.2 / zlib1.3.1-e00f703; a second build is byte-identical. ZIP replays bytes 2/2, futures 1/2 partial, tracing 4/7, and both controls. - Rescoring identical outputs with the old bytes key gives 79 correct / 6 missed / 1 wrong / 3 extras on both baseline and candidate, with two stale-oracle mutation failures. This is answer-key correction, not a product accuracy gain. The old v10→v11 two-position gain is not counted again.
Final report and reader path · Computed comparison and raw evidence · Replay script.
The report distinguishes initial/interrupted evidence from final/, with exact source hashes and final ZIP identity. All nine tested source/test hashes match committed head 3b09a193e69428c83cb0c5c0374c37d9c134adee.
Final-head CI 42592939655 completed successfully for that exact head: 19 successful jobs, only the two deployment jobs skipped. Both complete regression shards, browser/WebM gates, Node compatibility, ZIP byte freshness, three-platform package smoke and Windows portability succeeded. The Code Analysis module job executed 461 tests, all passing, none skipped, including the new cfg/provenance/unknown-impl regressions. This is current-head CI, not the historical v11 run.
The scoped test-value/simplification review led to separate caller/target agreement and uncertainty blockers; no unrelated cleanup or capability removal was performed. Historical v11 saved facts remain accepted under their original contract. The isolated ZIP dependency install reported eight npm audit warnings against unchanged dependencies (one moderate, seven high); no security clearance is claimed. #1296 and #1297 remain Draft and unmerged; no change to labs/code-analysis, live installations or releases.
v13 starts from v12 final 3b09a193e on a new stacked branch. Draft PR #1298 targets #1297's head branch; #1297 stays Draft and unchanged.
Diagnosis preceded the fix: futures' futures-util/src/io/split.rs and the call at :49 were already captured, but closure parameter l had no type because signature scope only read enclosing function parameters. The call fell to rust-trait-or-method-dispatch with no target.
v13 (rust-source-direct-v13 / adapter 13) binds closure inputs from a local free-function signature: a bare fn(...), impl Fn/FnMut/FnOnce(...), or a generic parameter with exactly one Fn-family bound, after substituting call-argument shapes. The call records the innermost closure anchor at its opening |; directCaller remains the enclosing named function or method. Competing bounds, unbound generics, turbofish, arity shifts, reassignment/shadowing, destructured inputs, method callees, iterator adapters, dyn receivers and external APIs bind nothing. A scoped review found the stale-shape, turbofish and aggregate-destructuring gaps; they were fixed with regressions before final acceptance.
Results:
- Futures: 1/2 → 2/2. The new real position is
split.rs:49:55, closure49:44, callerReadHalf<R>::poll_vectored_read, targetAsyncRead::poll_vectored_readatfutures-io/src/lib.rs:136.lock_and_then'sF: FnOnce(&mut T, &Waker)and&self.handle: &BiLock<R>provel: &mut R; only the declaration is established. Both captures remain partial because of a separatearc_wake.rsparse error. - Original 20: 81/86 correct, 5 missed, 0 wrong, 2 extras, identical per position to v12; 0 new positions, 0 withdrawn, 0 wrong-target removals, 0 regressions in that set. Counterexamples 152 total, 121 applicable and passing, 31 N/A, 8 classes.
- Bytes 2/2 and tracing 4/7 are unchanged. The compiled closure control passes both sides and nine assertions each;
dyn, method-callee and iterator-adapter closures produce no known call. - Source-first reserved case
Subscriber::event_enabled(tracing-core): the frozen four-call answer scored 4/4, but an independent reader found a fifth real call attracing-subscriber/src/fmt/mod.rs:402. It is real yet unread becausefmtis declared inside the crate'sfeature!macro, so the completed answer scores 4/5 with one known miss, not a product gain or closure regression. - Readers without answers or product diffs confirmed the futures closure path and the four tracing calls, separated
Subscriberfrom the same-nameLayermethod by arity and receiver bound, and found thefmtomission in source. - Module suite 469 pass, 0 fail, 0 skipped, including 62 Rust tests. Final ZIP
179cdbdb…(405 files, official Node 22.23.2 / zlib1.3.1-e00f703) is byte-identical to a repeat build and the tracked archive; fresh-unpack replay gives futures 2/2, reserved 4/5, closure control andbytes-truncate-zero1/1. Transientextract/rust-parser-failedattempts are recorded incommands.md; failed runs produced no queries or scores. - Final CI 42607917579 for head
3ab78d5be: 19 success, only the two deployment jobs skipped. The Code Analysis module step passed in full-regression (1). - Evidence:
benchmarks/code-analysis-rust-trait-forwarding-20261109/evidence/revision-v13/, includingcomparison-final.json, reader reports and the review receipt.
v14 starts from v13 final 3ab78d5be on the same Draft PR #1298; #1296, #1297 and #1298 stay Draft.
The reproduced defect used a compiled fixture where the provider and the caller each define Item::mark. Before the fix, changing the provider returned zero known references and changing the caller returned one wrong reference to its own Item::mark, because a written type was stored as a path and resolved in the caller module. v14 (rust-source-direct-v14 / adapter 14) resolves written types in the module that declares the helper, keeps the actual argument's module identity through generic substitution, and never binds an unresolved or external type to a same-spelled captured local type. Non-closure receiver typing is unchanged.
Results:
- Counterexample: provider 0 → 2 (closure calls at
24:36and41:26, target providerItem::markat5:9); caller 1 wrong → 0. Base, provider-head and caller-head all build withcargo build --offline;run-closure-provenance.pyverifies source hashes, builds and queries. - Real tracing case frozen from source first:
Dispatch::event(f42e7e6) is called throughget_default'sF: FnMut(&Dispatch) -> TinEvent::dispatch,Event::child_ofandtracing-log::dispatch_record. v13 finds 0/3, v14 finds 3/3, including the cross-crate caller. - Real ripgrep case frozen from source first:
IgnoreRef::is_absolute_parent(43e2f08) is called throughIgnore::parents()insidetake_whileincheck_symlink_loop. Both v13 and v14 return 0/1; this is retained as a measured coverage gap because the closure input comes from a local iterator declaration through a standard adapter. - Futures stays 2/2 (partial). Original 20 stays 81/86 correct, 5 missed, 0 wrong, 2 extras, identical per position to v13; all 81 hits retained, no batch wrong target existed to withdraw, and the same five positions remain missed. The single withdrawn wrong target is the caller-side counterexample.
- Module suite 472 pass, 0 fail, 0 skipped; the compiled closure control passes both sides and nine assertions each. Final ZIP
e7358404773caef411c60e0b22d593922d6a4dd5c00e59c46f27b5ee7b77a27c(405 files, official Node 22.23.2 / zlib1.3.1-e00f703) is byte-identical to a repeat build and the tracked archive. Unpacked-ZIP replays: provenance provider 2 / caller 0, tracing 3/3, ripgrep 0/1, futures 2/2. - Final CI 42620473485 for head
4390816b8: 19 success, only the two deployment jobs skipped. - Evidence:
benchmarks/code-analysis-rust-trait-forwarding-20261109/evidence/revision-v14/, includingcomparison-final.json, frozen answers, query JSONs, control output, test log and ZIP identity.
The new closure rule leaves method-callee, iterator-adapter, dyn and turbofish closures outside scope by design. The next real gains are different mechanisms: capture cfg-gated modules behind feature! (the reserved fmt/mod.rs:402 miss), model guard/deref receivers for try_lock!, and decide whether macro-item expansion is in scope for source positions. Receiver chains through renamed impl/struct generics, &mut B accessor forwarding without source evidence, and type inference for locals beyond captured nominal types remain unknown by design.