Files
brain-of-reese/tests/unit/test_verbatim_resolver.py
ducoterra b34b8ca672
Build and Push Containers / build-and-push-app (push) Successful in 1m46s
Build and Push Containers / build-and-push-db (push) Successful in 12s
phase: 182_verbatim_show_text
**Phase 182 — final verification pass (all 8 tasks already complete; this was verification + docs + one defect fix).**

- Verified: `app/rag/verbatim.py` (locator grammar, `splitlines()` slice, line-boundary cap, `resolve_answer_blocks`), `SHOW_TEXT_TOOL` + `shown_texts`, `SHOW_TEXT_CLAUSE`, `done.answer_text` (9 fields, key dropped when empty) + `ChatMessageRecord.answer_text` (≤50, 600 000-char cap counted in the 8 M budget), `verbatim.js` + 4 `{verbatim:true}` renderers, `Containerfile` minify step, `.env.example` 3 vars.
- `uv run python -c "…answer_text, show_text_max_chars, show_text_max_blocks"` → `True 12000 5`; each negative refuses startup naming its field; `0` accepted as inert ✅
- `bash .agents/validate.sh` → **validation OK**: 4320 unit+integration tests green, `TOTAL 6849 17 → 99%` (gate app/ >90% OK), `ruff check .` "All checks passed!", `pyright` 0 errors (re-run after my edits, 08:28).
- E2E, each in isolation `--no-cov`: `test_verbatim_show_text.py` 13 passed (panel bytes == `documents.content`, server caption, clipboard == server string, `/document.html?source=…&path=…`, honest unresolved state, reload+share, `show_image` regression, flag-off app) ✅; green: `test_answer_images` `test_harness_aligned_tools` `test_agent_document_tools` `test_markdown_tables` `test_markdown_inline_links_images` `test_svg_document_preview` `test_smoke` `test_document_viewer` `test_markdown_blockquotes` `test_chat_persistence` `test_thinking_timeline` `test_chat_rag` `test_settings_mobile_value_width`.
- **Defect found & fixed (pre-existing, not phase 182):** `tests/e2e/test_admin_settings_panel.py::test_admin_sees_groups_and_source_badges` failed — its whole-page `assert "reese" not in page.content()` tripped on the shell's onboarding chips, which follow the newest saved chats in the one shared E2E DB (a leftover `reeselink.json` question from a tool suite). Scoped the strict sweep to `.settings-shell` and kept a whole-page `reese:reese` credential needle → 12 passed with the leftovers still present.
- Docs: README fixed 2 inconsistencies — Quick Start omitted the **required** `BOR_ADMIN_PASSWORD`/`BOR_SESSION_SECRET` (the app fail-loud refuses boot) and the broken anchor `#chat--` → `#chat-`; full re-read of README (1816 lines) + AGENTS confirmed the phase-182 feature/settings/log/UI-contract text matches the code, and every `.env.example` var + every `Settings` field is documented.
- Notable: kept `resolve_answer_blocks` synchronous on the SSE terminal path (bounded indexed SELECTs, matching the existing `query_log` precedent and the phase's documented fence-lookup bound); no live-infra changes made.
- Next pending phase: none — `todo/` holds only 182 (its 8 task files are in `complete/`; the harness commits + moves `00_phase.md`).
2026-10-15 08:33:12 -04:00

706 lines
25 KiB
Python

"""Unit: the phase-182 verbatim resolver (``app/rag/verbatim.py``, task 02).
The module is the single source of truth for "which exact lines of which
indexed document, and what are their bytes", so the suite covers its three
layers: the pure grammar (:func:`canonical_locator`, :func:`fences_in`),
the pure slicing (:func:`slice_lines`, :func:`cap_slice`), and the
resolver (:func:`document_by_identity`, :func:`block_for`,
:func:`resolve_answer_blocks`).
Session-fixture style follows the agent suite (``tests/unit/test_agent.py``):
DETACHED :class:`~app.models.Document` rows plus a stand-in session for the
one bare ``(source, path)`` lookup — the resolver's SQL is a single
``WHERE`` on the table's unique pair, so a database adds nothing the
contract needs (and the suite runs without the stack up).
"""
from __future__ import annotations
import ast
import inspect
import re
import uuid
from typing import Any, cast
from unittest.mock import MagicMock
import pytest
from sqlalchemy import Select
from sqlalchemy.orm import Session
import app.rag.verbatim as verbatim_module
from app.config import Settings
from app.models import Document
from app.rag.retriever import TRUNCATION_MARKER
from app.rag.verbatim import (
LOCATOR_LANG,
SliceResult,
VerbatimBlock,
block_for,
canonical_locator,
cap_slice,
document_by_identity,
fences_in,
resolve_answer_blocks,
slice_lines,
)
def _settings(**kwargs: Any) -> Settings:
kwargs.setdefault("_env_file", None)
return Settings(**kwargs) # pyright: ignore[reportCallIssue]
def _doc(
source: str = "homelab",
path: str = "a.md",
title: str = "The Title",
content: str = "one\ntwo\nthree",
*,
is_image: bool = False,
) -> Document:
"""A DETACHED row — the resolver reads ``source``/``path``/``title``/
``content``/``is_image`` and nothing else, so no session is needed."""
return Document(
id=uuid.uuid4(),
source=source,
path=path,
full_path=f"/srv/sources/{source}/{path}",
title=title,
content=content,
content_hash="0" * 64,
is_image=is_image,
)
class _FakeDB:
"""Stand-in session for :func:`document_by_identity`'s single lookup.
Records every ``(source, path)`` pair it was asked for, so a test can
assert the FIRST-slash split reaches the ``WHERE`` clause verbatim —
including the traversal-shaped identity, which is simply a pair no row
has.
"""
def __init__(self, docs: list[Document]) -> None:
self.docs = {(d.source, d.path): d for d in docs}
self.lookups: list[tuple[str, str]] = []
def scalar(self, stmt: Select[tuple[Document]]) -> Document | None:
params = stmt.compile().params
pair = (str(params["source_1"]), str(params["path_1"]))
self.lookups.append(pair)
return self.docs.get(pair)
def _session(docs: list[Document]) -> _FakeDB:
return _FakeDB(docs)
def _real(session: _FakeDB) -> Session:
return cast("Session", session)
# --------------------------------------------------------------------------
# canonical_locator — the tolerant grammar in, ONE canonical string out
# --------------------------------------------------------------------------
def test_whole_document_locator_is_itself() -> None:
assert canonical_locator("homelab/a.md") == "homelab/a.md"
@pytest.mark.parametrize(
"raw",
[
"homelab/a.md 12-40",
"homelab/a.md:12-40",
"homelab/a.md#12-40",
"homelab/a.md#L12-L40",
"homelab/a.md L12-L40",
"homelab/a.md 12\u201340", # en dash, the grep-style range
"homelab/a.md 12 - 40 ", # stray spaces around the dash
],
)
def test_every_range_spelling_canonicalizes(raw: str) -> None:
assert canonical_locator(raw) == "homelab/a.md#12-40"
def test_bare_line_number_is_one_line_block() -> None:
assert canonical_locator("homelab/a.md 12") == "homelab/a.md#12-12"
def test_identity_with_slashes_and_case_survives_untouched() -> None:
"""Paths are case-sensitive row values; only the FIRST slash splits."""
assert canonical_locator("Homelab/Notes/Deep/a.md") == "Homelab/Notes/Deep/a.md"
@pytest.mark.parametrize(
"raw",
[
"a.md", # no source
"",
" ",
"homelab/a.md 0-5", # non-positive bound
"homelab/a.md 40-12", # start > end
"homelab/a.md x-y", # non-numeric bound
"homelab/a.md 12-40 extra", # trailing junk after the range
"bor homelab/a.md", # the caller left the language token in
"bor",
"homelab/a.md#", # dangling separator, no range
"homelab/a.md:",
],
)
def test_non_locators_are_refused(raw: str) -> None:
assert canonical_locator(raw) is None
def test_whitespace_bearing_path_with_a_range_is_refused() -> None:
"""The documented limit of the tolerant grammar: the fence's info
string is ONE whitespace-free identity plus the range."""
assert canonical_locator("homelab/my notes/a.md 12-40") is None
# --------------------------------------------------------------------------
# fences_in — the raw locator strings, in answer order
# --------------------------------------------------------------------------
def test_single_fence_yields_its_raw_locator() -> None:
answer = "Before.\n```bor homelab/a.md#12-40\nanything the model typed\n```\nAfter."
assert fences_in(answer) == ["homelab/a.md#12-40"]
def test_fences_come_back_in_answer_order_and_deduped_first() -> None:
answer = (
"```bor homelab/b.md\nb\n```\n"
"words\n"
"```bor homelab/a.md\na\n```\n"
"```bor homelab/b.md\nb again\n```\n"
)
assert fences_in(answer) == ["homelab/b.md", "homelab/a.md"]
def test_bare_language_fence_is_an_ordinary_code_block() -> None:
"""A `` ```bor `` with no path is NOT a locator — and it must not
swallow the real fence that follows it."""
answer = "```bor\nplain code\n```\n```bor homelab/a.md\na\n```"
assert fences_in(answer) == ["homelab/a.md"]
def test_unclosed_fence_contributes_nothing() -> None:
"""Defensive: a half-streamed answer never resolves a partial locator."""
assert fences_in("intro\n```bor homelab/a.md#12-40\nhalf streamed") == []
def test_non_bor_fences_are_ignored() -> None:
answer = "```python\nx = 1\n```\nplain text, no locator"
assert fences_in(answer) == []
def test_nested_backticks_end_the_fence_first() -> None:
"""Documented limitation, the renderer's rule: the fence closes at the
FIRST closer, so text after it is only prose unless it opens a fence."""
answer = "```bor homelab/a.md\n```\nor ```bor homelab/b.md``` inline\n```"
assert fences_in(answer) == ["homelab/a.md"]
def test_indented_fence_opens() -> None:
assert fences_in(" ```bor homelab/a.md\na\n ```") == ["homelab/a.md"]
# --------------------------------------------------------------------------
# slice_lines — the one shared coordinate system
# --------------------------------------------------------------------------
_TWELVE_LINES = "\n".join(f"line {n}" for n in range(1, 13))
def test_slice_whole_document() -> None:
result = slice_lines(_TWELVE_LINES)
assert result == SliceResult(
text=_TWELVE_LINES, first_line=1, last_line=12, total_lines=12, past_end=False
)
def test_slice_offset_only_reads_to_the_end() -> None:
result = slice_lines(_TWELVE_LINES, offset=10)
assert result.text == "line 10\nline 11\nline 12"
assert (result.first_line, result.last_line, result.total_lines) == (10, 12, 12)
assert result.past_end is False
def test_slice_limit_only_starts_at_line_one() -> None:
result = slice_lines(_TWELVE_LINES, limit=2)
assert result.text == "line 1\nline 2"
assert (result.first_line, result.last_line) == (1, 2)
def test_slice_offset_and_limit() -> None:
result = slice_lines(_TWELVE_LINES, offset=12, limit=1)
assert result.text == "line 12"
assert (result.first_line, result.last_line) == (12, 12)
def test_overshooting_limit_clamps_to_the_total() -> None:
result = slice_lines(_TWELVE_LINES, offset=11, limit=100)
assert result.text == "line 11\nline 12"
assert (result.first_line, result.last_line, result.past_end) == (11, 12, False)
def test_offset_past_the_end_refuses_with_the_true_total() -> None:
result = slice_lines(_TWELVE_LINES, offset=13, limit=5)
assert result.past_end is True
assert result.text == ""
assert result.total_lines == 12
def test_empty_document_is_past_end() -> None:
result = slice_lines("")
assert result == SliceResult(
text="", first_line=1, last_line=0, total_lines=0, past_end=True
)
def test_limit_below_one_is_an_empty_past_end_slice() -> None:
"""A contract violation from the caller: refuse loudly-by-shape, never
raise (the refusal text belongs to the caller)."""
result = slice_lines(_TWELVE_LINES, offset=3, limit=0)
assert result.past_end is True
assert result.text == ""
assert result.total_lines == 12
def test_line_numbers_agree_with_splitlines() -> None:
"""The grep → read(offset) coordinate system: the line ``grep`` calls
``N`` is what ``offset=N, limit=1`` returns, byte for byte."""
content = "# header\n\ntext one\n indented\nlast"
lines = content.splitlines()
for number, expected in enumerate(lines, start=1):
result = slice_lines(content, offset=number, limit=1)
assert result.text == expected
assert (result.first_line, result.last_line) == (number, number)
# --------------------------------------------------------------------------
# cap_slice — the character budget at a LINE boundary
# --------------------------------------------------------------------------
def test_cap_under_budget_returns_the_text_untouched() -> None:
text, last, truncated = cap_slice("one\ntwo\nthree", 1, 100)
assert (text, last, truncated) == ("one\ntwo\nthree", 3, False)
def test_cap_under_budget_offsets_from_the_slices_first_line() -> None:
_text, last, truncated = cap_slice("ten\neleven", 10, 100)
assert (last, truncated) == (11, False)
def test_cap_empty_text_reports_the_first_line() -> None:
assert cap_slice("", 7, 100) == ("", 7, False)
def test_cap_counts_a_slice_that_ends_on_a_blank_line() -> None:
"""Phase 182 (task 05) defect pin: a slice whose LAST line is blank
legitimately ends with ``"\\n"`` (that empty line IS part of the text
shown), so the extent counts it. ``splitlines()`` drops the trailing
empty element — which made the caption claim one line fewer than the
block displays AND made the canonical locator disagree with the same
range resolved through any other entry point (the tool branch), so the
same block showed twice."""
text, last, truncated = cap_slice("one\ntwo\n", 4, 100)
assert (text, last, truncated) == ("one\ntwo\n", 6, False)
def test_cap_cuts_on_a_line_boundary_and_appends_the_shared_marker() -> None:
text, last, truncated = cap_slice("one\ntwo\nthree", 1, 9) # line 3 is cut
assert truncated is True
assert text == f"one\ntwo\n{TRUNCATION_MARKER}"
# The marker is not content: the range stops at the last WHOLE line.
assert last == 2
def test_cap_landing_exactly_on_a_line_end_keeps_that_line() -> None:
"""The budget's edge IS the line's terminator — the line fits."""
text, last, truncated = cap_slice("one\ntwo\nthree", 1, 7) # exactly "one\ntwo"
assert truncated is True
assert text == f"one\ntwo\n{TRUNCATION_MARKER}"
assert last == 2
def test_cap_never_claims_a_line_whose_terminator_falls_outside_the_budget() -> None:
text, last, truncated = cap_slice("1\n22\n333\n4444", 1, 7) # "1\n22\n33"
assert truncated is True
assert text == f"1\n22\n{TRUNCATION_MARKER}"
assert last == 2
def test_cap_shorter_than_the_first_line_cuts_it_mid_way() -> None:
"""The one documented sub-line cut — and it still ends with the marker."""
text, last, truncated = cap_slice("abcdefghij\nsecond", 4, 4)
assert truncated is True
assert text == f"abcd\n{TRUNCATION_MARKER}"
assert last == 4
@pytest.mark.parametrize("cap", [0, -1])
def test_cap_zero_or_negative_is_a_loud_mis_wiring(cap: int) -> None:
with pytest.raises(ValueError, match="cap_slice"):
cap_slice("anything", 1, cap)
# --------------------------------------------------------------------------
# document_by_identity — the one bare lookup
# --------------------------------------------------------------------------
def test_identity_lookup_hits() -> None:
doc = _doc()
session = _session([doc])
assert document_by_identity(_real(session), "homelab/a.md") is doc
assert session.lookups == [("homelab", "a.md")]
def test_identity_lookup_misses() -> None:
session = _session([_doc()])
assert document_by_identity(_real(session), "homelab/missing.md") is None
def test_traversal_shaped_identity_is_simply_a_row_that_does_not_exist() -> None:
session = _session([_doc()])
assert document_by_identity(_real(session), "../../etc/passwd") is None
assert session.lookups == [("..", "../etc/passwd")]
def test_first_slash_splits_identity_when_the_path_has_slashes() -> None:
doc = _doc(path="notes/deep/a.md")
session = _session([doc])
assert document_by_identity(_real(session), "homelab/notes/deep/a.md") is doc
assert session.lookups == [("homelab", "notes/deep/a.md")]
def test_identity_without_a_slash_never_touches_the_database() -> None:
"""A bare source name is never a document (the agent's contract)."""
session = _session([_doc()])
assert document_by_identity(_real(session), "homelab") is None
assert session.lookups == []
# --------------------------------------------------------------------------
# block_for — the block a locator names
# --------------------------------------------------------------------------
def test_block_whole_document() -> None:
doc = _doc(content="one\ntwo\nthree")
block = block_for(_real(_session([doc])), "homelab/a.md", cap=1000)
assert block is not None
assert (block.source, block.path, block.title) == ("homelab", "a.md", "The Title")
assert (block.start_line, block.end_line, block.total_lines) == (1, 3, 3)
assert block.text == "one\ntwo\nthree"
assert block.truncated is False
assert block.locator == "homelab/a.md"
def test_block_with_a_named_range_carries_it_in_the_locator() -> None:
doc = _doc(content="\n".join(f"line {n}" for n in range(1, 13)))
block = block_for(
_real(_session([doc])), "homelab/a.md", offset=12, limit=2, cap=1000
)
assert block is not None
assert (block.start_line, block.end_line, block.total_lines) == (12, 12, 12)
assert block.text == "line 12"
assert block.locator == "homelab/a.md#12-12"
def test_block_of_an_image_document_is_refused() -> None:
"""Image display belongs to ``show_image`` (LOCKED A6)."""
doc = _doc(is_image=True)
assert block_for(_real(_session([doc])), "homelab/a.md", cap=1000) is None
def test_block_of_an_unknown_path_is_refused() -> None:
assert block_for(_real(_session([_doc()])), "homelab/nope.md", cap=1000) is None
def test_block_of_a_past_end_range_is_refused() -> None:
doc = _doc(content="one\ntwo")
assert block_for(_real(_session([doc])), "homelab/a.md", offset=9, cap=1000) is None
def test_capped_blocks_range_describes_the_lines_actually_shown() -> None:
doc = _doc(content="1\n22\n333\n4444")
block = block_for(_real(_session([doc])), "homelab/a.md", cap=6) # cuts line 3
assert block is not None
assert block.truncated is True
assert block.text == f"1\n22\n{TRUNCATION_MARKER}"
assert (block.start_line, block.end_line, block.total_lines) == (1, 2, 4)
assert block.locator == "homelab/a.md#1-2"
def test_block_reuses_a_callers_resolved_document() -> None:
"""The ``show_text`` branch already resolved the row (with suggestions);
the block build must not look it up twice."""
db = MagicMock()
block = block_for(cast("Session", db), "homelab/a.md", cap=1000, doc=_doc())
assert block is not None
assert block.locator == "homelab/a.md"
db.scalar.assert_not_called()
# --------------------------------------------------------------------------
# resolve_answer_blocks — the done-time fusion
# --------------------------------------------------------------------------
_TEN = "\n".join(f"line {n}" for n in range(1, 11))
def _answer(*locators: str) -> str:
return "".join(f"```bor {loc}\nmodel text\n```\n" for loc in locators)
def _shown(locator: str, *, first: int = 1, last: int = 3) -> VerbatimBlock:
return VerbatimBlock(
source="homelab",
path="a.md",
title="The Title",
start_line=first,
end_line=last,
total_lines=10,
text="one\ntwo\nthree",
locator=locator,
)
def test_no_fences_and_no_shown_blocks_is_empty() -> None:
assert resolve_answer_blocks(
_real(_session([])), "a plain answer", [], _settings()
) == []
def test_a_fence_resolves_without_any_tool_call() -> None:
doc = _doc(content=_TEN)
blocks = resolve_answer_blocks(
_real(_session([doc])),
_answer("homelab/a.md#4-5"),
[],
_settings(),
)
assert len(blocks) == 1
assert blocks[0].locator == "homelab/a.md#4-5"
assert blocks[0].text == "line 4\nline 5"
assert (blocks[0].start_line, blocks[0].end_line) == (4, 5)
def test_shown_blocks_are_appended_when_the_answer_locates_nothing() -> None:
blocks = resolve_answer_blocks(
_real(_session([])),
"no fence here",
[_shown("homelab/a.md"), _shown("homelab/a.md#4-6", first=4, last=6)],
_settings(),
)
assert [b.locator for b in blocks] == ["homelab/a.md", "homelab/a.md#4-6"]
def test_fence_wins_over_the_same_locator_from_shown() -> None:
"""ONE block per canonical locator, placed at the FENCE (the fence
controls placement)."""
doc = _doc(content=_TEN)
shown = _shown("homelab/a.md#2-3", first=2, last=3)
blocks = resolve_answer_blocks(
_real(_session([doc])),
"intro\n" + _answer("homelab/a.md#2-3") + "outro",
[shown, _shown("homelab/a.md#2-3", first=2, last=3)],
_settings(),
)
assert len(blocks) == 1
assert blocks[0].text == "line 2\nline 3"
def test_capped_fence_dedupes_against_the_same_capped_shown_block() -> None:
"""Phase 182 (task 05) defect pin: a char-capped fence carries a
NARROWER locator than the one its fence wrote (the cut extent) — and
that is exactly the key the ``show_text`` tool's same-range block
carries, so the pair is ONE block, placed at the fence."""
doc = _doc(content=_TEN)
settings = _settings(show_text_max_chars=20)
fenced = resolve_answer_blocks(
_real(_session([doc])), _answer("homelab/a.md"), [], settings
)
assert len(fenced) == 1 and fenced[0].truncated
assert fenced[0].locator == f"homelab/a.md#1-{fenced[0].end_line}"
shown = _shown(fenced[0].locator, last=fenced[0].end_line)
fused = resolve_answer_blocks(
_real(_session([doc])), _answer("homelab/a.md"), [shown], settings
)
assert [b.locator for b in fused] == [fenced[0].locator]
def test_two_fences_keep_answer_order_then_the_unlocated_shown() -> None:
second = _doc(path="b.md", title="B", content="bee\nbee two")
first = _doc(path="a.md", content=_TEN)
shown_a = _shown("homelab/a.md")
shown_c = _shown("homelab/c.md")
blocks = resolve_answer_blocks(
_real(_session([first, second])),
_answer("homelab/b.md", "homelab/a.md#9-10"),
[shown_a, shown_c],
_settings(),
)
# fences first, in answer order — then the shown blocks the answer
# never located, in their original call order (the whole-document
# ``homelab/a.md`` block is a DIFFERENT canonical locator from the
# fenced ``homelab/a.md#9-10``, so it stays unlocated).
assert [b.locator for b in blocks] == [
"homelab/b.md",
"homelab/a.md#9-10",
"homelab/a.md",
"homelab/c.md",
]
def test_block_budget_truncates_the_list() -> None:
doc = _doc(content=_TEN)
blocks = resolve_answer_blocks(
_real(_session([doc])),
_answer("homelab/a.md#1-2", "homelab/a.md#4-5"),
[_shown("homelab/a.md#7-8", first=7, last=8)],
_settings(show_text_max_blocks=1),
)
assert [b.locator for b in blocks] == ["homelab/a.md#1-2"]
@pytest.mark.parametrize(
"overrides",
[
{"answer_text": False},
{"show_text_max_blocks": 0},
{"show_text_max_chars": 0},
{"answer_text": False, "show_text_max_blocks": 0},
{"answer_text": False, "show_text_max_chars": 0},
{"show_text_max_blocks": 0, "show_text_max_chars": 0},
],
)
def test_every_kill_switch_combination_is_inert(overrides: dict[str, Any]) -> None:
doc = _doc(content=_TEN)
assert (
resolve_answer_blocks(
_real(_session([doc])),
_answer("homelab/a.md#4-5"),
[_shown("homelab/a.md#7-8", first=7, last=8)],
_settings(**overrides),
)
== []
)
def test_unresolvable_fence_is_simply_absent() -> None:
blocks = resolve_answer_blocks(
_real(_session([_doc(content=_TEN)])),
_answer("elsewhere/nope.md"),
[],
_settings(),
)
assert blocks == []
def test_image_document_fence_is_absent() -> None:
blocks = resolve_answer_blocks(
_real(_session([_doc(content=_TEN, is_image=True)])),
_answer("homelab/a.md#2-3"),
[],
_settings(),
)
assert blocks == []
def test_a_duplicated_fence_appears_once() -> None:
doc = _doc(content=_TEN)
blocks = resolve_answer_blocks(
_real(_session([doc])),
_answer("homelab/a.md#2-3") + "words\n" + _answer("homelab/a.md 2-3"),
[],
_settings(),
)
assert [b.locator for b in blocks] == ["homelab/a.md#2-3"]
def test_malformed_fence_is_ignored_without_reserving_its_text() -> None:
"""A locator the grammar refuses never reaches the resolver at all."""
blocks = resolve_answer_blocks(
_real(_session([_doc(content=_TEN)])),
_answer("homelab/a.md 40-12"),
[],
_settings(),
)
assert blocks == []
def test_a_loosened_grammar_still_refuses_non_numeric_bounds(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""The defensive branch: the range regex above guarantees digit bounds,
but if it is ever loosened, :func:`canonical_locator` still refuses a
non-numeric bound instead of raising out of ``int()``."""
monkeypatch.setattr(
verbatim_module,
"_TRAILING_RANGE_RE",
re.compile(r"[ :#](?P<range>[^ ]*)$"), # the separator, then ANY tail
)
assert canonical_locator("homelab/a.md:x-y") is None
def test_the_character_cap_applies_to_fenced_blocks() -> None:
doc = _doc(content=_TEN)
blocks = resolve_answer_blocks(
_real(_session([doc])),
_answer("homelab/a.md"),
[],
_settings(show_text_max_chars=20),
)
assert len(blocks) == 1
assert blocks[0].truncated is True
assert blocks[0].text.endswith(TRUNCATION_MARKER)
# 20 characters land exactly on the terminator of "line 3", so lines
# 1-3 are whole and the caption stops at 3 (line 4 is cut).
assert blocks[0].text == f"line 1\nline 2\nline 3\n{TRUNCATION_MARKER}"
assert blocks[0].end_line == 3
assert blocks[0].locator == "homelab/a.md#1-3"
def test_locator_language_constant_is_shared() -> None:
assert LOCATOR_LANG == "bor"
def test_module_never_imports_the_agent() -> None:
"""The one-way import rule, read off the AST (the docstring names the
agent on purpose to explain the rule, so a substring check would
prove nothing): ``agent.py`` imports this module's pure half; a
reverse import would cycle."""
tree = ast.parse(inspect.getsource(verbatim_module))
imports: list[str] = []
for node in ast.walk(tree):
if isinstance(node, ast.Import):
imports.extend(alias.name for alias in node.names)
elif isinstance(node, ast.ImportFrom):
imports.extend(f"{node.module or ''}.{alias.name}" for alias in node.names)
offending = [name for name in imports if name.startswith("app.rag.agent")]
assert offending == []
def test_the_fence_scan_stops_once_the_block_budget_is_spent() -> None:
"""A fence-stuffed answer costs at most ``show_text_max_blocks``
successful lookups: once the display budget is in, the scan stops —
the truncation to the same number makes every later block
unreachable, and the resolver runs on the request's event loop."""
session = _session([_doc(content=_TEN), _doc(path="b.md", title="B", content="bee\ntwo")])
blocks = resolve_answer_blocks(
_real(session),
_answer("homelab/a.md", "homelab/b.md", "homelab/a.md#2-3"),
[],
_settings(show_text_max_blocks=2),
)
assert [b.locator for b in blocks] == ["homelab/a.md", "homelab/b.md"]
assert len(session.lookups) == 2