phase: 182_verbatim_show_text
**Phase 182 — final verification pass (all 8 tasks already complete; this was verification + docs + one defect fix).**
- Verified: `app/rag/verbatim.py` (locator grammar, `splitlines()` slice, line-boundary cap, `resolve_answer_blocks`), `SHOW_TEXT_TOOL` + `shown_texts`, `SHOW_TEXT_CLAUSE`, `done.answer_text` (9 fields, key dropped when empty) + `ChatMessageRecord.answer_text` (≤50, 600 000-char cap counted in the 8 M budget), `verbatim.js` + 4 `{verbatim:true}` renderers, `Containerfile` minify step, `.env.example` 3 vars.
- `uv run python -c "…answer_text, show_text_max_chars, show_text_max_blocks"` → `True 12000 5`; each negative refuses startup naming its field; `0` accepted as inert ✅
- `bash .agents/validate.sh` → **validation OK**: 4320 unit+integration tests green, `TOTAL 6849 17 → 99%` (gate app/ >90% OK), `ruff check .` "All checks passed!", `pyright` 0 errors (re-run after my edits, 08:28).
- E2E, each in isolation `--no-cov`: `test_verbatim_show_text.py` 13 passed (panel bytes == `documents.content`, server caption, clipboard == server string, `/document.html?source=…&path=…`, honest unresolved state, reload+share, `show_image` regression, flag-off app) ✅; green: `test_answer_images` `test_harness_aligned_tools` `test_agent_document_tools` `test_markdown_tables` `test_markdown_inline_links_images` `test_svg_document_preview` `test_smoke` `test_document_viewer` `test_markdown_blockquotes` `test_chat_persistence` `test_thinking_timeline` `test_chat_rag` `test_settings_mobile_value_width`.
- **Defect found & fixed (pre-existing, not phase 182):** `tests/e2e/test_admin_settings_panel.py::test_admin_sees_groups_and_source_badges` failed — its whole-page `assert "reese" not in page.content()` tripped on the shell's onboarding chips, which follow the newest saved chats in the one shared E2E DB (a leftover `reeselink.json` question from a tool suite). Scoped the strict sweep to `.settings-shell` and kept a whole-page `reese:reese` credential needle → 12 passed with the leftovers still present.
- Docs: README fixed 2 inconsistencies — Quick Start omitted the **required** `BOR_ADMIN_PASSWORD`/`BOR_SESSION_SECRET` (the app fail-loud refuses boot) and the broken anchor `#chat--` → `#chat-`; full re-read of README (1816 lines) + AGENTS confirmed the phase-182 feature/settings/log/UI-contract text matches the code, and every `.env.example` var + every `Settings` field is documented.
- Notable: kept `resolve_answer_blocks` synchronous on the SSE terminal path (bounded indexed SELECTs, matching the existing `query_log` precedent and the phase's documented fence-lookup bound); no live-infra changes made.
- Next pending phase: none — `todo/` holds only 182 (its 8 task files are in `complete/`; the harness commits + moves `00_phase.md`).
This commit is contained in:
@@ -18,10 +18,13 @@ from app.rag.prompts import (
|
||||
ORIGIN_RULE,
|
||||
PERSONA,
|
||||
SEARCH_DISCIPLINE_RULE,
|
||||
SHOW_IMAGE_CLAUSE,
|
||||
SHOW_TEXT_CLAUSE,
|
||||
SUGGEST_INTRO,
|
||||
TOOLS_SECTION,
|
||||
_base,
|
||||
build_deflect_prompt,
|
||||
build_high_prompt,
|
||||
)
|
||||
|
||||
|
||||
@@ -323,3 +326,50 @@ def test_suggest_intro_byte_locked() -> None:
|
||||
) in SUGGEST_INTRO
|
||||
# The retired phase-118 final sentence is gone from the constant.
|
||||
assert "Cite the document(s) you used, by path." not in SUGGEST_INTRO
|
||||
|
||||
|
||||
# ---------- SHOW_TEXT_CLAUSE (phase 182, task 04: verbatim display) ----------
|
||||
|
||||
#: Anchors for ``SHOW_TEXT_CLAUSE`` — the ``show_text`` / ```bor``` locator
|
||||
#: teaching appended INSIDE ``<tools>`` when ``BOR_ANSWER_TEXT`` is on
|
||||
#: (phase 182, LOCKED A1–A3/A6). Pinned the way ``TOOLS_SECTION`` is
|
||||
#: (sha256 + exact prefix + total length) because this clause IS the fix
|
||||
#: for the retype bug the phase exists for: a silent wording drift here
|
||||
#: re-opens it (the tool alone never teaches that the user copies from
|
||||
#: what is DISPLAYED, nor the fence syntax).
|
||||
SHOW_TEXT_CLAUSE_SHA256 = "e03a8153ca6cde61c9437f3b66b4fa07cd2a3f9f2e24e3bb8c37ca1d7c7e9e3b"
|
||||
SHOW_TEXT_CLAUSE_LEN = 1179
|
||||
SHOW_TEXT_CLAUSE_PREFIX = (
|
||||
"`show_text` displays part of a document to the user EXACTLY as stored"
|
||||
)
|
||||
|
||||
|
||||
def test_show_text_clause_byte_locked() -> None:
|
||||
"""The clause is LOCKED copy: sha256 + exact prefix + total length,
|
||||
plus the two sentences the phase's contract depends on verbatim (the
|
||||
copy-from-the-display rule and the server-owns-the-numbers rule)."""
|
||||
assert len(SHOW_TEXT_CLAUSE) == SHOW_TEXT_CLAUSE_LEN
|
||||
assert _sha256(SHOW_TEXT_CLAUSE) == SHOW_TEXT_CLAUSE_SHA256
|
||||
assert SHOW_TEXT_CLAUSE.startswith(SHOW_TEXT_CLAUSE_PREFIX)
|
||||
assert SHOW_TEXT_CLAUSE.endswith("For an image use `show_image` instead.")
|
||||
assert "the user copies from what is displayed, not from your prose" in SHOW_TEXT_CLAUSE
|
||||
assert "the numbers you display are the server's, never yours" in SHOW_TEXT_CLAUSE
|
||||
|
||||
|
||||
def test_high_prompt_display_clause_composition_is_byte_locked() -> None:
|
||||
"""One mechanism, four combinations (phase 182, task 04): neither
|
||||
flag reproduces the untouched :data:`TOOLS_SECTION` tail,
|
||||
``show_image`` alone reproduces the phase-124 bytes exactly,
|
||||
``show_text`` alone appends only the text clause, and both append
|
||||
the image clause, a blank line, the text clause, then the closing
|
||||
tag — ``TOOLS_SECTION`` itself is never edited (its own sha pin
|
||||
above holds)."""
|
||||
off = build_high_prompt([])
|
||||
assert off.endswith(TOOLS_SECTION)
|
||||
head = off[: -len("</tools>")]
|
||||
assert build_high_prompt([], show_image=True) == head + SHOW_IMAGE_CLAUSE + "\n</tools>"
|
||||
assert build_high_prompt([], show_text=True) == head + SHOW_TEXT_CLAUSE + "\n</tools>"
|
||||
assert (
|
||||
build_high_prompt([], show_image=True, show_text=True)
|
||||
== head + SHOW_IMAGE_CLAUSE + "\n\n" + SHOW_TEXT_CLAUSE + "\n</tools>"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user