mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 11:49:28 +00:00
fix(hunt): a row's entry points are the ones in its file or a caller's file, not the whole repository's list
The DSPy arm over the second pool failed with LMInvalidRequestError on every change with more than two rows, at no
cost: `source.facts_for` attached every entry point of the product tree to every row, 8190 records and 1.5 MB per
row on apache/seatunnel (the first pool's arm lost 11 changes the same way on trigger.dev and shopper), and the
rendered prompt was refused. The screen table of the second pool weighed 814 MB for the same reason.
A row now carries the entry points declared in its own file or in a file that calls the function, which is what the
input has described all along ("in-repository entry points that reach the file"). `source.entry_point_count`
follows that definition.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
81ae206978
commit
9feb8f1e33
@@ -483,6 +483,8 @@ def facts_for(
|
||||
) -> SourceFacts:
|
||||
"""Compute repository facts at a line; supplied entry points, product files and texts avoid repeated work.
|
||||
|
||||
The facts carry only the entry points declared in the file itself or in a file that calls the function.
|
||||
|
||||
A caller computing facts for many lines of one checkout (the hunter's feature table) walks the product tree
|
||||
and reads it once; without ``files`` and ``texts`` every call walked and read the whole tree again."""
|
||||
root = Path(root)
|
||||
@@ -495,8 +497,13 @@ def facts_for(
|
||||
from .mapping import analyze_entry_points
|
||||
|
||||
entry_points = analyze_entry_points(root, [build_file_target(root, root / file) for file in files])
|
||||
callers = callers_of(root, function, files=files, texts=texts, index=index)
|
||||
# The entry points that reach the file: those declared in it or in a file that calls this function. The whole
|
||||
# repository's list was attached before; on an application with 8000 entry points every row carried 1.5 MB
|
||||
# and the hunter's prompt for any change with more than two rows was refused by the model.
|
||||
reaching = {path, *(caller_path for caller_path, _ in callers)}
|
||||
return SourceFacts(
|
||||
language, function, bounds(spans, function), callers_of(root, function, files=files, texts=texts, index=index), tuple(entry_points)
|
||||
language, function, bounds(spans, function), callers, tuple(entry for entry in entry_points if entry.path in reaching)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -189,3 +189,19 @@ def test_generated_reason_names_build_output_only(tmp_path):
|
||||
assert source.generated_reason(tmp_path, "big.js") == "too_large"
|
||||
assert source.generated_reason(tmp_path, "app.js") is None
|
||||
assert source.generated_reason(tmp_path, "missing.js") is None
|
||||
|
||||
|
||||
def test_facts_keep_only_the_entry_points_in_the_file_or_a_caller_file(tmp_path):
|
||||
from openultrasast.mapping import EntryPointRecord
|
||||
|
||||
(tmp_path / "app.py").write_text("def run(x):\n return x\n")
|
||||
(tmp_path / "web.py").write_text("from app import run\n\ndef view():\n return run(1)\n")
|
||||
(tmp_path / "far.py").write_text("def other():\n return 2\n")
|
||||
|
||||
def entry(path):
|
||||
return EntryPointRecord(path, 1, 2, None, path, "route", "public", "external", [], [], "test", "fixture")
|
||||
|
||||
entries = [entry("app.py"), entry("web.py"), entry("far.py")]
|
||||
facts = source.facts_for(tmp_path, "app.py", 2, entry_points=entries, files=["app.py", "web.py", "far.py"])
|
||||
assert facts.callers == (("web.py", 4),)
|
||||
assert [e.path for e in facts.entry_points] == ["app.py", "web.py"]
|
||||
|
||||
Reference in New Issue
Block a user