Files
brain-of-reese/.agent/user_stories/whole-document-context.md
T

3.4 KiB
Raw Blame History

Story: Whole-Document Context — a matched document is never truncated

Phase: 24_whole_document_context · E2E: tests/e2e/test_whole_document_context.py

Bug report (TODO.md L3–L4, verbatim)

"Documents are truncated for some reason? This should never happen"

"When the LLM matches a chunk it should get the entire document placed in its context so it can see the whole thing before answering the question"

Narrative

As a user asking about an indexed note, I want the entire document in the LLM's context whenever retrieval matches one of its chunks — so the answer is grounded in the whole note, not a silently cut-down version of it.

  • Given a question whose chunk matches a document
  • When the turn assembles context
  • Then the LLM receives the entire parent document — never a […truncated…]-cut version — so the answer is grounded in the whole note.

Owner-confirmed (2026-08-24, roadmap D1–D5)

  1. D1 — no cap at all (revises LOCKED A7): select_documents returns the full top-N document texts, always. The max_context_chars setting and BOR_MAX_CONTEXT_CHARS env var are removed. If a future KB ever makes the prompt too large for the model, the existing LLMError → SSE error path surfaces it loudly — no silent partial context. The emergency-valve variant (raised cap + warning log) was explicitly rejected.
  2. D2 — top_n_docs = 2 unchanged (the TODO is about truncation, not about how many documents).
  3. D3 — no viewer/import changes — both already serve full content (verified diagnosis above).
  4. D4 — E2E evidence via a deterministic mock tail-echo (repo pattern, cf. the phase-15 tuning-note echo); the big documents are seeded directly in the DB inside the E2E test — tests/fixtures/docs/ must not grow, because other suites pin summary.added == 8.
  5. D5 — no query_log schema change (no new columns, no migration).

Acceptance criteria

  1. No budget parameter in select_documents — it never truncates (TRUNCATION_MARKER remains for the steering section only).
  2. BOR_MAX_CONTEXT_CHARS gone from settings/env/README (app/config.py, .env.example, README.md).
  3. The story E2E's three tests green in isolation (uv run pytest tests/e2e/test_whole_document_context.py -v --no-cov).
  4. Steering-note truncation (phase 15, BOR_STEERING_MAX_CHARS + shared marker) unchanged.
  5. Unit + integration green, app/ coverage >90%, one --no-gpg-sign commit.

Playwright Mapping Rule

Test Scenario → tests/e2e/test_whole_document_context.py (mock LLM tail-echo, oversized documents seeded directly in the DB):

  1. test_whole_document_over_old_cap_reaches_llm — a 30 000-char document (past the old 24 000 cap): its tail sentinel (last line) is echoed in the rendered answer, […truncated…] is absent, the source chip renders, query_log row deflected == False.
  2. test_second_document_of_over_cap_pair_reaches_llm — two ~16 000-char documents (32 000 combined — the exact case the old budget cut): the second, lower-ranked document's tail sentinel is echoed (doc 1's is not — it pins the rank order), both source chips render.
  3. test_small_document_path_unchanged — regression: standard fixtures via the real importer → grounded answer with the kubernetes.md chip, no […truncated…] (the under-cap path is byte-identical to before).