phase: 182_verbatim_show_text
Build and Push Containers / build-and-push-app (push) Successful in 1m46s
Build and Push Containers / build-and-push-db (push) Successful in 12s

**Phase 182 — final verification pass (all 8 tasks already complete; this was verification + docs + one defect fix).**

- Verified: `app/rag/verbatim.py` (locator grammar, `splitlines()` slice, line-boundary cap, `resolve_answer_blocks`), `SHOW_TEXT_TOOL` + `shown_texts`, `SHOW_TEXT_CLAUSE`, `done.answer_text` (9 fields, key dropped when empty) + `ChatMessageRecord.answer_text` (≤50, 600 000-char cap counted in the 8 M budget), `verbatim.js` + 4 `{verbatim:true}` renderers, `Containerfile` minify step, `.env.example` 3 vars.
- `uv run python -c "…answer_text, show_text_max_chars, show_text_max_blocks"` → `True 12000 5`; each negative refuses startup naming its field; `0` accepted as inert ✅
- `bash .agents/validate.sh` → **validation OK**: 4320 unit+integration tests green, `TOTAL 6849 17 → 99%` (gate app/ >90% OK), `ruff check .` "All checks passed!", `pyright` 0 errors (re-run after my edits, 08:28).
- E2E, each in isolation `--no-cov`: `test_verbatim_show_text.py` 13 passed (panel bytes == `documents.content`, server caption, clipboard == server string, `/document.html?source=…&path=…`, honest unresolved state, reload+share, `show_image` regression, flag-off app) ✅; green: `test_answer_images` `test_harness_aligned_tools` `test_agent_document_tools` `test_markdown_tables` `test_markdown_inline_links_images` `test_svg_document_preview` `test_smoke` `test_document_viewer` `test_markdown_blockquotes` `test_chat_persistence` `test_thinking_timeline` `test_chat_rag` `test_settings_mobile_value_width`.
- **Defect found & fixed (pre-existing, not phase 182):** `tests/e2e/test_admin_settings_panel.py::test_admin_sees_groups_and_source_badges` failed — its whole-page `assert "reese" not in page.content()` tripped on the shell's onboarding chips, which follow the newest saved chats in the one shared E2E DB (a leftover `reeselink.json` question from a tool suite). Scoped the strict sweep to `.settings-shell` and kept a whole-page `reese:reese` credential needle → 12 passed with the leftovers still present.
- Docs: README fixed 2 inconsistencies — Quick Start omitted the **required** `BOR_ADMIN_PASSWORD`/`BOR_SESSION_SECRET` (the app fail-loud refuses boot) and the broken anchor `#chat--` → `#chat-`; full re-read of README (1816 lines) + AGENTS confirmed the phase-182 feature/settings/log/UI-contract text matches the code, and every `.env.example` var + every `Settings` field is documented.
- Notable: kept `resolve_answer_blocks` synchronous on the SSE terminal path (bounded indexed SELECTs, matching the existing `query_log` precedent and the phase's documented fence-lookup bound); no live-infra changes made.
- Next pending phase: none — `todo/` holds only 182 (its 8 task files are in `complete/`; the harness commits + moves `00_phase.md`).
This commit is contained in:
2026-10-15 08:33:12 -04:00
parent 814a400e6d
commit b34b8ca672
104 changed files with 10852 additions and 203 deletions
+30 -9
View File
@@ -139,21 +139,31 @@ def test_shared_html_identical_header_guest_safe() -> None:
def test_shared_html_scripts_and_no_controls() -> None:
"""Script load order (the house pattern): brand.js classic FIRST,
the classic markdown renderer second, the shared.js module last —
ALL with ABSOLUTE /assets/ paths: the page is served from the
the classic markdown renderer second, the classic verbatim panel client
third (phase 182 task 07 — it must be a global BEFORE the module, and
AFTER markdown.js whose placeholders it hydrates), the shared.js module
last — ALL with ABSOLUTE /assets/ paths: the page is served from the
NESTED /shared/<token> route, where a relative "assets/…" ref
would resolve to /shared/assets/… and 404. NO direct header.js
<script> tag (single-evaluation design — shared.js imports it
relatively). Zero controls (owner-locked): no document-modal, no
composer, no Send/Save/Share/New chat buttons, no form element,
and the ONLY <button>s on the page are the shared bar's own (the
hamburger + the two sign-out copies)."""
and the ONLY <button>s the page itself ships are the shared bar's own
(the hamburger + the two sign-out copies). Phase 182's narrow exception
(the panel's Copy button + its plain viewer link) is injected by the
SHARED verbatim.js client, not by this markup, and is pinned in
tests/unit/test_frontend_verbatim_blocks.py."""
html = _html()
srcs = re.findall(r'<script[^>]*src="([^"]+)"', html)
assert srcs == ["/assets/brand.js", "/assets/markdown.js", "/assets/shared.js"], (
f"shared.html must load brand.js + markdown.js (classic, absolute "
f"/assets/ paths — the nested route breaks relative refs) and the "
f"shared.js module, in that order, got {srcs}"
assert srcs == [
"/assets/brand.js",
"/assets/markdown.js",
"/assets/verbatim.js",
"/assets/shared.js",
], (
f"shared.html must load brand.js + markdown.js + verbatim.js (classic, "
f"absolute /assets/ paths — the nested route breaks relative refs) and "
f"the shared.js module, in that order, got {srcs}"
)
# The stylesheet too (a relative href would break the same way).
assert '<link rel="stylesheet" href="/assets/styles.css">' in html
@@ -289,7 +299,18 @@ def test_render_shared_message_record_shape() -> None:
js = _js()
body = _fn(js, "renderSharedMessage")
assert 'addSharedMessage("user", renderMarkdown(m.text))' in body
assert 'addSharedMessage("brain", renderMarkdown(m.text))' in body
# Phase 182 (task 07): the brain renderer opts INTO the verbatim pass
# (the chat page's restore does the same — parity), and hydrates the
# placeholders + appends the unlocated blocks from the record's
# `answer_text` before the source chips. The user renderer stays
# one-argument.
assert 'addSharedMessage("brain", renderMarkdown(m.text, { verbatim: true }))' in body
assert "hydrateVerbatim(" in body, "the shared page hydrates (parity)"
assert "appendUnlocatedVerbatim(" in body
assert "enhanceAnswerCodeBlocks(wrap)" in body
assert body.index("addAnswerImage(") < body.index("hydrateVerbatim(") < body.index(
"addSources(wrap, m.sources)"
), "the panel band matches the chat page: image, panels, then the chips"
assert "renderMarkdown" in body, "the escape-first global renderer"
assert "function renderMarkdown" not in js, (
"shared.js must NOT define its own renderer — markdown.js is the one copy"