phase: 95_read_truncation_cap
All gates are green. Final verification is complete — no fixes were needed; the phase is fully implemented and passing. **Phase 95 final verification report** - Verified all 3 tasks already implemented (task files in `complete/`): read cap + notice + `ToolResultPiece` (task 01), `tool_result` SSE + live/saved/shared marker (task 02), E2E suite (task 03). - Code checks passed: `BOR_READ_MAX_CHARS` (default 128 000, validator), pinned `READ_TRUNCATION_NOTICE` + `TRUNCATION_MARKER`, byte-identical at/under-cap read, holder `read_truncations` (no `tool_calls` impact), piece order (after `tool`, before next round), `ChatToolResultEvent`, `ToolCall` back-compat fields, `app.js` live/restore handlers, `shared.js`, `.truncated-note` CSS, `.env.example` entry, mock-LLM echo script. - **Tests:** `uv run pytest` → 1966 passed; `uv run pytest --cov=app --cov-report=term-missing` → all green, TOTAL **99%** (>90% gate). - **E2E:** `uv run pytest tests/e2e/test_read_truncation_cap.py -v --no-cov` → **3 passed** (frame order + live marker + LLM notice via echo; save→shared fidelity; short-read control). - **Regression (isolated):** `test_agent_document_tools` 4 ✓, `test_chat_history` 5 ✓, `test_share_chat` 4 ✓, `test_big_read_progress` 4 ✓, `test_stop_generation` 3 ✓. - **Lint/types:** `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors, 0 warnings. **Completion criteria:** ① over-cap read → first-cap-chars + marker + pinned notice — ✓ (unit-pinned: at-cap/cap+1/notice tests); ② user marker live/saved/shared — ✓ (E2E + frontend tests); ③ at/under cap byte-identical, no frame — ✓ (unit + control E2E); ④ top-2 `<documents>` retrieval untouched — ✓ (`app/rag/retriever.py` unmodified vs HEAD); ⑤ suite green, >90% coverage, ruff+pyright clean — ✓; ⑥ no completed-phase behavior change — ✓ (all gates green; commit left to harness per pass rules). - No defects found; no changes made this pass. Next pending phase: none in `todo/` (96 is the next free number).
This commit is contained in:
@@ -209,6 +209,32 @@ def test_agent_max_rounds_rejects_negative(monkeypatch: pytest.MonkeyPatch) -> N
|
||||
_settings()
|
||||
|
||||
|
||||
def test_read_max_chars_default_and_env_override(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Phase 95: the agent ``read`` tool's result is capped at
|
||||
``BOR_READ_MAX_CHARS`` (default 128 000 chars ≈ 32k tokens — a
|
||||
quarter of the owner's 128k-token minimum context). Env-tunable in
|
||||
both directions."""
|
||||
monkeypatch.delenv("BOR_READ_MAX_CHARS", raising=False)
|
||||
assert _settings().read_max_chars == 128_000
|
||||
monkeypatch.setenv("BOR_READ_MAX_CHARS", "5000")
|
||||
assert _settings().read_max_chars == 5000
|
||||
# ``0`` is legal (every non-empty read truncates to the marker +
|
||||
# notice) — it is not a kill switch, so no lower-bound error.
|
||||
monkeypatch.setenv("BOR_READ_MAX_CHARS", "0")
|
||||
assert _settings().read_max_chars == 0
|
||||
|
||||
|
||||
def test_read_max_chars_rejects_negative(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""A negative cap is a typo — it would slice from the END of the
|
||||
content (negative indexing) instead of failing, so the validator
|
||||
fails loudly at startup (the ``agent_max_rounds`` pattern)."""
|
||||
monkeypatch.setenv("BOR_READ_MAX_CHARS", "-1")
|
||||
with pytest.raises(ValidationError, match="read_max_chars"):
|
||||
_settings()
|
||||
|
||||
|
||||
def test_stream_thinking_default_true_and_env_parse(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Phase 17 kill-switch (``BOR_STREAM_THINKING``): on by default,
|
||||
``0``/``false`` turn the ``thinking`` SSE frames off."""
|
||||
|
||||
Reference in New Issue
Block a user