phase: 182_verbatim_show_text
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 — 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`).
This commit is contained in:
2026-10-15 08:33:12 -04:00
parent 814a400e6d
commit b34b8ca672
104 changed files with 10852 additions and 203 deletions
+7 -7
View File
@@ -47,7 +47,7 @@ from app.config import Settings
from app.db import SessionLocal
from app.models import Document, FolderSummary, GitSource
from app.rag import agent
from app.rag.agent import AGENT_TOOLS, AgentHolder, run_agent
from app.rag.agent import AGENT_TOOLS, SHOW_TEXT_TOOL, AgentHolder, run_agent
from app.rag.llm import (
LLMClient,
RetryPiece,
@@ -319,7 +319,7 @@ def test_ls_top_level_lists_registered_sources_through_run_agent(
holder, llm = _run_call(db, "ls", {})
assert llm.requests[0][1] == AGENT_TOOLS
assert llm.requests[0][1] == [*AGENT_TOOLS, SHOW_TEXT_TOOL]
assert llm.requests[1][0][3]["content"].startswith(
"2 sources:\n"
"\n"
@@ -482,7 +482,7 @@ def test_ls_path_like_scope_unknown_source_gets_no_source_refusal(kb, src, db) -
agent.NO_SOURCE_NOT_A_DIRECTORY.format(scope="app")
)
assert holder.tool_calls == 0 and holder.read_docs == []
assert llm.requests[1][1] == AGENT_TOOLS # rejected → tools stay offered
assert llm.requests[1][1] == [*AGENT_TOOLS, SHOW_TEXT_TOOL] # rejected → tools stay offered
def test_ls_unknown_folder_gets_not_a_folder_with_parents_subfolders(
@@ -505,7 +505,7 @@ def test_ls_unknown_folder_gets_not_a_folder_with_parents_subfolders(
"backups/ containers/ networking/"
)
assert holder.tool_calls == 0 and holder.read_docs == []
assert llm.requests[1][1] == AGENT_TOOLS # rejected → tools stay offered
assert llm.requests[1][1] == [*AGENT_TOOLS, SHOW_TEXT_TOOL] # rejected → tools stay offered
# ---------- read (the canonical combined source/path form) ----------
@@ -595,7 +595,7 @@ def test_read_bare_path_single_source_suggestion_then_corrected_read(kb, db) ->
"No document at 'deep/nested/doc.md' — "
"did you mean 'Alpha/deep/nested/doc.md'?"
)
assert llm.requests[1][1] == AGENT_TOOLS
assert llm.requests[1][1] == [*AGENT_TOOLS, SHOW_TEXT_TOOL]
# Round 2: the corrected combined identity succeeds — the full
# content (plus the phase-106 D5 date line), the holder records the
# row, and it counts.
@@ -604,7 +604,7 @@ def test_read_bare_path_single_source_suggestion_then_corrected_read(kb, db) ->
"date: 2024-06-15\n"
"FULL-TEXT"
)
assert llm.requests[2][1] == AGENT_TOOLS
assert llm.requests[2][1] == [*AGENT_TOOLS, SHOW_TEXT_TOOL]
# SEC-14-04: short-lived session loads fresh copies
assert [d.id for d in holder.read_docs] == [created.id]
assert holder.tool_calls == 1 # only the corrected read executed
@@ -670,7 +670,7 @@ def test_grep_whole_kb_through_run_agent(kb, db) -> None:
holder, llm = _run_call(db, "grep", {"pattern": "needle"})
# Offered: the first request carries AGENT_TOOLS (the 3-tool list).
assert llm.requests[0][1] == AGENT_TOOLS
assert llm.requests[0][1] == [*AGENT_TOOLS, SHOW_TEXT_TOOL]
# Executed against the real DB: catalog order, grep-style lines.
assert llm.requests[1][0][3]["content"].startswith(
"Alpha/a/one.md:2: needle in one\n"