diff --git a/.agents/PLAN.md b/.agents/PLAN.md index 8c7cefa..6e892f6 100644 --- a/.agents/PLAN.md +++ b/.agents/PLAN.md @@ -84,6 +84,25 @@ A15 — `thinking`, `tool`, unlimited tool rounds under never-truncated contract is unchanged; the `read`-tool cap is the only exception, owner-permitted 2026-09-10. +Phase 182 (verbatim text display, owner chat 2026-10-14) adds +**`show_text(path, offset?, limit?)` as the fifth agent tool** — offered +only when `BOR_ANSWER_TEXT=1` (the default), gated exactly like +`show_image`, with its own `` clause and its own kill switch — and +the **additive `done.answer_text`** field above. The new settings are +`BOR_ANSWER_TEXT` (master switch, ON), `BOR_SHOW_TEXT_MAX_CHARS` (per-block +budget, 12 000) and `BOR_SHOW_TEXT_MAX_BLOCKS` (per-answer budget, 5), all +following the `agent_max_rounds` pattern (`0` inert, negative refuses +startup). The principle in one sentence: **the model points, the server +supplies the bytes** — a ` ```bor source/path 12-40 ` fence or a +`show_text` call names a location (canonical locator `source/path` or +`source/path#start-end`, 1-based and inclusive), and the displayed text is +sliced from `documents.content` server-side, so what the user copies is the +knowledge base, never a re-typed approximation. **A1–A6 and A15 are +otherwise +UNCHANGED:** no new SSE event type, no new table or column, no new model, +endpoint or transport, no change to retrieval, the honesty gate, the +persona text or the embedding dimension. + --- ## 3. High-Level Architecture @@ -129,7 +148,9 @@ POST /api/chat {message, history?} (auth: require_user) → cosine top-100 ∪ FTS top-30 → RRF fuse (k=60) [A7] ├─ HIGH (cosine ≥ 0.62 OR fts_hits > 0): │ persona + + + full top-2 - │ + → agent loop (ls/read/grep; round-capped + │ + → agent loop (ls/read/grep, plus show_image when + │ BOR_ANSWER_IMAGES=1 and show_text when BOR_ANSWER_TEXT=1 — the two + │ "show the user an artifact" tools, gated independently; round-capped │ BOR_AGENT_MAX_ROUNDS=10, 0 = tools off) → turbo streamed └─ LOW (A8): DEFLECT_MODE prompt (weak titles only, no tools, byte-identical direct-stream path) → turbo streamed @@ -139,7 +160,15 @@ POST /api/chat {message, history?} (auth: require_user) SSE frames (`data: \n\n`): `thinking` (before first delta) → `tool` (grounded turns, one per model call) → `retry` (pre-first-frame restarts) → `delta` (answer tokens) → `done` `{deflected, sources[], -suggestions[], budget_exhausted?}` (terminal). Failure: `error` (terminal — no `done`, no +suggestions[], budget_exhausted?, answer_text[]?}` (terminal). **Phase 182 +extends the `done` frame ADDITIVELY** — `answer_text` is the list of +server-resolved verbatim blocks (`locator`, `source`, `path`, `start`, +`end`, `total_lines`, `text`, `format`, `truncated`) the answer displayed; +there is **no eighth event type**, the key is OMITTED when no block was +displayed, and with `BOR_ANSWER_TEXT=0` it is absent on every turn (the +frame is then byte-identical to pre-phase). The same array persists on the +saved chat record, so restore and the anonymous shared page re-render the +panels from the server's bytes. Failure: `error` (terminal — no `done`, no `query_log` row; a pre-stream DB outage is a plain 503 JSON). A `tools=None` request never emits a `tool` frame; a round-capped turn whose final reply carries no visible content answers with the budget @@ -273,8 +302,11 @@ scripts.…`, and tests all honor it. question=… embed_ms=… top_score=… fts_hits=… summary_hits=… tuning=N kb_chars=N history_msgs=N threshold=… deflected=… sources=… thinking_chars=… tool_calls=N rounds=N cap_hit=0|1 total_ms=… - retries=N scaffold_stripped=N + retries=N scaffold_stripped=N verbatim_blocks=N ``` + (`verbatim_blocks=` — phase 182 — is the count of verbatim display blocks + actually SENT on the `done` frame, `0` on every turn without them, + deflected included.) (`sources=` = retrieval + agent-read docs, deduped; `tool_calls=` executed only; a cancelled turn writes neither line nor `query_log` row.) diff --git a/.agents/phases/todo/182_verbatim_show_text/00_phase.md b/.agents/phases/complete/182_verbatim_show_text/00_phase.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/00_phase.md rename to .agents/phases/complete/182_verbatim_show_text/00_phase.md diff --git a/.agents/phases/todo/182_verbatim_show_text/01_settings_and_kill_switch.md b/.agents/phases/complete/182_verbatim_show_text/01_settings_and_kill_switch.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/01_settings_and_kill_switch.md rename to .agents/phases/complete/182_verbatim_show_text/01_settings_and_kill_switch.md diff --git a/.agents/phases/todo/182_verbatim_show_text/02_verbatim_resolver_module.md b/.agents/phases/complete/182_verbatim_show_text/02_verbatim_resolver_module.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/02_verbatim_resolver_module.md rename to .agents/phases/complete/182_verbatim_show_text/02_verbatim_resolver_module.md diff --git a/.agents/phases/todo/182_verbatim_show_text/03_show_text_tool.md b/.agents/phases/complete/182_verbatim_show_text/03_show_text_tool.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/03_show_text_tool.md rename to .agents/phases/complete/182_verbatim_show_text/03_show_text_tool.md diff --git a/.agents/phases/todo/182_verbatim_show_text/04_prompt_teaching_clause.md b/.agents/phases/complete/182_verbatim_show_text/04_prompt_teaching_clause.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/04_prompt_teaching_clause.md rename to .agents/phases/complete/182_verbatim_show_text/04_prompt_teaching_clause.md diff --git a/.agents/phases/todo/182_verbatim_show_text/05_done_frame_and_persistence.md b/.agents/phases/complete/182_verbatim_show_text/05_done_frame_and_persistence.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/05_done_frame_and_persistence.md rename to .agents/phases/complete/182_verbatim_show_text/05_done_frame_and_persistence.md diff --git a/.agents/phases/todo/182_verbatim_show_text/06_markdown_locator_and_panel_css.md b/.agents/phases/complete/182_verbatim_show_text/06_markdown_locator_and_panel_css.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/06_markdown_locator_and_panel_css.md rename to .agents/phases/complete/182_verbatim_show_text/06_markdown_locator_and_panel_css.md diff --git a/.agents/phases/todo/182_verbatim_show_text/07_hydration_and_copy_buttons.md b/.agents/phases/complete/182_verbatim_show_text/07_hydration_and_copy_buttons.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/07_hydration_and_copy_buttons.md rename to .agents/phases/complete/182_verbatim_show_text/07_hydration_and_copy_buttons.md diff --git a/.agents/phases/todo/182_verbatim_show_text/08_e2e_and_docs_pass.md b/.agents/phases/complete/182_verbatim_show_text/08_e2e_and_docs_pass.md similarity index 100% rename from .agents/phases/todo/182_verbatim_show_text/08_e2e_and_docs_pass.md rename to .agents/phases/complete/182_verbatim_show_text/08_e2e_and_docs_pass.md diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.md new file mode 100644 index 0000000..428828c --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.md @@ -0,0 +1 @@ +(no final assistant message — see the .err log) diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.md.status new file mode 100644 index 0000000..65a791b --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.md.status @@ -0,0 +1 @@ +error: no final assistant text diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.validate new file mode 100644 index 0000000..04830a0 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a1.validate @@ -0,0 +1,143 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 12%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 17%] +........................................................................ [ 19%] +........................................................................ [ 20%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 32%] +........................................................................ [ 33%] +........................................................................ [ 35%] +........................................................................ [ 36%] +........................................................................ [ 38%] +........................................................................ [ 40%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 53%] +........................................................................ [ 54%] +........................................................................ [ 56%] +........................................................................ [ 57%] +........................................................................ [ 59%] +........................................................................ [ 61%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 65%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 78%] +........................................................................ [ 80%] +........................................................................ [ 81%] +........................................................................ [ 83%] +........................................................................ [ 85%] +........................................................................ [ 86%] +........................................................................ [ 88%] +........................................................................ [ 89%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 94%] +........................................................................ [ 96%] +........................................................................ [ 97%] +........................................................................ [ 99%] +................... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 292 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 549 0 100% +-------------------------------------------------- +TOTAL 6849 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.md new file mode 100644 index 0000000..7a6e811 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.md @@ -0,0 +1,10 @@ +**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`). diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.validate new file mode 100644 index 0000000..04830a0 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__00_phase.a2.validate @@ -0,0 +1,143 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 12%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 17%] +........................................................................ [ 19%] +........................................................................ [ 20%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 32%] +........................................................................ [ 33%] +........................................................................ [ 35%] +........................................................................ [ 36%] +........................................................................ [ 38%] +........................................................................ [ 40%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 53%] +........................................................................ [ 54%] +........................................................................ [ 56%] +........................................................................ [ 57%] +........................................................................ [ 59%] +........................................................................ [ 61%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 65%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 78%] +........................................................................ [ 80%] +........................................................................ [ 81%] +........................................................................ [ 83%] +........................................................................ [ 85%] +........................................................................ [ 86%] +........................................................................ [ 88%] +........................................................................ [ 89%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 94%] +........................................................................ [ 96%] +........................................................................ [ 97%] +........................................................................ [ 99%] +................... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 292 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 549 0 100% +-------------------------------------------------- +TOTAL 6849 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.md new file mode 100644 index 0000000..22d3422 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.md @@ -0,0 +1,19 @@ +**Implemented (task 01 — settings + kill switch, inert)** +- `app/config.py`: `answer_text: bool = True` (master switch, default ON, docstring names the env var + the exact off-state), `show_text_max_chars: int = 12_000`, `show_text_max_blocks: int = 5`, plus two `@field_validator`s (`…_non_negative`) that fail startup naming the field; `0` accepted as inert. +- `app/core/settings_catalog.py`: three `SettingMeta` rows in the `Agent tools` group (`Answer text` / `Show text max chars` / `Show text max blocks`), plain — not secret, not restart-required, overridable. +- `.env.example`: `BOR_ANSWER_TEXT=true`, `BOR_SHOW_TEXT_MAX_CHARS=12000`, `BOR_SHOW_TEXT_MAX_BLOCKS=5` in the agent-tools block with the `0`/negative semantics (dotenv-parsed and verified). +- Tests: 5 new unit cases (`test_config.py`: defaults, env overrides, `0` inert, each negative refuses naming the field), 2 new catalogue pins (row group/label/flags + annotation/defaults), 1 new integration row-contract (`GET` shape, raw PUT → live, `0` storable, negative → 422 storing nothing, DELETE → default, anon 403), 1 new live-apply test (`_save` + `invalidate_settings()` → resolves without restart, reset returns defaults). No consumer reads the fields — no app behavior touched. +- Stale-doc fix in previously-completed work: hard-coded "78 items/rows/settings" prose (already wrong at 79) made generic in `app/api/admin_settings.py`, `tests/integration/test_admin_settings_api.py`, `tests/e2e/test_admin_settings_panel.py`, `tests/e2e/test_settings_mobile_value_width.py`. + +**Gates (all green)** +- `uv run pytest` → **4274 passed** (unit + integration). +- `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99%**; `app/config.py` 100%, `app/core/settings_catalog.py` 100%, `app/api/admin_settings.py` 100%. +- `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors. +- `uv run pytest tests/e2e/test_admin_settings_panel.py -v --no-cov` → 12 passed in isolation (the generated panel renders the three new rows). +- Criteria checks: `get_settings()` prints `True 12000 5`; `BOR_SHOW_TEXT_MAX_CHARS=-1` / `BOR_SHOW_TEXT_MAX_BLOCKS=-1` each raise naming their field. + +**Docs**: README env table — three new rows in *Agent tools* (ON-by-default rationale, line-boundary truncation, `0` = inert, negative refuses startup). No AGENTS.md change needed (it carries no env table; rule 5's verbatim-panel UI contract belongs to the phase's later/final task). + +**Notable decisions**: budgets use the `>= 0` family (`0` = inert) rather than `> 0`, per LOCKED A8; block-cap error text is `must be >= 0 (blocks)`. No new consumers, no schemas/agent/prompts/frontend touched. + +**Next pending task**: `.agents/phases/todo/182_verbatim_show_text/02_verbatim_resolver_module.md`. diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.validate new file mode 100644 index 0000000..467fd90 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__01_settings_and_kill_switch.a1.validate @@ -0,0 +1,139 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 5%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 10%] +........................................................................ [ 11%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 20%] +........................................................................ [ 21%] +........................................................................ [ 23%] +........................................................................ [ 25%] +........................................................................ [ 26%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 32%] +........................................................................ [ 33%] +........................................................................ [ 35%] +........................................................................ [ 37%] +........................................................................ [ 38%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 47%] +........................................................................ [ 48%] +........................................................................ [ 50%] +........................................................................ [ 52%] +........................................................................ [ 53%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 65%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 74%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 79%] +........................................................................ [ 80%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 89%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 94%] +........................................................................ [ 96%] +........................................................................ [ 97%] +........................................................................ [ 99%] +.......................... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 280 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 454 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 156 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/schemas.py 533 0 100% +-------------------------------------------------- +TOTAL 6615 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.md new file mode 100644 index 0000000..4c3682d --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.md @@ -0,0 +1,21 @@ +All gates green. Final report: + +**Implemented** +- `app/rag/verbatim.py` (new, inert — nothing imports it yet): `LOCATOR_LANG`, frozen `VerbatimBlock` / `SliceResult`, `canonical_locator` (tolerant `source/path` + ` `/`:`/`#`/`#L` + `12-40`/`12–40`/`L12-L40`/bare `12` → one canonical `source/path#start-end`, refuses no-source, empty, non-positive/reversed/non-numeric bounds, trailing junk, leading `bor`), `fences_in` (order-preserving, first-occurrence dedupe, bare `` ```bor `` not swallowed, unclosed fence yields nothing, body discarded), `slice_lines` (`read`/`grep`-identical 1-based semantics, clamping, `past_end` + true total), `cap_slice` (line-boundary cut + shared `TRUNCATION_MARKER`, mid-line exception documented, `cap<=0` raises), `document_by_identity` (bare first-slash `(source, path)` lookup, no agent import), `block_for` (refuses missing/image/past-end; canonical locator incl. cap-derived range), `resolve_answer_blocks` (kill switches first, fences-then-unlocated-shown order, fence wins dedupe, block-budget truncation). +- One-way import rule enforced: no `app.rag.agent` import (AST test + clean `grep -n import`). +- `tests/unit/test_verbatim_resolver.py`: 79 tests (grammar, fences, slicing, capping, identity, block, resolver fusion, every kill-switch combination, AST import rule), house style — detached `Document` rows + stand-in session like `tests/unit/test_agent.py`. + +**Verification** +- `uv run pytest tests/unit/test_verbatim_resolver.py -v` → 78→79 passed; `--cov=app.rag.verbatim` → **100%** +- `uv run pytest --cov=app --cov-report=term-missing` → **4353 passed**, TOTAL **99%** (>90%) +- `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors +- `python -c "…canonical_locator('homelab/a.md#L12-L40')"` → `homelab/a.md#12-40` ✓ + +**Docs**: no doc impact (task states nothing user-visible yet; the module is unwired — tasks 03/05 hook it in, phase's final pass re-checks README/AGENTS). + +**Notes/deviations** +- Mid-session the repo was replayed under this run (HEAD now `814a400` phase 181, task 01 complete, `app/services/answer_text.py` superseded): I implemented the current task file's `app/rag/verbatim.py` spec against the live tree; earlier stale-tree work was discarded and left untouched. +- `canonical_locator` refuses a range on a whitespace-bearing identity (documented grammar limit) and keeps one defensive non-numeric-bound guard (tested via monkeypatched grammar) so the parser stays total. +- No live-infrastructure actions taken. + +**Next pending task**: `.agents/phases/todo/182_verbatim_show_text/03_show_text_tool.md` diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.validate new file mode 100644 index 0000000..e26c41b --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__02_verbatim_resolver_module.a1.validate @@ -0,0 +1,141 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 13%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 23%] +........................................................................ [ 24%] +........................................................................ [ 26%] +........................................................................ [ 28%] +........................................................................ [ 29%] +........................................................................ [ 31%] +........................................................................ [ 33%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 38%] +........................................................................ [ 39%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 47%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 56%] +........................................................................ [ 57%] +........................................................................ [ 59%] +........................................................................ [ 61%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 71%] +........................................................................ [ 72%] +........................................................................ [ 74%] +........................................................................ [ 76%] +........................................................................ [ 77%] +........................................................................ [ 79%] +........................................................................ [ 81%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 86%] +........................................................................ [ 87%] +........................................................................ [ 89%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 94%] +........................................................................ [ 95%] +........................................................................ [ 97%] +........................................................................ [ 99%] +................................. [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 280 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 454 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 156 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 155 0 100% +app/schemas.py 533 0 100% +-------------------------------------------------- +TOTAL 6770 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.md new file mode 100644 index 0000000..593e656 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.md @@ -0,0 +1,9 @@ +**Task 03 complete — `show_text` agent tool.** + +- `app/rag/agent.py`: `SHOW_TEXT_TOOL` (exact task copy, after `SHOW_IMAGE_TOOL`), `agent_tools()` appends it when `answer_text` (offer order `ls, read, grep, show_image, show_text`; base three + pre-phase offers byte-identical), `AgentHolder.shown_texts`, and the `_execute_tool` branch in the exact 8-step order (path → flag-off `UNKNOWN_TOOL` → `_resolve_path` → A6 image refusal → reused `_read_range_args`/`BAD_RANGE_ARGS`/`OFFSET_PAST_END` → block budget before the work → `block_for` + canonical-locator dedupe → success result with the `read`/`show_image` header contract, `_origin_lines`, server-clamped `lines:` extent, `SHOWN_TEXT_TRUNCATION_NOTICE` on cap); module docstring extended with the A1–A3/A6 contract. +- `SHOW_TEXT_*` refusals: 4 constants, each used by exactly one branch (agent.py:2248/2265/2286/2310). +- Tests: +18 in `tests/unit/test_agent.py` (`-k show_text`: 18 passed) — offer matrix, tool-definition contract, refusal-copy pins, whole/ranged/capped shows, origin lines, 10 refusal cases with counting assertions, scripted-turn wiring (2nd line `Document …`, `lines: 3-5 of 5` matching the slice). +- Deliberate offer-array pin updates (each commented): `test_chat_gate.py`, `test_image_chips_and_answers.py`, `test_agent.py`, `test_chat_api.py`, `test_agent_tools.py`, `test_read_line_ranges_handbook.py`, e2e `test_answer_images.py`; leak-guard env pins added to `tests/conftest.py` + `tests/e2e/conftest.py` (`BOR_ANSWER_TEXT`/`_MAX_CHARS`/`_MAX_BLOCKS` code defaults). +- `README.md`: `show_text` row in the agent-tools table, new “Verbatim text display (phase 182)” section, cross-ref in the image table (settings rows already documented by task 01). No `chat_api.py`/`chat.js`/template touched. +- Gates: `uv run pytest` → **4371 passed**; coverage `app/` **99%** TOTAL (agent.py 99%, only pre-existing line 1312 missing; verbatim.py 100%); ruff + pyright clean; E2E in isolation: `test_answer_images.py` 5 passed, plus `agent_document_tools`/`harness_aligned_tools`/`tool_budget_telemetry`/`read_truncation_cap`/`search_tool_scope` all green. +- No git index/history mutations; phase stays in `todo/` (tasks 04–06 remain). diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.validate new file mode 100644 index 0000000..5e9119a --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__03_show_text_tool.a1.validate @@ -0,0 +1,141 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 13%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 23%] +........................................................................ [ 24%] +........................................................................ [ 26%] +........................................................................ [ 28%] +........................................................................ [ 29%] +........................................................................ [ 31%] +........................................................................ [ 32%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 41%] +........................................................................ [ 42%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 47%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 56%] +........................................................................ [ 57%] +........................................................................ [ 59%] +........................................................................ [ 60%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 65%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 74%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 79%] +........................................................................ [ 80%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 93%] +........................................................................ [ 95%] +........................................................................ [ 97%] +........................................................................ [ 98%] +................................................... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 280 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 156 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 155 0 100% +app/schemas.py 533 0 100% +-------------------------------------------------- +TOTAL 6810 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.md new file mode 100644 index 0000000..d8ca008 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.md @@ -0,0 +1,15 @@ +**Task 04 complete — `SHOW_TEXT_CLAUSE` taught, gated, byte-identical when off.** + +- `app/rag/prompts.py`: new `SHOW_TEXT_CLAUSE` (locked 7-part copy: display contract → SEE/COPY/RUN → do-NOT-retype → ` ```bor [range] ` with EMPTY body → server owns the numbers → refuse out loud → `show_image` pointer) + module-docstring paragraph. +- `build_high_prompt(show_text=…)`: clause rides INSIDE `` after `SHOW_IMAGE_CLAUSE` via one "section minus final `` + clauses + tag" mechanism; `TOOLS_SECTION` untouched; all 4 flag combos pinned. +- `app/api/chat.py`: grounded `TurnPlan` passes `show_text=settings.answer_text` beside `show_image`. +- Tests: +7 in `test_prompts.py` (locked sentence order, byte-identity when off, inside-`` placement, clause composition, deflect never carries `show_text`/`bor`), +2 sha/composition locks in `test_prompt_lock.py`, +1 grounded integration pin in `test_chat_api.py` (clause **and** tool offered together: 3 tools off / 4 on). +- Fixed pre-existing fallout of task 03 in prompt-reconstruction pins: `test_kb_overview_api.py` (×2), `test_image_chips_and_answers.py`. +- **Defect fixed (deviation, deliberate):** `tests/e2e/mock_llm.py`'s SHOW_IMAGE flow gated on the loose `"show_image" in system`, which the locked text clause now matches → phase-124 toggle-off E2E failed. Tightened to `_SHOW_IMAGE_CLAUSE_MARKER` (a sentence only the image clause carries); intent unchanged, ON app fires exactly as before. Mock triggers for phase 182 still deferred to task 08. +- Env note: a **stale `mock_llm` uvicorn from Oct 14 held port 8901** and served old mock code; killed it (test-double artifact, not live infra). + +Gates: `uv run pytest --cov=app --cov-report=term-missing` → **4381 passed**, `app/` **99 %** (`prompts.py` 100 %). `uv run ruff check .` → clean; `uv run pyright` → 0 errors. E2E in isolation `--no-cov`: `test_answer_images.py`, `test_harness_aligned_tools.py`, `test_agent_document_tools.py`, `test_markdown_tables.py` all green. Criterion one-liner: `show_text=True` → `True`, default → `False`. + +Docs: README "Verbatim text display (phase 182)" gained a *What the prompt teaches* bullet (copy-from-display rule + `bor` fence syntax + omit-the-range rule) and the off-state bullet now names the absent clause; SEE/COPY/RUN wording aligned. No AGENTS.md change (its rule-5 UI list lands with tasks 06/08). + +Next pending task: `.agents/phases/todo/182_verbatim_show_text/05_done_frame_and_persistence.md`. diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.validate new file mode 100644 index 0000000..f133ad6 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__04_prompt_teaching_clause.a1.validate @@ -0,0 +1,141 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 13%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 23%] +........................................................................ [ 24%] +........................................................................ [ 26%] +........................................................................ [ 27%] +........................................................................ [ 29%] +........................................................................ [ 31%] +........................................................................ [ 32%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 41%] +........................................................................ [ 42%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 47%] +........................................................................ [ 49%] +........................................................................ [ 50%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 59%] +........................................................................ [ 60%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 65%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 78%] +........................................................................ [ 80%] +........................................................................ [ 82%] +........................................................................ [ 83%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 93%] +........................................................................ [ 95%] +........................................................................ [ 96%] +........................................................................ [ 98%] +............................................................. [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 280 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 155 0 100% +app/schemas.py 533 0 100% +-------------------------------------------------- +TOTAL 6816 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.md new file mode 100644 index 0000000..a2e0ab8 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.md @@ -0,0 +1,20 @@ +**Task 05 complete — all gates green.** + +**Implemented** +- `app/schemas.py`: new `VerbatimBlockRef` (source/path/title/start_line/end_line/total_lines/text≤600 000/truncated/locator≤2100); `ChatDoneEvent.answer_text` + serializer POPs the key when `None`/empty (absent, never `null`/`[]`); `ChatMessage.answer_text` (cap 50) dropped by `_drop_image_when_absent`; docstrings in the `answer_image` style incl. the two deliberate differences (list + inline bytes, A4). +- `app/api/chat.py`: `visible_parts` accumulator beside `content_chars` (same post-filter pieces, never `thinking`); done-time `resolve_answer_blocks(...)` in a short-lived session, **skipped entirely on deflected turns** (D9), degrading to no-blocks + a named log line if the KB drops mid-answer; `answer_text=blocks or None`; per-turn line gains `verbatim_blocks=%d`; module docstring paragraph. +- Defect fixes in task 02's `app/rag/verbatim.py` (found by the new frame tests): `cap_slice` under-counted a slice ending on a blank line (`splitlines()`), so the caption lied by one line **and** the locator mismatched the same range resolved by `show_text`, making one block paint twice; dedupe now keys on the resolved locator as well as the written canonical; fence scan stops once `show_text_max_blocks` blocks are in (bounded lookups on the loop). +- `README.md`: `done.answer_text` wire contract + deflected/off semantics, payload-limit rows; `AGENTS.md` rule 10: `verbatim_blocks=N`. + +**Gates** +- `uv run pytest` → exit 0 (4398 collected); `uv run pytest --cov=app --cov-report=term-missing` → `app/schemas.py` 100 %, `app/rag/verbatim.py` 100 %, `app/api/chat.py` 99 % (only pre-existing miss: the SEC-14-04 concurrency 503 pre-check), TOTAL 99 %. +- `uv run ruff check .` clean; `uv run pyright` 0 errors. +- E2E in isolation (`--no-cov`, exit 0): `test_answer_images.py`, `test_harness_aligned_tools.py`+`test_agent_document_tools.py`+`test_markdown_tables.py`, `test_chat_persistence.py`/`test_share_chat.py`/`test_chat_rag.py`. +- New tests: 3 gate unit + field-order pin, 8 chat-API integration (tool block, fence-only, fence+tool dedupe, max_blocks=2 order, byte-identity, `answer_text=False`, deflected, resolution-failure degradation), 4 chats-API persistence, 6 schema, 2 resolver defect pins. +- Byte budget (phase-167 audit): observed `api method=POST path=/api/chat status=200 bytes=1272 enc=identity stream=1` on a `show_text` turn; worst-case frame (5 × 12 000-char blocks + long paths) ≈ 65 KB ≈ 25 % of the 256 KB budget — no concern. + +**Deviations to note** +1. `_require_within_total_budget` now also sums block bytes (task work-item 5 said existing validators don't change): `POST/PUT /api/chats` is anonymous (phase 55) and `answer_text[].text` carries the 600 000 cap, so without this the 8 000 000 SEC-05 invariant gains an unbounded second byte channel. Tightening only — no legitimate record (5 × 12 000 = 60 KB) is affected; pinned by `test_saved_chat_total_budget_counts_verbatim_block_text`. +2. The `verbatim.py` fixes above touch task 02's module (behaviour bug, not a spec change) — pinned in `tests/unit/test_verbatim_resolver.py`. + +**Next pending task:** `.agents/phases/todo/182_verbatim_show_text/06_markdown_locator_and_panel_css.md`. diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.validate new file mode 100644 index 0000000..32241a8 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__05_done_frame_and_persistence.a1.validate @@ -0,0 +1,142 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 13%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 17%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 26%] +........................................................................ [ 27%] +........................................................................ [ 29%] +........................................................................ [ 31%] +........................................................................ [ 32%] +........................................................................ [ 34%] +........................................................................ [ 35%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 44%] +........................................................................ [ 45%] +........................................................................ [ 47%] +........................................................................ [ 49%] +........................................................................ [ 50%] +........................................................................ [ 52%] +........................................................................ [ 53%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 62%] +........................................................................ [ 63%] +........................................................................ [ 65%] +........................................................................ [ 66%] +........................................................................ [ 68%] +........................................................................ [ 70%] +........................................................................ [ 71%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 76%] +........................................................................ [ 78%] +........................................................................ [ 80%] +........................................................................ [ 81%] +........................................................................ [ 83%] +........................................................................ [ 84%] +........................................................................ [ 86%] +........................................................................ [ 88%] +........................................................................ [ 89%] +........................................................................ [ 91%] +........................................................................ [ 93%] +........................................................................ [ 94%] +........................................................................ [ 96%] +........................................................................ [ 98%] +........................................................................ [ 99%] +............... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 292 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 549 0 100% +-------------------------------------------------- +TOTAL 6849 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.md new file mode 100644 index 0000000..d75bcf3 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.md @@ -0,0 +1,24 @@ +**Task 06 complete — all gates green.** + +**Implemented** +- `frontend/assets/markdown.js`: `renderMarkdown(md, opts)` (2nd optional arg, `opts && opts.verbatim === true` the only truthy path); new step-0 verbatim pass BEFORE the fence pass using the pinned regex; body/info line/closer dropped, `\u0000VERBATIMn\u0000` placeholder restored as `
` + `verbatim-caption` + `role="status"` “Retrieving the exact text…”, everything through `escapeHtml`; unparseable locator returned byte-for-byte to the fence pass; new local `borLocator()` (client mirror of `app.rag.verbatim.canonical_locator`); paragraph guard gained the placeholder clause (pre-phase guard text untouched); header comment rewritten. +- `frontend/assets/styles.css`: one labelled phase-182 region — `.verbatim`, sticky `.verbatim-head`, clipped `.verbatim-caption`, text `.verbatim-badge` (`--ok`, `text-transform: none`), `.verbatim-body` (`max-height: min(40rem,70vh)`, `overflow:auto`, `white-space: pre`, `tab-size: 2`, `overflow-wrap: normal`), `user-select: none` `.verbatim-lines` gutter, `.verbatim-pending`/`.verbatim-state`, `.verbatim-unresolved` (badge hidden), `.code-block` + `.code-block-copy`/`.verbatim-copy` (pill, 3px focus ring, ellipsis label, `.copied`); palette vars only, nothing animates; `.code-block-copy`/`.verbatim-copy` lifted to 44px in the ≤640 block. +- New tests: `tests/unit/test_frontend_verbatim_markdown.py` (22: source pins + node behavioral + JS↔Python parity table + 400-case deterministic fuzz), `tests/unit/test_frontend_verbatim_css.py` (20). + +**Gates** +- `uv run pytest` → **4449 passed**; `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99%** (`app/rag/verbatim.py` 100%, no new `app/` code); `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors. +- New files in isolation: `uv run pytest tests/unit/test_frontend_verbatim_markdown.py tests/unit/test_frontend_verbatim_css.py -v` green. +- E2E in isolation (`--no-cov`): `test_markdown_tables.py`, `test_markdown_blockquotes.py`, `test_markdown_inline_links_images.py`, `test_document_viewer.py`, `test_answer_images.py`, `test_thinking_display.py`, `test_background_no_motion.py` all green. +- Live browser check against the served app: `{verbatim:true}` → `data-bor-locator="homelab/a.md#12-40"`, no `GARBAGE` in the HTML and none in the painted DOM; sticky head, 70vh-capped scroll body, `user-select: none` gutter, badge `VERBATIM`, copy pill 32px desktop → 44px at 375px. + +**Docs**: README — new chat-section paragraph (opt-in pass + pass order) and a “The client never paints the model’s copy” bullet in §Verbatim text display; AGENTS.md rule 5 — the verbatim-panel contract (“verbatim-and-badged OR plainly the model’s”). + +**Decisions / deviations** +1. Criterion #2’s “OFF returns the ordinary `
`”: a ` ```bor  ` info string has *never* matched the fence rule (`/```(\w*)\n/`), so OFF is escaped prose — pinned byte-identical to pre-phase; a bare ` ```bor ` fence still yields `
`. Widening the fence rule was rejected (it would change every existing call site, violating the byte-identity mandate).
+2. Implemented the pinned regex verbatim: `(?![\s\S])` covers a fence open exactly at end-of-input (info line typed, body not yet streamed); a half-typed *body* renders as ordinary text until its closer arrives — same as every incomplete fence today. Documented in header + code comment.
+3. Added the `VERBATIM`-placeholder clause to the paragraph guard so the restored `
` isn’t wrapped in `

`; the pre-phase guard string is untouched (phase-180 pin stays green). +4. Went beyond the task’s testing note by pinning locator parity in a unit test (table + deterministic fuzz) — parity is hydration-critical and checkable without a browser. +5. Dropped `scrollbar-color` from `.verbatim-body`: `test_prose_word_wrap.py` pins scrollbar theming as modal-only (phase 116). +6. Fixed a stale pin in `tests/unit/test_document_viewer.py` (`function renderMarkdown(md)` → `function renderMarkdown(md`), broken by the new signature. + +**Next pending task**: `182_verbatim_show_text/07_hydration_and_copy_buttons.md` (opts the three answer renderers in, adds `verbatim.js` hydration + Copy buttons). diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.validate new file mode 100644 index 0000000..2254383 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__06_markdown_locator_and_panel_css.a1.validate @@ -0,0 +1,142 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 8%] +........................................................................ [ 9%] +........................................................................ [ 11%] +........................................................................ [ 12%] +........................................................................ [ 14%] +........................................................................ [ 16%] +........................................................................ [ 17%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 29%] +........................................................................ [ 30%] +........................................................................ [ 32%] +........................................................................ [ 33%] +........................................................................ [ 35%] +........................................................................ [ 37%] +........................................................................ [ 38%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 50%] +........................................................................ [ 51%] +........................................................................ [ 53%] +........................................................................ [ 55%] +........................................................................ [ 56%] +........................................................................ [ 58%] +........................................................................ [ 59%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 71%] +........................................................................ [ 72%] +........................................................................ [ 74%] +........................................................................ [ 76%] +........................................................................ [ 77%] +........................................................................ [ 79%] +........................................................................ [ 80%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 89%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 93%] +........................................................................ [ 95%] +........................................................................ [ 97%] +........................................................................ [ 98%] +......................................................... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 292 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 204 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 55 0 100% +app/config.py 304 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 111 0 100% +app/core/theming.py 40 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 141 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 855 4 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 252 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 549 0 100% +-------------------------------------------------- +TOTAL 6849 17 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.md new file mode 100644 index 0000000..3d0be18 --- /dev/null +++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.md @@ -0,0 +1,25 @@ +All gates are green. Final state of the work: + +## What landed (task 07 — hydration, panels, Copy buttons) + +**New client — `frontend/assets/verbatim.js`** (531 lines, classic script, globals like `markdown.js`) +- `buildVerbatimPanel(block, opts)` → sticky `.verbatim-head` (`.verbatim-caption` `source/path · lines 12–40 of 210` / `… · all 210 lines`, `.verbatim-badge` `VERBATIM`, `.verbatim-open`, `.verbatim-copy` `Copy N lines from `), `.verbatim-body` = `ol.verbatim-lines` gutter + `pre.verbatim-text` (`pre.textContent = block.text`), `.verbatim-more` on a capped block; root `role="group"` + `aria-label` + `data-bor-locator` = the **server's** locator. +- `hydrateVerbatim` (exact canonical-locator `===`, else exactly one block on the same `source/path`, else the pinned unresolved sentence — never throws, idempotent because only `.verbatim-pending` is touched), `appendUnlocatedVerbatim` (the `answer_image` band), `settleVerbatimPlaceholders`, `enhanceAnswerCodeBlocks` (`.code-block` + Copy, **no badge**, idempotent), `copyTextWithFallback`. +- **No second locator grammar** (no `borLocator`, no range regex, no `parseInt`) — pinned as the phase's drift guard. All `createElement`/`textContent`, all `addEventListener`, zero `innerHTML`. + +**Wiring** — `index.html` + `shared.html` load it after `markdown.js`; `Containerfile` minifies it without `--bundle`. `app.js`: both live answer renderers opt in, the `done` handler runs image → hydrate → unlocated → Copy-settle → sources, `answer_text: ev.answer_text || undefined` joins the save point, the restore path re-renders + hydrates from `m.answer_text`, five terminal settle sites (`error` frame, 300 s guard, its abort surface, Stop, the failed-turn funnel), `VERBATIM_LINK_OPTS` (`documentUrl(…, "/")` + `openDocumentModal`), and the share copy now **delegates** to the one clipboard helper. `shared.js`: same three globals + a plain `/document.html` href, no modal. `styles.css`: extended only inside the labelled phase-182 region (`.verbatim-body` flex row, `.verbatim-text`, `.verbatim-open`, `.verbatim-more`, 44 px mobile link) — palette variables only. + +## Verification +- `uv run pytest tests/unit tests/integration` → **4483 passed**; `--cov=app` → **TOTAL 99 %** (>90 %). +- `ruff check .` → all checks passed; `pyright` → **0 errors**. +- New `tests/unit/test_frontend_verbatim_blocks.py`: **34 tests** (source pins + a node half that runs caption/gutter/match/block-guard logic against the real file). +- Stale pins reconciled (byte-pin `PINNED_RUN_TURN` regenerated, 3 brain-restore shapes, the task-06 call-site test rewritten as *only the answer renderers opted in*, the share-copy internals re-pinned at their new home, `shared.html` script order, `renderMarkdown(finalText, { verbatim: true })`). +- Playwright regression pass: smoke, share_chat, chat_answer_clusters, chat_persistence, prose_word_wrap, no_empty_box, save_share_ux, failed_turn_retry, answer_images, long_answers, reasoning_bubble, edit_and_resend, chat_error_honesty — all green. +- Real-browser sanity check (throwaway script, not committed): caption/badge/gutter/Copy at 1280 px and 375 px, gutter stays put while the body scrolls sideways, **clipboard equals the server string exactly**, `Copy`→`Copied`, plain code block copies with no badge, unresolved shows the sentence with no badge/body/`

`, no page overflow at 375 px, 44 px tap targets, 3 px `:focus-visible` ring.
+
+**Docs**: README (panel anatomy, the hydration rule, unresolved/settle behaviour, Copy-on-every-settled-block, parity, the shared-page exception, renderer opt-in count) and AGENTS rule 5's UI contract line.
+
+## Notes
+- Nothing committed and nothing staged — child passes never touch the index/history; the harness makes the one atomic phase commit.
+- Environment gotcha worth knowing: a stray `python -m http.server` on port 8123 makes every E2E suite fail with `404`/`Sign-in failed (HTTP 501)`; I killed the one my own throwaway check left behind.
+- For task 08's E2E, the behaviours already pinned at source level that want browser assertions: exactly one `.verbatim` per locator after a reload, clipboard equality, the unresolved copy, nothing at *Retrieving the exact text…* after `slow_llm`/always-fail, the appended unlocated block above the source clusters, and shared-page parity with no other controls.
diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.md.status
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.md.status
@@ -0,0 +1 @@
+ok
diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.validate
new file mode 100644
index 0000000..04830a0
--- /dev/null
+++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__07_hydration_and_copy_buttons.a1.validate
@@ -0,0 +1,143 @@
+........................................................................ [  1%]
+........................................................................ [  3%]
+........................................................................ [  4%]
+........................................................................ [  6%]
+........................................................................ [  8%]
+........................................................................ [  9%]
+........................................................................ [ 11%]
+........................................................................ [ 12%]
+........................................................................ [ 14%]
+........................................................................ [ 16%]
+........................................................................ [ 17%]
+........................................................................ [ 19%]
+........................................................................ [ 20%]
+........................................................................ [ 22%]
+........................................................................ [ 24%]
+........................................................................ [ 25%]
+........................................................................ [ 27%]
+........................................................................ [ 28%]
+........................................................................ [ 30%]
+........................................................................ [ 32%]
+........................................................................ [ 33%]
+........................................................................ [ 35%]
+........................................................................ [ 36%]
+........................................................................ [ 38%]
+........................................................................ [ 40%]
+........................................................................ [ 41%]
+........................................................................ [ 43%]
+........................................................................ [ 44%]
+........................................................................ [ 46%]
+........................................................................ [ 48%]
+........................................................................ [ 49%]
+........................................................................ [ 51%]
+........................................................................ [ 53%]
+........................................................................ [ 54%]
+........................................................................ [ 56%]
+........................................................................ [ 57%]
+........................................................................ [ 59%]
+........................................................................ [ 61%]
+........................................................................ [ 62%]
+........................................................................ [ 64%]
+........................................................................ [ 65%]
+........................................................................ [ 67%]
+........................................................................ [ 69%]
+........................................................................ [ 70%]
+........................................................................ [ 72%]
+........................................................................ [ 73%]
+........................................................................ [ 75%]
+........................................................................ [ 77%]
+........................................................................ [ 78%]
+........................................................................ [ 80%]
+........................................................................ [ 81%]
+........................................................................ [ 83%]
+........................................................................ [ 85%]
+........................................................................ [ 86%]
+........................................................................ [ 88%]
+........................................................................ [ 89%]
+........................................................................ [ 91%]
+........................................................................ [ 93%]
+........................................................................ [ 94%]
+........................................................................ [ 96%]
+........................................................................ [ 97%]
+........................................................................ [ 99%]
+...................                                                      [100%]
+=============================== warnings summary ===============================
+.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
+  /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
+    from starlette.testclient import TestClient as TestClient  # noqa
+
+-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
+================================ tests coverage ================================
+_______________ coverage: platform linux, python 3.13.13-final-0 _______________
+
+Name                           Stmts   Miss  Cover
+--------------------------------------------------
+app/__init__.py                    1      0   100%
+app/api/__init__.py                0      0   100%
+app/api/admin_settings.py        114      0   100%
+app/api/auth.py                   52      0   100%
+app/api/chat.py                  292      1    99%
+app/api/chat_images.py            52      0   100%
+app/api/chats.py                 111      0   100%
+app/api/config.py                 13      0   100%
+app/api/doc_drafts.py             99      0   100%
+app/api/docs.py                  239      1    99%
+app/api/git_sources.py           259      0   100%
+app/api/health.py                 10      0   100%
+app/api/steering.py               42      0   100%
+app/api/suggestions.py            33      0   100%
+app/api/sync.py                  204      0   100%
+app/api/tokens.py                 40      0   100%
+app/api/ui_settings.py            55      0   100%
+app/config.py                    304      0   100%
+app/core/__init__.py               0      0   100%
+app/core/auth.py                  45      0   100%
+app/core/caching.py              124      0   100%
+app/core/compression.py           59      0   100%
+app/core/debugging.py             29      2    93%
+app/core/docs_push.py             43      0   100%
+app/core/errors.py                 5      0   100%
+app/core/http_cache.py            22      0   100%
+app/core/logging.py               13      0   100%
+app/core/rate_limit.py            44      0   100%
+app/core/response_budget.py       63      0   100%
+app/core/security_headers.py      20      0   100%
+app/core/settings_catalog.py      18      0   100%
+app/core/settings_migrate.py      32      0   100%
+app/core/settings_overlay.py     111      0   100%
+app/core/theming.py               40      0   100%
+app/core/tokens.py                44      0   100%
+app/db.py                         22      0   100%
+app/main.py                      105      0   100%
+app/models.py                    141      0   100%
+app/rag/__init__.py                0      0   100%
+app/rag/agent.py                 494      1    99%
+app/rag/archive_upload.py        134      0   100%
+app/rag/chunker.py               220      4    98%
+app/rag/doc_dates.py              18      0   100%
+app/rag/folder_summaries.py      134      0   100%
+app/rag/git_sources.py            77      0   100%
+app/rag/importer.py              855      4    99%
+app/rag/llm.py                   253      1    99%
+app/rag/md_images.py              63      0   100%
+app/rag/overview.py               78      0   100%
+app/rag/pdf.py                   192      0   100%
+app/rag/prompts.py               162      0   100%
+app/rag/retriever.py             252      3    99%
+app/rag/scaffolding.py            55      0   100%
+app/rag/source_removal.py         41      0   100%
+app/rag/sources_meta.py           16      0   100%
+app/rag/suggestions.py            27      0   100%
+app/rag/summarizer.py             58      0   100%
+app/rag/svg_text.py              111      0   100%
+app/rag/verbatim.py              160      0   100%
+app/schemas.py                   549      0   100%
+--------------------------------------------------
+TOTAL                           6849     17    99%
+coverage gate: app/ 99% (>90%) OK
+All checks passed!
+0 errors, 0 warnings, 0 informations
+WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414).
+Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
+
+validation OK
diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.err b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.err
new file mode 100644
index 0000000..e69de29
diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.md b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.md
new file mode 100644
index 0000000..441b0c3
--- /dev/null
+++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.md
@@ -0,0 +1,32 @@
+**Task 08 complete.** Everything is verified green; nothing staged or committed (the pipeline owns the commit and the task-file move).
+
+## Delivered
+
+| File | Change |
+|---|---|
+| `tests/e2e/test_verbatim_show_text.py` | **new**, 1 428 lines — the phase's dedicated Playwright suite (13 specs) |
+| `tests/e2e/mock_llm.py` | +402 lines — the three scripted `show_text` branches, the corrupted-fence-body generator, the fixture doc-picker, module docstring |
+| `.agents/PLAN.md` | §4 fifth tool + additive `done.answer_text`, §9 `verbatim_blocks=N`, revisions paragraph incl. the explicit **A1–A6 / A15 otherwise UNCHANGED** statement |
+| `README.md` | two precision fixes to the `BOR_ANSWER_TEXT=0` wording (server surface is pre-phase; the client's never-paint-the-model's-copy rule is flag-independent) |
+
+Suite coverage: tool flow with a deliberately corrupted model fence, server-bytes/caption/gutter/badge/viewer link, five-tool offer + one executed call, in-page SSE tap (`≤7` event types, `answer_text` inside `done`), append path above the source clusters, clipboard byte-equality for `.verbatim-copy` and `.code-block-copy`, standalone fence with zero tool calls, honest state for a hallucinated locator, wrong range corrected to the server's extent, `OFFSET_PAST_END` refusal, reload + **`/history` → `/?chat=` (local storage cleared, so the pass cannot be vacuous)** + anonymous shared page, image regression + `show_text`-on-image refusal naming `show_image`, 390 px scroll/44 px controls, and App B (`BOR_ANSWER_TEXT=false`).
+
+## Gates
+
+| Gate | Result |
+|---|---|
+| `pytest tests/e2e/test_verbatim_show_text.py --no-cov` (isolated) | **13 passed** in 28 s |
+| Regression sweep (all 14 named suites + phase 180's, isolated) | **14/14 rc=0**, no edits to existing specs |
+| `pytest --cov=app` (unit + integration) | all pass, `app/` coverage **99%** (17 missed / 6 849) |
+| `ruff check .` | All checks passed |
+| `pyright` | 0 errors |
+| Phase-116 trigger discipline | 41 triggers: no containment involving a new phrase; no other suite contains one |
+| **Mutation check (suite has teeth)** | 5/5 caught: drop the live `{verbatim:true}` opt-in · Copy writes wrong string · honest sentence muted · append path no-op'd · panel body swapped for the title |
+
+## Flagged (per operating rule 3 — not silently deviated)
+
+1. **App B fence rendering.** Task 08's bullet expects a ` ```bor ` fence with the flag off to render as an ordinary `
` block. That contradicts the contract locked by task 07 and recorded in `AGENTS.md` rule 5 ("an unresolvable locator painting the pinned sentence… with no badge, no body and **none of the model's bytes**"). I asserted the **locked** behavior (honest sentence + Copy on the ordinary block) and corrected the README wording; pre-phase `
` for a `bor` body would re-open the drift incident.
+2. **One existing mock branch was NOT byte-identical.** Phase 182's `SHOW_TEXT_CLAUSE` ends "For an image use `show_image` instead.", so phase 124's gate `if "show_image" not in system` now also matches a text-clause-only prompt and the image flow fired on `BOR_ANSWER_IMAGES=0` apps. Tightened to `_SHOW_IMAGE_CLAUSE_MARKER = "displays a standalone image document"` (a sentence only the image clause carries, `prompts.py:394`); `test_answer_images.py` green.
+3. **Trigger constant names** are public (`SHOW_TEXT_TRIGGER`, `SHOW_TEXT_INLINE_TRIGGER`, `SHOW_TEXT_MISSING_TRIGGER`) rather than the task's `_FENCE_ONLY_TRIGGER`/`_BAD_LOCATOR_TRIGGER`, matching the mock's convention for constants suites import; semantics, phrases and flow order are exactly as specified. `_SHOW_TEXT_CONFIRM_MARKER` keeps its task name.
+
+Incident note for transparency: an earlier shell-quoting mistake of mine silently stripped `{ verbatim: true }` from `app.js:4363`; it was restored and the file is byte-verified (md5 `33a584f3…`), with the full suite, the E2E suite and the mutation harness all re-run against the restored tree.
diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.md.status b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.md.status
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.md.status
@@ -0,0 +1 @@
+ok
diff --git a/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.validate b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.validate
new file mode 100644
index 0000000..04830a0
--- /dev/null
+++ b/.agents/reports/182_verbatim_show_text/182_verbatim_show_text__08_e2e_and_docs_pass.a1.validate
@@ -0,0 +1,143 @@
+........................................................................ [  1%]
+........................................................................ [  3%]
+........................................................................ [  4%]
+........................................................................ [  6%]
+........................................................................ [  8%]
+........................................................................ [  9%]
+........................................................................ [ 11%]
+........................................................................ [ 12%]
+........................................................................ [ 14%]
+........................................................................ [ 16%]
+........................................................................ [ 17%]
+........................................................................ [ 19%]
+........................................................................ [ 20%]
+........................................................................ [ 22%]
+........................................................................ [ 24%]
+........................................................................ [ 25%]
+........................................................................ [ 27%]
+........................................................................ [ 28%]
+........................................................................ [ 30%]
+........................................................................ [ 32%]
+........................................................................ [ 33%]
+........................................................................ [ 35%]
+........................................................................ [ 36%]
+........................................................................ [ 38%]
+........................................................................ [ 40%]
+........................................................................ [ 41%]
+........................................................................ [ 43%]
+........................................................................ [ 44%]
+........................................................................ [ 46%]
+........................................................................ [ 48%]
+........................................................................ [ 49%]
+........................................................................ [ 51%]
+........................................................................ [ 53%]
+........................................................................ [ 54%]
+........................................................................ [ 56%]
+........................................................................ [ 57%]
+........................................................................ [ 59%]
+........................................................................ [ 61%]
+........................................................................ [ 62%]
+........................................................................ [ 64%]
+........................................................................ [ 65%]
+........................................................................ [ 67%]
+........................................................................ [ 69%]
+........................................................................ [ 70%]
+........................................................................ [ 72%]
+........................................................................ [ 73%]
+........................................................................ [ 75%]
+........................................................................ [ 77%]
+........................................................................ [ 78%]
+........................................................................ [ 80%]
+........................................................................ [ 81%]
+........................................................................ [ 83%]
+........................................................................ [ 85%]
+........................................................................ [ 86%]
+........................................................................ [ 88%]
+........................................................................ [ 89%]
+........................................................................ [ 91%]
+........................................................................ [ 93%]
+........................................................................ [ 94%]
+........................................................................ [ 96%]
+........................................................................ [ 97%]
+........................................................................ [ 99%]
+...................                                                      [100%]
+=============================== warnings summary ===============================
+.venv/lib/python3.13/site-packages/fastapi/testclient.py:1
+  /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
+    from starlette.testclient import TestClient as TestClient  # noqa
+
+-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
+================================ tests coverage ================================
+_______________ coverage: platform linux, python 3.13.13-final-0 _______________
+
+Name                           Stmts   Miss  Cover
+--------------------------------------------------
+app/__init__.py                    1      0   100%
+app/api/__init__.py                0      0   100%
+app/api/admin_settings.py        114      0   100%
+app/api/auth.py                   52      0   100%
+app/api/chat.py                  292      1    99%
+app/api/chat_images.py            52      0   100%
+app/api/chats.py                 111      0   100%
+app/api/config.py                 13      0   100%
+app/api/doc_drafts.py             99      0   100%
+app/api/docs.py                  239      1    99%
+app/api/git_sources.py           259      0   100%
+app/api/health.py                 10      0   100%
+app/api/steering.py               42      0   100%
+app/api/suggestions.py            33      0   100%
+app/api/sync.py                  204      0   100%
+app/api/tokens.py                 40      0   100%
+app/api/ui_settings.py            55      0   100%
+app/config.py                    304      0   100%
+app/core/__init__.py               0      0   100%
+app/core/auth.py                  45      0   100%
+app/core/caching.py              124      0   100%
+app/core/compression.py           59      0   100%
+app/core/debugging.py             29      2    93%
+app/core/docs_push.py             43      0   100%
+app/core/errors.py                 5      0   100%
+app/core/http_cache.py            22      0   100%
+app/core/logging.py               13      0   100%
+app/core/rate_limit.py            44      0   100%
+app/core/response_budget.py       63      0   100%
+app/core/security_headers.py      20      0   100%
+app/core/settings_catalog.py      18      0   100%
+app/core/settings_migrate.py      32      0   100%
+app/core/settings_overlay.py     111      0   100%
+app/core/theming.py               40      0   100%
+app/core/tokens.py                44      0   100%
+app/db.py                         22      0   100%
+app/main.py                      105      0   100%
+app/models.py                    141      0   100%
+app/rag/__init__.py                0      0   100%
+app/rag/agent.py                 494      1    99%
+app/rag/archive_upload.py        134      0   100%
+app/rag/chunker.py               220      4    98%
+app/rag/doc_dates.py              18      0   100%
+app/rag/folder_summaries.py      134      0   100%
+app/rag/git_sources.py            77      0   100%
+app/rag/importer.py              855      4    99%
+app/rag/llm.py                   253      1    99%
+app/rag/md_images.py              63      0   100%
+app/rag/overview.py               78      0   100%
+app/rag/pdf.py                   192      0   100%
+app/rag/prompts.py               162      0   100%
+app/rag/retriever.py             252      3    99%
+app/rag/scaffolding.py            55      0   100%
+app/rag/source_removal.py         41      0   100%
+app/rag/sources_meta.py           16      0   100%
+app/rag/suggestions.py            27      0   100%
+app/rag/summarizer.py             58      0   100%
+app/rag/svg_text.py              111      0   100%
+app/rag/verbatim.py              160      0   100%
+app/schemas.py                   549      0   100%
+--------------------------------------------------
+TOTAL                           6849     17    99%
+coverage gate: app/ 99% (>90%) OK
+All checks passed!
+0 errors, 0 warnings, 0 informations
+WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414).
+Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest`
+
+validation OK
diff --git a/.agents/screenshots/166_pre_answer_window_1280.png b/.agents/screenshots/166_pre_answer_window_1280.png
index f12f6fb..350bd53 100644
Binary files a/.agents/screenshots/166_pre_answer_window_1280.png and b/.agents/screenshots/166_pre_answer_window_1280.png differ
diff --git a/.agents/screenshots/doc_modal_scrollbar_1280.png b/.agents/screenshots/doc_modal_scrollbar_1280.png
index 3792c88..88bff57 100644
Binary files a/.agents/screenshots/doc_modal_scrollbar_1280.png and b/.agents/screenshots/doc_modal_scrollbar_1280.png differ
diff --git a/.env.example b/.env.example
index 09bfa99..ab8186f 100644
--- a/.env.example
+++ b/.env.example
@@ -104,6 +104,9 @@ BOR_NAME_HIT_BONUS=0.005          # selection-time bonus a name-hit doc's best f
 # --- Agent document tools (grounded turns may extend context: ls / read / grep) ---
 # BOR_AGENT_MAX_ROUNDS=10   # hard cap on agent tool rounds per turn (0 = no tools); every tool result carries the model's remaining count (phase 160)
 # BOR_READ_MAX_CHARS=128000      # cap on a `read` result (chars); over-cap reads truncate + a notice that teaches the grep -> read(offset, limit) workflow (phase 95, rewritten phase 131)
+BOR_ANSWER_TEXT=true              # verbatim file display (phase 182): the master switch, ON by default (an answer's code block must never silently differ from the file). false = the escape hatch — the `show_text` tool is not offered, its  teaching clause is absent, ```bor locator fences are not resolved, and the done frame carries no `answer_text` key (every byte-identity contract is exactly pre-phase)
+BOR_SHOW_TEXT_MAX_CHARS=12000     # per-block char budget for ONE displayed verbatim slice (phase 182); the slice is cut at a LINE BOUNDARY + the shared […truncated…] marker and the caption's line range shrinks to what is actually shown; 0 = inert (no block displays), negative fails startup naming the field
+BOR_SHOW_TEXT_MAX_BLOCKS=5        # per-answer cap on displayed verbatim blocks (phase 182), counted in answer order; 0 = inert (no block displays), negative fails startup naming the field
 
 # --- Import scope (A9 default; ANY well-formed extension is allowed) ---
 # Comma-separated file extensions (lowercase, no dot) the importer reads.
diff --git a/AGENTS.md b/AGENTS.md
index 1340e38..0ffeb2f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -47,7 +47,30 @@
    in-flight row (`role="status"`) / alert + Retry row
    (`role="alert"`, a real `