Repository navigation
v3.1.0
v3.1.0 is a minor release. It adds one MCP action (search action=uql), makes
the complete answer of nav action=callers proof-carrying, and moves every
MCP tool response onto one envelope contract. No request shape changes and no
action is removed, but several response values change. Read Behaviour
changes and migration below before upgrading an agent or script that
branches on completeness, verdict, success or agent_summary. The index
is rebuilt automatically on the next refresh (extractor version 53 → 54).
Highlights:
- One query language for multi-hop questions:
search action=uql
(RFC-0041, #1800, #1801, #1802, #1804, #1814, #1820). A pipeline such as
symbol('X').callers(depth=2).untested()runs in one call. Every stage
reports its own completeness and reason codes, and the total iscomplete
only when every stage is. Relations reusenav action=callersand pass its
completeness through unchanged. On the RFC-0041 benchmark (8 questions × 2
repos) uql needed 8 calls instead of 21–22 and about half the tokens
(−49% on TSA, −56% on rich), with 0 wrongcompletein every arm. CLI
parity:--uql. - Proof-carrying
complete(RFC-0040, #1799).nav action=callers
answerscompleteonly when all 12 checks in a closed registry ran over the
queried target set and found nothing. A check that was skipped fails closed,
and the answer names it. - A wrong-
completeoracle suite in CI (#1796). A 15-case known-answer
corpus built from real bugs, an oracle that never imports TSA, Hypothesis
properties on generated projects, and a nightly sweep of rich and gson. Each
case is checked in both bare and qualified form. - Text search completes on Windows (#1783).
search action=texton cold
clones: rich 30.4 s → 2.9 s, axios 27.9 s → 3.0 s. Both used to fail with
SOURCE_SCAN_BUDGET_EXCEEDED. - Faster cold index (#1825). Pool workers start concurrently, the
certification tree encodes faster, no-op edge resets are skipped, and the
automatic worker count scales with the file count. Cold index, median of
3: rich 25.8 → 16.5 s, fastapi 59.2 → 40.1 s. The index contents and the
certification root are byte-identical. - Far fewer dead-code false positives (#1790). Functions used as values
(dispatch tables, arguments, decorators, implicit entry points, module-scope
uses) are no longer reported dead. On this repository: 1,874 → 202 reported
functions, none new. Findings now carryconfidence. - One envelope contract for every MCP tool response (#1807–#1812). The
response guard runs with an empty allowlist. Every failure haserrorand
a machine code, completeness uses one vocabulary, and the verdict agrees
withsuccessandagent_summary. - Release gate numbers (dogfood round 14). The 7 pinned repos were rich,
pydantic, fastapi, axios, gson, zod and hono. 0 wrongcompletein bare and
qualified mode, by the ground truth and by the in-repo oracle
(scripts/wrong_complete) over every stored Python answer. Latency was
measured against the v3.0.0 wheel on the same machine in one session, ABBA
order, with a fresh index per run. A laptop suspend during the run discarded
and redid the affected runs.- Cold MCP
index action=full, median of 2 runs:- axios 23.6 → 14.0 s;
- gson 46.4 → 28.8 s;
- rich 23.9 → 14.8 s;
- pydantic 79.9 → 64.8 s (noisy: individual runs ranged 36–119 s).
- Warm
nav action=callers:- pydantic 0.18 → 0.14 s;
- fastapi 0.12 → 0.11 s;
- rich 0.15 → 0.08 s.
- First
nav action=callersin a fresh process, processes 2–4 (persisted
stores hit): fastapi 3.4 → 2.9 s, with 44% fewerlstatcalls
(17.9k → 10.0k). On the other 6 repos it was within noise of v3.0.0. - Unscoped callers on unique names (#1798), over 424 targets: answers list
495 fewer callers. 493 of them had no proven binding to the target. All
10 ground-truth callers among them are still reported as evidence
(NAME_ONLY_INBOUND/UNRESOLVED_INBOUND). - uql: 39
symbol(...).callers(depth=2)queries across the 7 repos, 23 of
themcomplete. Every row matched a nav-callers BFS, and nocomplete
answer missed a caller.
- Cold MCP
Behaviour changes and migration
None of these makes an answer more confident than before. Each one either adds
a field, moves a value onto the canonical vocabulary, or makes a failure
explicit.
- Index status says
incomplete, notpartial(#1811).- What changed:
codegraph_status/index action=statusreport
completeness: incompletewhere they used to pass the snapshot value
partialthrough. The snapshot value moves to the new
snapshot_completenessfield. A status that is notcompletenames a
reason code (INDEX_NOT_CERTIFIED,MISSING_INDEX,
INDEX_BUILD_IN_PROGRESS, …), and the raw reason stays in
oracle_reason. - Migration: compare against
incomplete, or read
snapshot_completenessfor the old value.
- What changed:
- No
N/Averdict (#1810).- What changed:
health action=file/check_file_health(empty and
non-code files) andcode_patterns(empty files) answerverdict: INFO
withverdict_reason: EMPTY_FILEorNON_CODE_FILE.grade: "N/A"and
signalare unchanged. - Migration: branch on
verdict_reasoninstead ofverdict == "N/A".
- What changed:
- Syntax errors answer
success: false(#1812).- What changed: the syntax-error short circuit of
safe_to_edit,
smart_context,check_file_healthandcode_patterns, and an
ast_diffthat could not be computed, answersuccess: falsewith
erroranderror_code(SYNTAX_ERROR,LANGUAGE_UNSUPPORTED,
AST_DIFF_FAILED). They used to answersuccess: truewith
verdict: ERROR. The rest of the envelope is unchanged. - Migration: treat
success: false+error_codeas the failure
signal. Code that only readverdictstill seesERROR.
- What changed: the syntax-error short circuit of
- Failures are
ERROR, notCAUTION/WARN(#1812).- What changed:
check_constraintswith an unparseable rule file answers
verdict: ERROR/error_code: CONSTRAINT_CONFIG_INVALID(was
CAUTION). A failed incremental sync answersverdict: ERROR(was
WARN).advise_parser_readinessfailures no longer default toINFO.
A success without a top-level verdict takesagent_summary.verdict
instead ofINFO. - Migration: gates that treated
CAUTION/WARNas "proceed with
care" for these tools must handleERROR.
- What changed:
- Every failure carries
erroranderror_type(#1808, #1809).- What changed: missing
error/error_typefields are filled from the
response's own message. Messages containing "syntax error" classify as
validation, and "AST cache is empty" asindex_not_ready(both were
internal). Values set by the tool are never overwritten. - Migration: none, unless you matched
error_type: internalfor those
two cases.
- What changed: missing
codegraph_test_gapagent_summaryis a dict (#1812).- What changed: like every other tool,
agent_summaryis now a dict. The
text it used to hold is insummary_line. - Migration: read
summary_linefor the old string.
- What changed: like every other tool,
- Unscoped
nav action=callerson a unique name no longer lists unproven
same-name calls (#1798).- What changed: a name with exactly one definition in the project, asked
withoutfile_path, is now answered exactly as if its declaring file had
been given (all four forms, bare / qualified × scoped / unscoped, share one
target set). Before, the unscoped bare form listed every same-name call
whose receiver was not proven, so richText.joinlisted 48 callers
(", ".join,os.path.join, …) against 7 when scoped. Those sites now
appear as evidence (NAME_ONLY_INBOUND,NON_CALL_REFERENCES) instead of
as callers. - Migration: read
name_only_sites/unresolved_inbound_sitesif you
relied on the longer unscoped list. Names with several definitions are
unchanged.
- What changed: a name with exactly one definition in the project, asked
- Index format: extractor version 53 → 54 (#1773).
- What changed: Python
@overloadstubs are marked insymbols_json. - Migration: nothing to do. The next refresh re-extracts every file
written by extractor 53, so the first refresh after the upgrade costs
about a cold index.
- What changed: Python
tql_executereports completeness, and rejects bad selectors at parse
time (RFC-0041 §6).- What changed:
search action=tql_executekeeps its request and
response shape and gainscompletenessandcompleteness_reasons.
Edge, history, rule and branch predicates answerunknownwith
SELECTOR_PREDICATE_UNPROVEN. An unknown pseudo-class is rejected when the
selector is parsed (error: "TQL syntax error: unknown pseudo-class ...",
error_code,fixed_selector); it used to fail at evaluation with
"TQL evaluation failed: ...". An unknown attribute is now rejected; it
used to evaluate to[].#namerows carryclasswhen the per-file
function rows have it. - Migration: a selector with a typo now fails instead of returning no
rows. Usefixed_selectorwhere it is given.
- What changed:
search action=chainis deprecated in the docs (RFC-0041 §6).- What changed: nothing at run time.
chainkeeps working, emits no
warning, and parses through the same UQL parser. Docs and skills route
multi-hop questions tosearch action=uql. - Migration: prefer
uqlfor the questions it covers.chain's
answer-pack steps (explore,include,uml,semantic, …) have no UQL
equivalent yet; the UQL parser rejects them withUQL_CHAIN_ONLY_STAGE.
- What changed: nothing at run time.
- Forward-slash paths in every
navanswer (#1813).- What changed: without an index on Windows,
navanswers named files as
app\doc.py, andtracereturned absolute OS paths. They now use
repo-relative, forward-slash paths, like indexed answers. File-scoped
lookups such asfile_path="app/util.py"now match on Windows instead of
falling back to every definition. - Migration: none, unless you repaired backslashes downstream.
- What changed: without an index on Windows,
- Dead-code results (#1790).
- What changed:
dead_codeandcodegraph_overvieworphans drop
functions that are used as values, and each finding hasconfidence
(high/low) andconfidence_reason, with high/low counts.
Low-confidence findings are sorted last. - Migration: expect much shorter lists; filter on
confidenceif you
want only high-confidence findings.
- What changed:
- Automatic index worker count scales with the project (#1825).
- What changed: the automatic count is one worker per 64 files, at least
2 and at mostcpu_count - 1(wascpu_count - 1for every project of 64+
files). Explicit counts andTSA_INDEX_WORKERSare unchanged. - Migration: set
TSA_INDEX_WORKERSto keep the old count.
- What changed: the automatic count is one worker per 64 files, at least
- No global pytest reruns (#1806). Contributors only:
--reruns=1is gone
fromaddopts, and the runtime contract rejects it. A test that really
needs a retry opts in with@pytest.mark.flaky(reruns=1)and an issue
reference. Installed packages are not affected.
Added
-
search action=uql: the unified, evidence-carrying query language
(RFC-0041, #1800, #1801). One grammar and IR replace the separate TQL and
chain parsers. A query is a TQL selector or a pipeline of stages:- sources
symbol(...)/select(...); - relations
callers(depth),tests(),impact(depth),callees(); - refinements
filter/exclude/untested()/tested()/take/
sort.
Each stage reports its own and its effective completeness. Output is
compact by default (detail="full"for structured rows withdepth/
viaprovenance). Paging uses stateless, generation-pinned cursors (limit
1–500, default 50). Errors are typed values from a closed set of 18 codes
withfixed_querywhere the fix is mechanical. Source stages revalidate
every indexed file within a 2 s deadline (SOURCE_RECHECK_DEADLINE). The
answer cache admits uql answers. CLI:--uql,--uql-limit,
--uql-cursor,--uql-detail. Discovery:search action=help target_action=uql. - sources
-
Batched
nav callersfor uql relation stages (#1802, #1820).
execute_batchanswers a stage's requests under one certified index read
and one call graph, and the work that does not depend on the name (alias
imports, ES alias edges, the reference-vocabulary prefilter,stat) is
shared across names within one answer. Every input still runs all RFC-0040
checks, and its payload is byte-identical to a single call. Singlenav
calls outside a query are unchanged. -
Multi-hop routing (#1804). The
searchandnavdescriptions, help
text,caller_treenext_stepand the skills point multi-hop questions at
search action=uql. After a callers answer,test_mapor callers on a
listed caller appends a uql follow-up hint.
Tests
- Wrong-
completedetection fornav action=callersnow runs in CI. Until
now, "0 wrongcomplete" was measured by hand in dogfood rounds, and the
evidence lived outside the repo.-
tests/known_answer/is a known-answer corpus: 15 minimal projects built
from the real bugs #1740, #1743, #1758, #1759, #1762, #1764/#1769, #1766,
#1768, #1772 (4 variants) and #1773. The ground truth is marked in the
fixture source. Each case is checked in both bare and qualified modes:- a
completeanswer lists every true caller and every site the oracle finds; - callers that are listed now stay listed;
- no caller outside the truth is listed;
- an unlisted true caller appears in an evidence field;
- the bare answer is never more confident than the qualified one.
- a
-
scripts/wrong_complete/is an independent oracle that never imports TSA.
It resolves receivers with Pythonastand uses a token scan for Java and
TS/JS. The same package holds the scorer and the real-repo sweep, and each
part has unit tests. -
tests/property/test_callers_oracle_properties.pyruns Hypothesis over
generated multi-file Python projects and checks four invariants:completeimplies the oracle's sites are a subset of the listed callers;- the bare answer is never more confident than the qualified one;
- an unrelated same-named definition never upgrades confidence;
- a rename that keeps call semantics keeps the callers.
PR CI uses a fixed seed and 6 examples.
-
.github/workflows/wrong-complete-oracle.ymlruns nightly:- it runs more Hypothesis examples;
- it sweeps rich and gson at the commits pinned by the dogfood rounds, and
fails on any wrongcompletethat a reviewed exclusion does not cover; - it uploads the scores as an artifact.
-
- No global
--reruns=1(#1806, #1818, #1829). A global rerun hid flaky
tests and flipped mutation detections. Tests that relied on it were fixed
or markedflaky(reruns=1)with an issue (#1815, #1816). The unit-test time
budget is judged on CPU time as well as wall time, Windows CI keeps pytest
temp on the runner work disk (Windows suite 650–740 s → 307–470 s), and
timing-ratio assertions became exact work counts. - Fail-closed CI quality gate and mutation ratchet (#1803).
scripts/ci_required_gate.pyfails the gate when a selected lane is
skipped, cancelled or missing. The mutation baseline runs one job per
module, fails on mutmut errors, and ratchets the unkilled count per module
(tests/effectiveness/mutation_ratchet.json).
Performance
-
Faster cold index (#1825). Index contents are identical (canonical dumps
match table by table, and the certification root is byte-identical):- spawn-pool workers start concurrently instead of one after another
(13 workers, construction plus first task: 7.22 s → 3.92 s); - the certification tree encodes
str/int/Nonecells on a fast path
and re-encodes a group key only when it changes; - edge-resolution resets that would write identical values are skipped
(fastapi: 65.9k–72.9k → 52.4k writer calls); - the automatic worker count scales with the file count (see Behaviour
changes).
End to end, median of 3 interleaved runs on fresh clones: rich cold index
25.8 → 16.5 s, fastapi 59.2 → 40.1 s. No-op refresh is unchanged. - spawn-pool workers start concurrently instead of one after another
-
First
nav action=callersafter an edit + refresh is faster on Windows
(#1778). Profiling showed that #1776 did not cause the slower first query
seen in the v3.0.0 gate. On one shared index, develop with and without #1776
timed the same (fastapi 7.0 s vs 7.0 s), and so did the r12 and r12b wheels.
About 80% of the time is the certified snapshot capture. Graph building is
about 10%. The largest part of the capture is the source walk: four walks per
capture, each running anlstat(which opens the file on Windows) on every
directory entry. The walk now skips thelstatfor entries that have an
unsupported extension and are not directories, because those entries are
skipped whateverlstatreturns. On fastapi a walk drops from 4,457 to
2,485lstatcalls and from 0.62 s to 0.33 s. Same-machine A/B, 12 edit
cycles per side: fastapi 12.7 s → 9.0 s, axios 2.96 s → 2.85 s,
rich 2.12 s → 1.95 s. Warm queries are unchanged. The inventory rows and
verdicts are byte-identical. Answers on the r10 batteries after an edit
(fastapi 102, axios 19, rich 148 queries) are identical across four sources:
the warm process, a cold process on develop, a cold process with this change,
and develop's warm process. Extractor version unchanged.
Fixed
-
An ambiguous Python base class no longer drops override dispatch
(#1834, #1836). When a base class was imported through a package re-export
and another class in the project had the same name, theextendsedge stayed
aclass:Nameplaceholder. Inheritedself.m()calls in the base were then
not recorded as possibly dispatching to a subclass override, and
nav action=callersansweredcompletewith 0 callers for the override
(fastapiHTTPBearer403.make_not_authenticated_error, 3 sites in
fastapi/security/http.py). The answer is nowunknownwith
NAME_ONLY_INBOUND. The bug was already present in v3.0.0. -
A unique name gets the same callers with or without
file_path(#1798).
nav action=callersgives a name with one definition in the project its
declaring file (callers_target_set.sole_definition_file) before the #1759
rewrite, so the bare, qualified, scoped and unscoped forms share one RFC-0040
target set. The scope is added only when it is provable: exactly one
function or method definition in the call graph, and exactly one declaring
file in the index. uql drops its workaround of sending unique names
unscoped. See Behaviour changes. -
Forward-slash repo-relative paths in every
navanswer (#1813).
CallGraph.build,query_symbol_search, the lineage grep fallback and
tracenormalise paths once where they are produced. -
dead_codeno longer reports functions used as values (#1790). A
lexical scan finds non-call uses of the still-dead candidates: a use inside
a function becomes a reference edge, and a module-scope use or a
registering decorator becomes a root. Implicit entry points (__init__,
__call__,visit_*) are roots. Findings in files whose dotted module path
cannot be resolved areconfidence: lowand sorted last; the dogfood
backlog ignores them. The reference index is cached while source mtimes and
sizes are unchanged. -
uql
callees()lists same-file callees (#1814). Callees resolved to a
definition in the caller's file (callee_resolution: "local") were dropped
and the stage was labelledCALLEE_UNRESOLVED. -
Seal honours the busy timeout when leaving WAL (#1821, #1822). SQLite's
WAL → DELETE switch never calls the busy handler, so any other connection
holding the private build database made seal fail at once with a raw
database is locked.leave_wal()now retries within the same 10 s budget,
and a holder still present at the deadline raises the typed, retryable
INDEX_GENERATION_SEAL_BUSY→INDEX_WRITER_BUSY. Nothing is published. -
Interrupted certification reads no longer leave a zombie lock (#1831).
When a deadline fired between two rows of the manifest certification read,
the cursor stayed active, and anything that kept the exception (log capture,
a log record withexc_info) kept the read lock, so the run was not
published.read_recorded_source_rows,validate_snapshot_schemaand
_query_visible_columnsfinish their cursor infinally, andleave_wal
collects reference cycles once before waiting and logs bounded holder
evidence when it gives up. -
MCP tool responses now satisfy the envelope contract (#1808–#1812). The
tool-response guard from #1807 ran with 50 allowlisted violations; the
allowlist is now empty. All changes add fields or move a value onto the
canonical vocabulary, and none makes an answer more confident:- Every failure carries
errorand a machine code (#1808, #1809).
BaseMCPTool.executenow fills a missingerror(from the response's
ownmessage,errors, summary line orstatus) and a missing
error_type(classified from the message, as the MCP server already did
for MCP clients). Direct callers and MCP clients see the same fields, and
the MCP server's error envelope now always haserrortoo. Producer-set
values are never overwritten.pulse_batch(TARGETS_FAILED),
codegraph_incremental_sync(SYNC_INCOMPLETE) andverify_plan/
edit action=verifynow name the cause inerror. Messages containing
"syntax error" classify asvalidation, and "AST cache is empty" as
index_not_ready(both wereinternal). - No
N/Averdict (#1810).check_file_health/health action=file
(empty and non-code files) andcode_patterns(empty files) answer
verdict: INFOwithverdict_reason: EMPTY_FILEorNON_CODE_FILE.
grade: "N/A"andsignalare unchanged. - Completeness uses one vocabulary (#1811). Index status
(codegraph_status,index action=status) maps the snapshot value
partialtocompleteness: incomplete, keeps the snapshot value in the
newsnapshot_completenessfield, and names a reason code whenever the
status is notcomplete(INDEX_NOT_CERTIFIED,MISSING_INDEX,
INDEX_BUILD_IN_PROGRESS,PROJECT_ROOT_MISSING,
INDEX_SNAPSHOT_UNAVAILABLE, …; the raw reason stays inoracle_reason).
codegraph_full_index(INDEX_NOT_CERTIFIED,UNINDEXED_SOURCE_FILES),
incremental sync (INDEX_SCOPE_INCOMPLETE) and faileduql/
search action=uqlqueries (QUERY_NOT_EXECUTED) now name their reasons. - Verdict agrees with
successandagent_summary(#1812).- The syntax-error short circuit of
safe_to_edit,smart_context,
check_file_healthandcode_patterns, and anast_diffthat could not
be computed, now answersuccess: falsewitherroranderror_code
(SYNTAX_ERROR,LANGUAGE_UNSUPPORTED,AST_DIFF_FAILED). They used
to answersuccess: truewithverdict: ERROR. The rest of each
envelope is unchanged. On aread_existingroute the snapshot was still
read, soaccess_statestaysavailablefor these failures. check_constraintswith an unparseable rule file answers
verdict: ERROR/error_code: CONSTRAINT_CONFIG_INVALIDinstead of
CAUTION.- A failed incremental sync answers
verdict: ERRORinstead ofWARN. advise_parser_readinessfailures no longer default toverdict: INFO.- A success without a top-level verdict takes
agent_summary.verdict
instead ofINFO;hyphae_selecton a missing index now saysWARN
at both places. codegraph_test_gapreturnsagent_summaryas a dict. The text it
used to hold is nowsummary_line.
- The syntax-error short circuit of
- Every failure carries
-
nav action=callerscompleteis now proof-carrying (RFC-0040). It
used to mean "no failure check fired", so any path that skipped a check
answeredcomplete(the #1740 / #1758 / #1759 / #1772 / #1644 class).
Now every check in a closed registry reportsCheckedorNotChecked,
andcompleteis built in one place, only when all 12 checks ran over the
queried target set and found nothing. A check that is missing, did not
run, or ran over another target fails closed tounknown(orincomplete
with callers listed) with a code naming it. Bare and qualified names
resolve to one target set before any check runs. This closes skip paths
that were still open:- no project root;
- an unreadable accessor declaration;
- an unreadable graph for the same-file sibling methods;
- module-level call sites without a line, never counted on the
qualified/graph path; - unreadable reference stamps;
- the index-rebuilding reply with no completeness.
New codes:
NAME_ONLY_INBOUND_UNCHECKED,
UNATTRIBUTED_CALL_SITES_UNCHECKED,ACCESSOR_UNCHECKED. There is also a
boundedcompleteness_checksfield ({"required": 12, "checked": 12}on a
census). The r12b dogfood batteries were rerun with develop and with this
branch on the same repo commits: 3,291 answers over 7 repos in both modes,
0 completeness or reason changes, and an unchangedcompleteshare and
wrong-completecount. Extractor version unchanged. -
A call graph built on a certified snapshot is now explicitly not an
incremental base (#1793).call_graph_incremental.generation_ofreturned
the snapshot'ssource_generation(idxsrc-v3:…), a source-tree
fingerprint that never equals the generation id a refresh plan records. So a
certified graph could never be the base for the #1723 incremental update, but
only by accident. #1778 (PR #1791) measured the possible gain as small:
neutral on fastapi, and never applicable on axios or rich
(SCOPE_TOO_LARGE). Mapping the fingerprint back to a generation would also
need proof that the private copy has the same edge rowids and rows as the
generation. So this now fails closed on purpose.generation_ofcompares
only generation ids and returnsNonefor a certified snapshot. A certified
graph keeps no alignment or edge records (they could never be used), only the
reasonCERTIFIED_SNAPSHOT_NOT_A_BASE.updateand the post-publish warm
report that reason (call_graph_warm.incremental_reason). Certified queries
still reuse the incremental result built on the published generation through
the input digest. Answers are unchanged, and the full rebuild that replaces
the refused increment equals a fresh build. Extractor version unchanged. -
--text-search/search action=textcompletes on Windows (#1783).
On small, clean repos (rich has 553 tracked files; axios fails the same way) it
returnedSOURCE_SCAN_BUDGET_EXCEEDEDafter 13–28 s, whilegit grepanswered
at once. v2.2.0 behaved the same. The budget that tripped was time: a fixed 5 s.
Three costs added up. First, the Windows reader reopened and re-verified the
whole ancestor directory chain for every file, about 7.7CreateFileWcalls
per file. Second, files were read one at a time, so the on-access malware
scan of each first open (25–65 ms per file, up to 10 s for one file, measured
with plainopen()too) was paid serially. Third, the decoder's first import
counted against the scan budget. Now one reader per scan pins each directory
once and verifies all of them at the end. Files are read on a bounded 8-thread
read-ahead pool, still yielded in discovery order. The budget is 30 s and
starts after worker start-up. On cold clones, rich dropped from 30.4 s to 2.9 s
and axios from 27.9 s to 3.0 s. Results equalgit grep -n -Fon tracked
files outside hidden and build/dependency paths. Budget failures now name the
budget, its limit and unit, and includescan_progress. They still return no
partial results. -
self.m()binds to a method that has@overloadstubs (#1773). Dogfood
round 12 on pydantic:_Pipeline.constrainin
pydantic/experimental/pipeline.pyhas about ten@overloadstubs and one
implementation, and its 15 callers are sibling methods calling
self.constrain(...). With several same-named definitions in the enclosing
class, the call could not be told apart and was only a name match, so the
qualified_Pipeline.constrainlisted 0 callers while the bareconstrain
listed them all. Stubs exist only for the type checker: at run time the
class body's last, undecorated definition is the method. Python functions
decorated with@overloador@<x>.overloadare now marked in
symbols_json, and the call graph drops a group's stubs when the same file,
class and name have exactly one implementation, which then stands for the
method.self.constrain(...)binds to it as certain, and the bare name
resolves to the single method, so both forms give the same answer (#1759).
Stubs with no implementation (.pyi, Protocol stubs) and two undecorated
definitions (conditional definitions) are unchanged. The extractor version
goes from 53 to 54. -
A cold fixture-detection scan walks the source tree once (#1779). The
is_fixtureTier-2 scan oftests/resolved every*.pystring literal
with its ownrglobovertree_sitter_analyzer/and walked each test
module's AST twice. On this repository a cold scan took about 17 s locally
and overran the 30 s per-test timeout on a macOS release runner. The scan now
builds one basename index per run and walks each statement once; the result
is byte-identical and the cold scan takes about 6 s. -
A test that overruns its timeout fails as itself (#1779). In the v3.0.0
release run, the timeout intest_real_repo_finds_java_pluginlanded on an
instruction with no line number (tb_linenoisNoneon Python 3.11+).
pytest 8.4 could not render that traceback, so the xdist worker raised an
INTERNALERROR and the whole session ended with exit code 3 after 4192 passed
tests. On Windows, pytest-timeout's thread method callsos._exit, so a
timeout showed only asworker 'gwN' crashedwith no stack (PR #1777). A
test plugin (tests/pytest_crash_guard.py) now makes the line number fall
back to the frame's, turns any report that still cannot be built into a
failed report naming the test, and raises the thread-method timeout in the
main thread. A timeout is now an ordinary, rerunnable test failure with its
traceback on every OS. A test stuck in native code is still ended by the
hang watchdog (#1638).