symgrep-codesearch 0.6.3__tar.gz → 0.6.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/PKG-INFO +1 -1
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/pyproject.toml +7 -1
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/enclosing.py +7 -4
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/PKG-INFO +1 -1
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/SOURCES.txt +1 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_blocks_extraction.py +2 -1
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_blocks_retrieval.py +2 -1
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_data_symbols.py +2 -1
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_file_structure.py +3 -2
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_index_reconstruct.py +2 -1
- symgrep_codesearch-0.6.4/tests/test_nudge_classify.py +147 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/LICENSE +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/README.md +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/setup.cfg +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/__init__.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/blocks.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/classfile.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/cli.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/data_symbols.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/docsymbols.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/mcp_server.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/mcp_structured.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/report.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/resolve.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/resolve_js.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/resolve_python.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/ripgrep.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/semantic.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/structural.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep/structure.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/dependency_links.txt +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/entry_points.txt +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/requires.txt +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/top_level.txt +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_bulk_describe.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_classfile.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_describe_lane_confinement.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_doc_symbols.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_freshness.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_honest_recall.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_http_ensure.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_index_scope.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_index_worker.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_mcp_structured.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_name_uniqueness.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_nudge_runaway.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_report_filters.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_resolve.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_resolve_js.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_resolve_python.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_resolve_r2.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_review_regressions.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_semantic_freshness_signal.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_sites_and_symbols.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_structural.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_symbol_vocabulary.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_ts_fallback_loud.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_ts_symbol_coverage.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_usage.py +0 -0
- {symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_veccore_adoption.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: symgrep-codesearch
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
4
4
|
Summary: Code search with honest recall — structure-aware grep that tells you what it does not know, plus search by meaning
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/ashdamle/symgrep
|
|
@@ -7,6 +7,12 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
# Semgrep team. The IMPORT name is unchanged — `import symgrep` — so consumers (honestreview, spendguard,
|
|
8
8
|
# 7thsense, warden) are unaffected by the distribution rename. The package dir stays src/symgrep.
|
|
9
9
|
name = "symgrep-codesearch"
|
|
10
|
+
# 0.6.4: grammar fix — C# (.cs) now parses. The tree-sitter-language-pack migration left C# pointing at the
|
|
11
|
+
# legacy grammar name "c_sharp"; the maintained pack's manifest calls it "csharp", so `get_parser("c_sharp")`
|
|
12
|
+
# raised TreeSitterUnavailable and every .cs file silently degraded to nearest_decl. enclosing._TS_PACK_NAME now
|
|
13
|
+
# maps c_sharp→csharp (same mechanism as embedded_template→embeddedtemplate). Patch: a pip-installed user on
|
|
14
|
+
# 0.6.3 gets real C# treesitter spans again. (Also lands this release's dev-only work: the one-shot nudge-cost
|
|
15
|
+
# fix and a CI import fix — neither ships in the wheel.)
|
|
10
16
|
# 0.6.3: MCP surface completeness — TOOL_DESCRIPTION now documents structural=/lang= (the last undescribed
|
|
11
17
|
# params), and a new `symgrep install-mcp` subcommand self-registers the server via `claude mcp add`. No API
|
|
12
18
|
# change; keeps PyPI current with the capability descriptions pip-installed MCP clients see.
|
|
@@ -20,7 +26,7 @@ name = "symgrep-codesearch"
|
|
|
20
26
|
# semantic search. Minor bump (dependency surface changed; no breaking import/CLI/MCP change).
|
|
21
27
|
# 0.5.0: added the public `file_structure` library API (+ its MCP tool and `symgrep structure` CLI), import
|
|
22
28
|
# module-name normalization, and the FileStructure `connects` list (structure schema v2).
|
|
23
|
-
version = "0.6.
|
|
29
|
+
version = "0.6.4"
|
|
24
30
|
description = "Code search with honest recall — structure-aware grep that tells you what it does not know, plus search by meaning"
|
|
25
31
|
readme = "README.md"
|
|
26
32
|
# 3.11+ : the maintained grammar pack (tree-sitter-language-pack, a CORE dep below) ships abi3 wheels for
|
|
@@ -213,10 +213,13 @@ _TS_UNAVAILABLE_ANNOUNCED: List[bool] = [False]
|
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
# symgrep's internal grammar name -> the MAINTAINED pack's (tree-sitter-language-pack) name, ONLY where they
|
|
216
|
-
# differ.
|
|
217
|
-
# ERB/EJS grammar is "embedded_template" in the legacy pack but "embeddedtemplate" in the
|
|
218
|
-
#
|
|
219
|
-
|
|
216
|
+
# differ. Most code languages (TS_LANG_BY_EXT) and "html" resolve identically in both packs; the two that
|
|
217
|
+
# differ: the embedded ERB/EJS grammar is "embedded_template" in the legacy pack but "embeddedtemplate" in the
|
|
218
|
+
# maintained one, and C# is "c_sharp" in the legacy pack but "csharp" in the maintained pack's manifest
|
|
219
|
+
# (requesting "c_sharp" there routes to a download manifest that lacks it → DownloadError, which is why every CI
|
|
220
|
+
# run went red on C# after the pack migration). A name absent here passes through unchanged. This is a fixed
|
|
221
|
+
# spelling map (parsing, not a judgement).
|
|
222
|
+
_TS_PACK_NAME = {"embedded_template": "embeddedtemplate", "c_sharp": "csharp"}
|
|
220
223
|
|
|
221
224
|
|
|
222
225
|
def _ts_parser(lang: str):
|
{symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: symgrep-codesearch
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
4
4
|
Summary: Code search with honest recall — structure-aware grep that tells you what it does not know, plus search by meaning
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/ashdamle/symgrep
|
|
@@ -11,8 +11,9 @@ import tempfile
|
|
|
11
11
|
import pathlib
|
|
12
12
|
|
|
13
13
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
14
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # tests dir on path: checklib imports when run directly (python tests/<file>.py), as CI does
|
|
14
15
|
from symgrep import blocks, structural # noqa: E402
|
|
15
|
-
from
|
|
16
|
+
from checklib import Checks # noqa: E402
|
|
16
17
|
|
|
17
18
|
c = Checks("test_blocks_extraction")
|
|
18
19
|
|
|
@@ -15,7 +15,8 @@ import tempfile
|
|
|
15
15
|
import pathlib
|
|
16
16
|
|
|
17
17
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
18
|
-
|
|
18
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # tests dir on path: checklib imports when run directly (python tests/<file>.py), as CI does
|
|
19
|
+
from checklib import Checks # noqa: E402
|
|
19
20
|
|
|
20
21
|
c = Checks("test_blocks_retrieval")
|
|
21
22
|
|
|
@@ -12,8 +12,9 @@ import tempfile
|
|
|
12
12
|
import pathlib
|
|
13
13
|
|
|
14
14
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
15
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # tests dir on path: checklib imports when run directly (python tests/<file>.py), as CI does
|
|
15
16
|
from symgrep import data_symbols as ds # noqa: E402
|
|
16
|
-
from
|
|
17
|
+
from checklib import Checks # noqa: E402
|
|
17
18
|
|
|
18
19
|
c = Checks("test_data_symbols")
|
|
19
20
|
_SEM_LINE = re.compile(r"^\s+(\d\.\d+)\s+(\S+)\s+(~?\S+):(\d+)\s*$") # honestreview's exact parse
|
|
@@ -16,8 +16,9 @@ import pathlib
|
|
|
16
16
|
import contextlib
|
|
17
17
|
|
|
18
18
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
19
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # tests dir on path: checklib imports when run directly (python tests/<file>.py), as CI does
|
|
19
20
|
from symgrep.structure import file_structure, STRUCTURE_SCHEMA_VERSION # noqa: E402
|
|
20
|
-
from
|
|
21
|
+
from checklib import Checks # noqa: E402
|
|
21
22
|
|
|
22
23
|
c = Checks("test_file_structure")
|
|
23
24
|
|
|
@@ -121,7 +122,7 @@ c.check("CLI == library API (no drift)", rc == 0 and cli_out == s.to_dict())
|
|
|
121
122
|
# 6. a tree-sitter language (Go). tree-sitter is an OPTIONAL dependency: assert the contract that actually
|
|
122
123
|
# holds here — extraction when the grammar is present, LANGUAGE-NAMED honest degradation when it is not
|
|
123
124
|
# (never a silent basis downgrade dressed as a clean result). Both are real contracts, so neither branch skips.
|
|
124
|
-
from
|
|
125
|
+
from checklib import ts_available
|
|
125
126
|
HAVE_TS = ts_available("go") # symgrep's own loader (either grammar pack), not one pack's import name
|
|
126
127
|
|
|
127
128
|
GO = pathlib.Path(d) / "m.go"
|
|
@@ -12,8 +12,9 @@ import sys
|
|
|
12
12
|
import tempfile
|
|
13
13
|
|
|
14
14
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
15
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # tests dir on path: checklib imports when run directly (python tests/<file>.py), as CI does
|
|
15
16
|
from symgrep import semantic # noqa: E402
|
|
16
|
-
from
|
|
17
|
+
from checklib import Checks # noqa: E402
|
|
17
18
|
|
|
18
19
|
c = Checks("test_index_reconstruct")
|
|
19
20
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Guards for the nudge's COST DELIVERY — the fix for the measured $70/day defect (2026-10-07).
|
|
2
|
+
|
|
3
|
+
The classification itself is correct and must stay agentic; what these pin is HOW the verdict is fetched, so
|
|
4
|
+
the expensive path can never come back silently:
|
|
5
|
+
|
|
6
|
+
1. NEVER a Claude Code session / the capped Anthropic plan. The old hook shelled `spendguard ask … --budget 0`,
|
|
7
|
+
which routed to the claude-code subscription lane — a full `claude -p` session (~80K cold tokens, Opus).
|
|
8
|
+
Tests: the hook's miss-path shells the one-shot CLASSIFIER (not `spendguard ask`/`--budget 0`); the model is
|
|
9
|
+
non-anthropic (cannot reach the claude-code lane); and the classifier REFUSES a claude-code executor outright.
|
|
10
|
+
2. STAYS AGENTIC. With no gated LLM path available the verdict is None (fail open) — there is NO mechanical
|
|
11
|
+
string/regex classifier that decides true/false. The WHOLE command is the evidence (never sliced).
|
|
12
|
+
3. CACHE IN FRONT. A repeat command returns from cache without spawning anything.
|
|
13
|
+
|
|
14
|
+
Run: python tests/test_nudge_classify.py (command is `python …`, so the LIVE hook sees no grep)
|
|
15
|
+
"""
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
import types
|
|
20
|
+
|
|
21
|
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
22
|
+
sys.path.insert(0, HERE)
|
|
23
|
+
sys.path.insert(0, os.path.join(os.path.dirname(HERE), "hooks"))
|
|
24
|
+
from checklib import Checks # noqa: E402
|
|
25
|
+
_t = Checks("test_nudge_classify")
|
|
26
|
+
check = _t.check
|
|
27
|
+
|
|
28
|
+
import symgrep_nudge as h # noqa: E402
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ---- 1a. NON-ANTHROPIC model: the classifier can never reach the claude-code lane / the capped plan ----------
|
|
32
|
+
import symgrep_nudge_classify as clf # noqa: E402
|
|
33
|
+
check("classifier default model is NON-anthropic (cannot route to the claude-code session / capped plan)",
|
|
34
|
+
not clf.NUDGE_VENDOR_DEFAULT.lower().startswith("anthropic"),
|
|
35
|
+
f"NUDGE_VENDOR_DEFAULT={clf.NUDGE_VENDOR_DEFAULT!r}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# ---- 1b. The hook's miss-path shells the CLASSIFIER, never `spendguard ask … --budget 0` (the session path) --
|
|
39
|
+
_captured = {}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _fake_run(argv, **kw):
|
|
43
|
+
_captured["argv"] = list(argv)
|
|
44
|
+
_captured["input"] = kw.get("input")
|
|
45
|
+
out = types.SimpleNamespace()
|
|
46
|
+
out.stdout = json.dumps({"code_search": True, "why": "test", "executor": "api", "cost": 1e-5})
|
|
47
|
+
out.stderr = ""
|
|
48
|
+
out.returncode = 0
|
|
49
|
+
return out
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _with(tmp_cache, py_exists=True):
|
|
53
|
+
"""Point the cache at a throwaway sqlite and the classifier python at a real (any) existing file."""
|
|
54
|
+
os.environ["SYMGREP_NUDGE_CACHE"] = tmp_cache
|
|
55
|
+
os.environ["SYMGREP_NUDGE_PYTHON"] = sys.executable if py_exists else os.path.join(tmp_cache, "nope")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
import tempfile # noqa: E402
|
|
59
|
+
_tmp = tempfile.mkdtemp(prefix="nudge-test-")
|
|
60
|
+
_cache = os.path.join(_tmp, "verdicts.sqlite")
|
|
61
|
+
|
|
62
|
+
_orig_run = h.subprocess.run
|
|
63
|
+
h.subprocess.run = _fake_run
|
|
64
|
+
try:
|
|
65
|
+
_with(_cache)
|
|
66
|
+
v = h.judge_is_code_search("rg -n uniquepattern_abc123 src/")
|
|
67
|
+
argv = _captured.get("argv", [])
|
|
68
|
+
check("miss-path verdict is the classifier's JSON (True here)", v is True, f"v={v!r}")
|
|
69
|
+
check("miss-path shells a PYTHON interpreter, not the spendguard binary",
|
|
70
|
+
bool(argv) and "python" in os.path.basename(argv[0]).lower(), f"argv0={argv[:1]}")
|
|
71
|
+
check("miss-path runs symgrep_nudge_classify.py (the one-shot), not `ask`",
|
|
72
|
+
len(argv) >= 2 and argv[1].endswith("symgrep_nudge_classify.py"), f"argv1={argv[1:2]}")
|
|
73
|
+
check("miss-path argv contains NEITHER 'ask' NOR '--budget' (the old session path is gone)",
|
|
74
|
+
"ask" not in argv and "--budget" not in argv, f"argv={argv}")
|
|
75
|
+
check("the WHOLE command is sent to the classifier on stdin (no slice)",
|
|
76
|
+
_captured.get("input") == "rg -n uniquepattern_abc123 src/", f"input={_captured.get('input')!r}")
|
|
77
|
+
|
|
78
|
+
# ---- 3. CACHE IN FRONT: a repeat returns from cache WITHOUT spawning the classifier -----------------------
|
|
79
|
+
_captured.clear()
|
|
80
|
+
|
|
81
|
+
def _boom(*a, **k):
|
|
82
|
+
raise AssertionError("cache HIT must not spawn the classifier subprocess")
|
|
83
|
+
|
|
84
|
+
h.subprocess.run = _boom
|
|
85
|
+
v2 = h.judge_is_code_search("rg -n uniquepattern_abc123 src/")
|
|
86
|
+
check("a repeat command is served from the content cache (no subprocess)", v2 is True, f"v2={v2!r}")
|
|
87
|
+
finally:
|
|
88
|
+
h.subprocess.run = _orig_run
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---- 2a. STAYS AGENTIC: with no gated LLM path, there is NO mechanical verdict (fail open = None) -------------
|
|
92
|
+
for k in ("SYMGREP_SPENDGUARD",):
|
|
93
|
+
os.environ.pop(k, None)
|
|
94
|
+
os.environ["SYMGREP_NUDGE_PYTHON"] = os.path.join(_tmp, "does-not-exist")
|
|
95
|
+
os.environ["SYMGREP_NUDGE_CACHE"] = os.path.join(_tmp, "empty.sqlite")
|
|
96
|
+
# A clearly-code-search command: a regex/keyword classifier WOULD answer True here. The honest answer with no
|
|
97
|
+
# LLM reachable is None (fail open) — proving no mechanical path decides the meaning.
|
|
98
|
+
check("no LLM path reachable → judge returns None (no regex/keyword fallback decides it)",
|
|
99
|
+
h.judge_is_code_search("rg -n 'def handler' src/") is None,
|
|
100
|
+
"a non-None verdict would mean a mechanical classifier exists")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---- 1c. The classifier REFUSES a claude-code executor (the session) even if routing ever drifted there -------
|
|
104
|
+
# Inject a fake spendguard so classify() runs with no network/spend: its adapters.call returns a claude-code hit.
|
|
105
|
+
_fake_sg = types.ModuleType("spendguard")
|
|
106
|
+
_fake_adapters = types.ModuleType("spendguard.adapters")
|
|
107
|
+
_prompt_seen = {}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _fake_call(model, prompt, **kw):
|
|
111
|
+
_prompt_seen["model"] = model
|
|
112
|
+
_prompt_seen["prompt"] = prompt
|
|
113
|
+
_prompt_seen["kw"] = kw
|
|
114
|
+
return {"executor": "claude-code", "text": '{"code_search": true, "why": "x"}', "cost": 0.0, "error": None}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
_fake_adapters.call = _fake_call
|
|
118
|
+
_fake_sg.adapters = _fake_adapters
|
|
119
|
+
_fake_sg.require = lambda *a, **k: None
|
|
120
|
+
sys.modules["spendguard"] = _fake_sg
|
|
121
|
+
sys.modules["spendguard.adapters"] = _fake_adapters
|
|
122
|
+
|
|
123
|
+
res = clf.classify("rg -n foo src/")
|
|
124
|
+
check("classifier REFUSES a claude-code executor (the ~80K Opus session this fix removes)",
|
|
125
|
+
res["code_search"] is None and "claude-code" in (res["error"] or ""),
|
|
126
|
+
f"res={res}")
|
|
127
|
+
check("the refused (session) verdict carries executor='claude-code' for the guard to see",
|
|
128
|
+
res["executor"] == "claude-code", f"executor={res['executor']!r}")
|
|
129
|
+
|
|
130
|
+
# ---- 2b. WHOLE command is the evidence — classify() sends the command verbatim, never a slice ----------------
|
|
131
|
+
long_cmd = "rg -n '" + ("x" * 5000) + "' src/ --glob '*.py'"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _fake_call_ok(model, prompt, **kw):
|
|
135
|
+
_prompt_seen["prompt"] = prompt
|
|
136
|
+
return {"executor": "api", "text": '{"code_search": true, "why": "x"}', "cost": 1e-5, "error": None}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
_fake_adapters.call = _fake_call_ok
|
|
140
|
+
res2 = clf.classify(long_cmd)
|
|
141
|
+
check("classify() sends the ENTIRE command to the model (no truncation of the evidence)",
|
|
142
|
+
_prompt_seen.get("prompt") == long_cmd, "prompt was sliced")
|
|
143
|
+
check("classify() does not pass a strict schema= (so the $0 lane stays reachable)",
|
|
144
|
+
"schema" not in _prompt_seen.get("kw", {}) or _prompt_seen["kw"].get("schema") is None,
|
|
145
|
+
f"kw keys={list(_prompt_seen.get('kw', {}))}")
|
|
146
|
+
|
|
147
|
+
_t.finish()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/requires.txt
RENAMED
|
File without changes
|
{symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/src/symgrep_codesearch.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_describe_lane_confinement.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{symgrep_codesearch-0.6.3 → symgrep_codesearch-0.6.4}/tests/test_semantic_freshness_signal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|