diff --git a/adapters/code_locator.py b/adapters/code_locator.py index 117d6161..45325b65 100644 --- a/adapters/code_locator.py +++ b/adapters/code_locator.py @@ -185,6 +185,7 @@ def _ground_single( fuzzy_threshold: int, max_symbols: int, hits: list[dict] | None = None, + mapping_symbol_names: list[str] | None = None, ) -> list[dict]: """Attempt to ground a single description at the given threshold tier. @@ -219,6 +220,15 @@ def _ground_single( except Exception as exc: logger.debug("[ground] fuzzy validate failed for '%s': %s", description[:60], exc) + if mapping_symbol_names: + for name in mapping_symbol_names: + try: + rows = db.lookup_by_name(name) + for row in rows: + matched_ids.add(row["id"]) + except Exception as exc: + logger.debug("[ground] symbol name lookup failed for '%s': %s", name, exc) + # Stage 1: multi-file fused retrieval (FC-2 fix, v0.4.6). # Previously this stage took only the top-1 BM25 hit via next(), # which collapsed multi-file features to a single anchor — the @@ -358,6 +368,7 @@ def ground_mappings(self, mappings: list[dict]) -> tuple[list[dict], int]: code_regions = self._ground_single( description, db, bm25_thresh, fuzzy_thresh, max_sym, hits=hits, + mapping_symbol_names=mapping.get("symbols"), ) if code_regions: tier_used = tier_idx diff --git a/tests/_extract_headless.py b/tests/_extract_headless.py index 93dca740..584da54f 100644 --- a/tests/_extract_headless.py +++ b/tests/_extract_headless.py @@ -141,13 +141,14 @@ def _extract_step1_excerpt(skill_md: str) -> str: steps_idx = skill_md.find("## Steps") body = skill_md[steps_idx:] if steps_idx != -1 else skill_md - headers = list(_STEP_HEADER_RE.finditer(body)) - if not headers: + step1_re = re.compile(r"^###\s+1\.\s+", re.MULTILINE) + step1_match = step1_re.search(body) + if not step1_match: return body.strip() - first = headers[0] - second_start = headers[1].start() if len(headers) >= 2 else len(body) - return body[first.start():second_start].strip() + next_header = _STEP_HEADER_RE.search(body, step1_match.end()) + end = next_header.start() if next_header else len(body) + return body[step1_match.start():end].strip() def _cache_path(skill_sha: str, transcript_sha: str, model: str) -> Path: diff --git a/tests/test_coverage_loop.py b/tests/test_coverage_loop.py index 06c9b07a..ffd0f4d5 100644 --- a/tests/test_coverage_loop.py +++ b/tests/test_coverage_loop.py @@ -144,7 +144,7 @@ def test_tier0_match_stops_early(self): adapter, db = _make_initialized_adapter() call_count = {"n": 0} - def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None): + def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None, **kwargs): call_count["n"] += 1 if bm25_t == 0.5: # tier 0 return [{"symbol": "found", "file_path": "a.py", @@ -167,7 +167,7 @@ def test_tier1_match_after_tier0_fails(self): adapter, db = _make_initialized_adapter() tiers_tried = [] - def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None): + def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None, **kwargs): tiers_tried.append(bm25_t) if bm25_t == 0.3: # tier 1 return [{"symbol": "weak_match", "file_path": "b.py", @@ -189,7 +189,7 @@ def test_all_tiers_fail_leaves_ungrounded(self): adapter, db = _make_initialized_adapter() tiers_tried = [] - def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None): + def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None, **kwargs): tiers_tried.append(bm25_t) return [] @@ -238,7 +238,7 @@ def test_bm25_search_failure_still_tries_tiers(self): adapter, db = _make_initialized_adapter() tiers_tried = [] - def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None): + def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None, **kwargs): tiers_tried.append((bm25_t, hits)) return [] @@ -272,7 +272,7 @@ def test_grounding_tier_stamped_on_regions(self): """Each code_region gets a grounding_tier field matching the tier used.""" adapter, db = _make_initialized_adapter() - def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None): + def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None, **kwargs): if bm25_t == 0.3: # tier 1 return [ {"symbol": "sym1", "file_path": "a.py", @@ -299,7 +299,7 @@ def test_summary_logging(self, caplog): """Batch summary log is emitted with tier distribution.""" adapter, db = _make_initialized_adapter() - def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None): + def fake_ground_single(desc, db_, bm25_t, fuzzy_t, max_s, hits=None, **kwargs): # "intent zero" matches at tier 0, "intent one" at tier 1, "intent two" never if "zero" in desc and bm25_t == 0.5: return [{"symbol": "a", "file_path": "a.py", diff --git a/tests/test_phase3_integration.py b/tests/test_phase3_integration.py index 6abd67b5..5eb37f3b 100644 --- a/tests/test_phase3_integration.py +++ b/tests/test_phase3_integration.py @@ -61,8 +61,9 @@ def _dump(name: str, data: dict | list) -> None: async def _dump_graph(label: str) -> dict: """Dump raw SurrealDB graph state and write as artifact.""" ledger = get_ledger() - await ledger._ensure_connected() - client = ledger._client + inner = getattr(ledger, "_inner", ledger) + await inner._ensure_connected() + client = inner._client intents = await client.query("SELECT * FROM intent") symbols = await client.query("SELECT * FROM symbol")