phase: 142_kb_overview_freshness
Build and Push Containers / build-and-push-app (push) Successful in 2m33s
Build and Push Containers / build-and-push-db (push) Successful in 12s

All verification complete. Final report:

**Phase 142 final verification pass — all green**

- **Verified implemented** (working tree matches design; app diff is exactly 2 lines of logic): `app/rag/overview.py` — `regenerate_overview` now orders the lite-model document list `created_at` desc, `(source, path)` tie-break (newest docs survive the cap); `app/rag/prompts.py` — `_KB_INTRO` rewritten to the honest intro (recency bias, "map not inventory", verify-with-`ls`/`grep`; "(generated at import time)" gone).
- **Completion criteria:**
  1. Forced-cap outline leads with newest docs — ✅ E2E `test_kb_overview_freshness.py` test 1 (cap 300, digest from `zz_new/z.md`, no "old" tokens) + integration repro (cap 150 → `mydocs zz new 03 md zz new 03`)
  2. New honest intro served in `<knowledge_base>` — ✅ unit pin (verbatim) + E2E test 2 (`build_kb_section` surface, tag/cap byte-stable)
  3. Gates — ✅ `uv run pytest --cov=app --cov-report=term-missing`: **3359 passed**, `app/` TOTAL **99%** (>90%); `uv run pytest tests/e2e/test_kb_overview_freshness.py -v --no-cov`: **3 passed** in isolation; `uv run pytest tests/e2e/test_kb_overview.py -v --no-cov`: **4 passed** in isolation; `uv run ruff check . && uv run pyright`: **clean, 0 errors**
  4. No behavior change in completed phases — ✅ cap env knob, change-gated sync trigger, `build_kb_section` cap/marker, deflect path all byte-identical (pinned pins pass in the 3359)
- **Documentation:** README.md reviewed in full (every `.env.example` var documented with matching defaults, all endpoints/routes verified against `app/api/`, Quick Start/deploy/troubleshooting claims verified) and AGENTS.md re-reviewed (rules + quick reference accurate) — **verified consistent, no changes needed**.
- **Decisions:** none required — no defects found; no live-infra changes (only the already-running local `db` container was used by tests).
- **Next pending phase:** `.agents/phases/todo/143_mobile_keyboard_after_answer`.
This commit is contained in:
2026-10-01 04:25:03 -04:00
parent a8c0402ad2
commit aa65d2d691
30 changed files with 1738 additions and 38 deletions
+30 -9
View File
@@ -1,10 +1,23 @@
"""KB overview generator (phase 31, task 02).
Builds the ``KB_OVERVIEW_MODE`` prompt from the document catalogue
(source, path, title, first summary line per document), calls the aipi
``lite`` model through the one-shot ``LLMClient.chat`` (phase 30, same
model as document summaries — no new model management), and stores the
plain-text outline in the single ``kb_overview`` row (migration 0005).
(one line per document: source, path, title, first summary line —
ordered RECENT-FIRST by the document's date, phase 142 task 02),
calls the aipi ``lite`` model through the one-shot ``LLMClient.chat``
(phase 30, same model as document summaries — no new model management),
and stores the plain-text outline in the single ``kb_overview`` row
(migration 0005).
The recency-first order is what makes the input cap honest: when
``BOR_OVERVIEW_INPUT_MAX_CHARS`` cuts the list, the documents that fall
off are the OLDEST, so the outline always represents the recent state
of the KB. The sort reads ``Document.created_at`` — phase 106's
git-history/mtime-derived, owner-correctable document date (the same
date the ``read`` tool's ``date:`` line shows); ``created_at_manual``
rows are included exactly as stored, the ordering never re-derives
dates. Same-date documents tie-break by ``(source, path)``, keeping
the pre-phase-142 lexicographic order within a date (deterministic for
the mock's digest; byte-identical for single-date KBs).
Chat turns never generate an overview — they read the stored row
(:func:`load_kb_overview`, one indexed PK lookup) and inject it into the
@@ -99,10 +112,12 @@ def build_overview_prompt(
+ the locked instruction.
* ``user`` — one line per document,
``source — path — title — {first line of summary}``, joined with
newlines. The summary field is omitted when the document has no
summary (pre-phase-30 rows, the fail-soft path, and pre-backfill
NULL rows — no dangling dash). The list is capped at *max_chars*
(default
newlines, in the EXACT order the caller passes *rows* (order-
preserving; the caller — :func:`regenerate_overview` — passes the
catalogue recent-first, phase 142 task 02). The summary field is
omitted when the document has no summary (pre-phase-30 rows, the
fail-soft path, and pre-backfill NULL rows — no dangling dash).
The list is capped at *max_chars* (default
``BOR_OVERVIEW_INPUT_MAX_CHARS``): overflow is cut exactly at the
cap and the shared ``[…truncated…]`` marker is appended on its own
line, so the model never sees more than the cap and the cut is
@@ -163,9 +178,15 @@ async def regenerate_overview(
if session is None:
session = SessionLocal()
try:
# RECENT-FIRST (phase 142, task 02): the document's date
# (``created_at``, phase 106) descending, so when the input cap
# bites the OLDEST documents fall off — the outline always
# represents the recent KB. The (source, path) tie-break keeps
# same-date documents in the pre-phase-142 lexicographic order
# (deterministic digest; byte-identical for single-date KBs).
result = session.execute(
select(Document.source, Document.path, Document.title, Document.summary)
.order_by(Document.source, Document.path)
.order_by(Document.created_at.desc(), Document.source, Document.path)
).all()
rows: list[tuple[str, str, str, str | None]] = [
(source, path, title, summary)
+16 -4
View File
@@ -125,11 +125,23 @@ _STEERING_INTRO = (
"Where these instructions conflict with the defaults above, follow the owner:\n"
)
#: One-line intro of the ``<knowledge_base>`` section (phase 31): the
#: lite-generated outline is the agent's a-priori picture of the KB.
#: One-line intro of the ``<knowledge_base>`` section (phase 31;
#: phase 142, task 03 — the honest-intro rewrite, owner-confirmed
#: 2026-09-30): the outline is a COMPACT, possibly partial picture
#: that favors RECENT documents (task 02 orders the generation input
#: newest-first, so recent docs are the ones it covers when the cap
#: bites) — a map of what exists, not a complete inventory — and
#: "latest / complete set" questions verify with ``ls``/``grep``
#: before answering from it; "(generated at import time)" is GONE
#: (false — the sync regenerates the row on every KB change — and it
#: taught the model to treat a partial outline as the whole frozen KB).
_KB_INTRO = (
"The basic categories of everything in this knowledge base "
"(generated at import time):\n"
'A compact picture of the knowledge base\'s categories and topics — '
'it favors recent documents and may omit older or lesser ones: a map '
'of what exists, not a complete inventory. For questions about the '
'latest state or the complete set ("the last N …", "everything '
'about …", "all the …"), verify with `ls` (drill into the folders) '
'or `grep` before answering from the outline:\n'
)
#: The ``<documents>`` section's start-here intro (phase 118, task 03 —