GitNexus/gitnexus/bench/tool-accuracy
Gergo Magyar cddbe135c0
fix(scope): follow namespace factory return types and record untyped drops
`import mod as rp; x = rp.make(); x.m()` lost the receiver type even when
`make` is declared `-> C`: `x` was bound to the raw dotted name `rp.make`,
and nothing followed a dotted name to a function's return type. The inline
`rp.make().m()` failed the same way in the compound resolver, which read
`ns.f()` only as a construction.

Resolve `ns.f` to `f`'s return annotation when `ns` is a namespace import,
the fact `propagateImportedReturnTypes` already mirrors for a named import.
The post-finalize chain follow uses it for bindings and the compound
resolver for inline calls. Only sites that emitted nothing change: the
full lang-resolution corpus emits the identical 2,838 CALLS/ACCESSES edges.

Record the drops that left `impact` at "exact":
- a plain receiver bound to a namespace function with no usable return type
  (`x = ns.untyped()`);
- an outer call whose `file:line:col` key a resolved inner site already
  claimed (`ns.untyped().m()`, `s.repo.Delete(id)`). Only a duplicate
  capture of the same member hides a drop now.

Receiver baseline: call drops 128 -> 151, reads 44 -> 48, ten shape-arm
cells INVISIBLE-GAP -> VISIBLE-GAP; every new drop has no CALLS edge to its
member (BASELINE.md lists them). The python.factory-qualified accuracy gap
is removed; the python-scope fingerprint and capture golden gain the new
fixture only.

Fixes #3498

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 08:22:29 +01:00
..
fixtures fix(rename): extend safe refactoring and flow coverage across languages (#3557) 2026-10-13 08:38:17 +03:00
.gitignore fix(release): gate publication on accuracy and paired evaluation (#3503) 2026-10-10 08:26:08 +01:00
expectations.ts fix(routes): resolve Express registrations made through helper parameters (#3629) 2026-10-18 22:13:10 +01:00
known-gaps.json fix(scope): follow namespace factory return types and record untyped drops 2026-10-21 08:22:29 +01:00
README.md fix(taint): report inline and factory handler flows (#3612) 2026-10-17 20:22:58 +00:00
run.ts fix(rename): extend safe refactoring and flow coverage across languages (#3557) 2026-10-13 08:38:17 +03:00
score.ts fix(release): gate publication on accuracy and paired evaluation (#3503) 2026-10-10 08:26:08 +01:00

Deterministic tool accuracy

This small release corpus implements the cheap tool-level checks proposed in discussion #3493, comment 18772530. The fixed answers come from local fixture source and public issue repros; the current engine output never defines the expected answer.

With the repository's dependencies installed, run from gitnexus/:

node --import tsx bench/tool-accuracy/run.ts --check --out bench/tool-accuracy/results
npm test -- test/unit/tool-accuracy-score.test.ts

The runner uses the real runPipelineFromRepo, CSV/database loader, metadata writer and LocalBackend.callTool. It indexes one small temporary TS/Python repository with PDG enabled and one parser worker. Community/process discovery is unnecessary for these checks and is disabled. Native parser workers require the normal build produced by npm ci; run npm run build after worker changes. The registry, database and fixture copy are isolated and removed after the run. Fixture code is parsed, never executed. Extension installation is disabled, accidental JavaScript fetches fail, and neither embeddings nor paid models run.

accuracy.json contains source SHA, working-tree status, fixture SHA-256, issue IDs, expected/actual answers, precision/recall and raw tool outputs. accuracy.md gives the same fixed-answer verdicts and concise failed answers. --out selects a report directory. Without --check, valid observations can be reported while a new fixed-answer failure is investigated; execution/output errors always exit nonzero. --check additionally enforces the regression gate.

Fixture / checks Public repro Fixed-answer contract
rename/ #3486 All three Writer.close references; zero edits to comments, strings or unrelated homonyms; typed DeferredWriter.flush parameters refuse without edits or source changes.
src/server/, test/stub.test.ts #3487 Server beats a same-path test stub; app.all has method *; Map.get is absent; helper-registered literal route is present.
src/web/ #3488 Both the base-URL template passed to a configured wrapper and a direct literal fetch link their consumer files.
src/security.ts, src/server/inline.ts #3489, #3490, #3491 Named and inline unsafe handlers reach the sink; guarded and constant commands have zero taint; statement and function-hop lines are 1-based.
pkg/ #3497 Direct, chained module-return helper and local module-return helper resolve to the same target.
mod.py, callers.py #3498 Direct, conditional, boolean and module-qualified annotated factories resolve to C.m.
nested*.py, local_import.py #3499 Imports resolve within their lexical scopes; unrelated nested declarations and sibling-local imports cannot capture bare calls.
summary.py, 501 deterministic drop records #3497 Production summarizeUnresolvedReceivers retains 500 names and reports one omitted name; querying a capped-out name requires lower-bound, while a complete empty summary permits exact.

The 501-name case supplies known suppressed outcomes to the production summary writer, persists its actual output as metadata and calls real impact. It tests the cap/consumer contract without requiring 501 parser fixtures. It does not claim parser coverage for those synthetic records. Python checks read actual context.outgoing.calls symbol UIDs, preserving lexical/class ownership.

Rename's positive fixtures construct each Writer receiver directly, including the imported class. A separate DeferredWriter.flush fixture exercises a typed parameter: a TypeScript annotation alone cannot prove which structurally compatible runtime object owns the method. The public rename tool (dry_run: true) must refuse it with planning_status: "unsupported" and code: "ambiguous_reference", zero edits, and unchanged source files. This safety check has no known-gap allowance. Fixture line anchors are updated together; the three exact semantic answers and the same-named method/function, comment and string controls remain required. The runner validates v2 semantic provenance, exact UTF-16 spans and before/after source lines, then scores the whole after line. Semantic rename does not use ripgrep or text-search edits.

Known gaps and repairs

The initial source baseline is dd096e690c06e5d54ab3595c63b83f15e04b6191: 11/31 fixed answers pass, 20 fail. Main at 50aa4be3b2c2c9a1561fc44878e5d8f87b99d16e repaired three #3487 route checks and all four #3499 checks, and their allowances were removed: 18/31 pass, 13 fail. The JSON report records every desired and actual answer independently of gate status. Inline-callback taint now passes and its allowance is removed. Guard taint remains a documented limitation and a visible known gap.

known-gaps.json is an explicit, reviewed list of failing check IDs with issue, reason and observed baseline answers. There is no wildcard, skip, automatic baseline-update command or production-engine fix in this corpus. The gate:

  • Rejects new failing checks, unknown/malformed allowances and missing/malformed tool outputs, exceptions, truncation and incomplete fixture extraction.
  • Rejects a previously correct fact disappearing or a new incorrect fact appearing inside an existing gap. Partial repairs can still proceed.
  • Rejects a passing check whose allowance remains: remove the allowance in the PR that repairs the case, so the fixed answer protects future releases.

Changing a fixture requires reviewing its fixed answers and the line anchors in FIXTURE_ANCHORS (expectations.ts); the runner and a unit test fail when an anchor no longer matches its fixture line. Broadening an allowance requires review of the actual repro; never change an expected answer simply to match current output.