mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
feat(contributor-scan): name the function a question cannot locate (M1b 12.3)
After per-family context, every remaining unresolved question reported context_scope_empty, all in three files. The cause is not a missing producer: app/routes/index.js requires seven handler modules and defines none of them, so a question naming handleContributionsUpdate there names a function that file genuinely does not hold, and the empty scope is the correct answer. Reporting that as "scope empty" hid which of two different things had happened. A file the frontend produced no methods for is one problem; a question naming a function defined in another module is another, and it is the common one. Taint and configuration now separate them, reporting context_function_unresolved with the name in the first case and context_scope_empty only when the file has no methods at all. The driver no longer stacks its generic gap on top of a query that already explained itself, and the new gap is question-owned so it cannot block another question's comparison. Completion is deliberately unchanged. The tempting fix is to widen such a question to its whole file, which would raise the number by answering a question nobody asked; a question whose function the graph does not hold stays unresolved, with the name now recoverable from the question that asked it. Group 12 is complete: admission no longer rejects genuine findings on a mis-extracted operation symbol, both families that could never complete their change context now can, and the remaining unresolved questions say precisely why. 1,406 tests passed, nine skipped. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5
parent
3e4ab8d219
commit
b95a371b7e
@@ -328,3 +328,22 @@ def test_a_family_whose_context_query_answers_nothing_stays_unresolved(tmp_path)
|
||||
outcomes = {o.identity.family: o for o in result.question_outcomes}
|
||||
assert "access_control" in outcomes
|
||||
assert any("context_projection_unavailable" in gap for gap in result.scope.unresolved_boundaries)
|
||||
|
||||
|
||||
def test_a_question_naming_a_function_the_file_does_not_define_says_so(tmp_path):
|
||||
"""M1b 12.3: a route-registration file names handlers defined elsewhere; that is not an empty file."""
|
||||
from dataclasses import replace as _replace
|
||||
|
||||
(tmp_path / "source.js").write_text("readable\n")
|
||||
boundary = {"kind": "context_boundary", "reason": "context_function_unresolved:contributor-scan", "function": "handleUpdate"}
|
||||
unresolved = [{"kind": "context_summary"}, boundary]
|
||||
backend = FamilyBackend({"source.js": vector() + unresolved}, {"dominance": [], "config": unresolved})
|
||||
target = _replace(region("source.js", "javascript"), function="handleUpdate", families=("injection",))
|
||||
result = scan_repository(tmp_path, [target], backend=backend, change_context=context("source.js"), population_complete=True)
|
||||
outcome = result.question_outcomes[0]
|
||||
assert outcome.status == "unresolved" and outcome.reason == "change_context_incomplete"
|
||||
gaps = [g for g in result.scope.unresolved_boundaries if "context_function_unresolved" in g]
|
||||
assert gaps, "the unresolvable function must be named, not reported as an empty scope"
|
||||
# The gap is owned by the question that asked it, so it cannot block another question.
|
||||
assert gaps[0].endswith(outcome.identity.question_id)
|
||||
assert not any("context_scope_empty" in g for g in result.scope.unresolved_boundaries)
|
||||
|
||||
Reference in New Issue
Block a user