phase: 106_document_dates
Everything is verified green. Final report: **Phase 106 — Document dates (final verification pass; all 10 tasks already complete)** - Verified all phase artifacts: alembic `0020` (dev DB at `0020`), `doc_dates.py`, git `file_commit_dates`, importer `doc_dates_by_root`/`dates_updated`, both entry-point wirings, date APIs + tree `created_at`/`updated_at`, LLM surfaces (prompt block, `read` line 2, appended `ls` field), `apply_recency_boost` in `retrieve()`, UI columns/badge, admin editor, mock-LLM regex — all present and correct; no defects found, no fixes needed. - `uv run pytest --cov=app --cov-report=term-missing` → **2299 passed, TOTAL 99%** (>90% ✓) - `uv run pytest tests/e2e/test_document_dates.py -v --no-cov` → **6/6 passed** in isolation (DB up) - 12 regression E2E suites (retrieval_quality, whole_document_context, agent_document_tools, ls_tree_drilldown, read_truncation_cap, kb_tree, kb_tree_nav, document_viewer, edit_summaries, import_documents, sync_button, hidden_folders_toggle, smoke) → **all green in isolation** - `uv run ruff check .` → clean; `uv run pyright` → **0 errors, 0 warnings** **Completion criteria:** 1) non-null `created_at` + 0020 upgrade/downgrade on dev DB ✓ (real-Alembic integration tests) 2) sync refresh/older/manual-persists/content-reset/no sources_meta bump ✓ 3) zip/tar mtime + future→today ✓ 4) LLM date surfaces + cross-check ✓ 5) UI Created/Updated/badge positions ✓ 6) admin editor set+revert round-trip ✓ 7) old-correct-beats-new-similar (defaults & boost-off) + near-tie + `BOR_RECENCY_BOOST=0` byte-identical ✓ 8) full gate ✓ 9) commit/phase-move — left to harness per instructions. - **Notable:** recency default tuned 0.001 → **0.0007** (task 07 step 5 explicitly permits; measured margins recorded in `test_recency_boost.py` docstring). - **Next pending phase:** none — `todo/` holds only this phase.
This commit is contained in:
@@ -3,8 +3,9 @@
|
||||
The RAG (Knowledge base) view lists the catalog the way the agent's
|
||||
``ls`` sees it (the phase-94 concept, ONE end to end): sources at the
|
||||
top, then per level the subfolders (recursive count + the STORED
|
||||
description) and the level's files (the existing 5-column
|
||||
``#docs-table`` — unchanged). The view's catalog load is now
|
||||
description) and the level's files (the ``#docs-table`` — phase 106,
|
||||
task 08, D8, added the Created column BEFORE Indexed, making it the
|
||||
6-column contract). The view's catalog load is now
|
||||
``loadTree()``: ONE fetch of ``GET /api/docs/tree`` (the full recursive
|
||||
tree in a single payload — task 02), then client-side drill navigation
|
||||
(no per-level fetch, no URL change).
|
||||
@@ -17,8 +18,12 @@ suite, task 06):
|
||||
* the shell's RAG view ships the static tree skeleton (``#kb-crumb``,
|
||||
``#kb-level`` + ``#kb-level-title``/``#kb-level-summary``,
|
||||
``#folders-wrap`` + ``#folders-table`` — ONE table for every level,
|
||||
the Folder | Documents | Description head) in order after
|
||||
``#stat-cards`` and BEFORE the unchanged file table;
|
||||
the Folder | Documents | Updated | Description head — phase 106
|
||||
(task 08, D8) added the Updated column (the subtree's MAX document
|
||||
created_at, D9) BETWEEN Documents and Description) in order after
|
||||
``#stat-cards`` and BEFORE the file table (now the 6-column
|
||||
Source | Path | Title | Chunks | Created | Indexed head — phase 106
|
||||
(task 08, D8) added the Created column BEFORE Indexed);
|
||||
* the exact ``/api/docs/tree`` fetch (and the flat ``/api/docs`` fetch
|
||||
is gone from the view module);
|
||||
* the drill state (``current`` / ``kbTree``), the state transitions
|
||||
@@ -189,8 +194,10 @@ def test_rag_view_ships_the_tree_skeleton_in_order() -> None:
|
||||
``#kb-crumb`` is the location nav; ``#kb-level`` is the level block
|
||||
(title + description); ``#folders-wrap`` hosts the ONE
|
||||
folders/sources table (``.table-wrap`` card, Folder | Documents |
|
||||
Description, visually-hidden caption, the ``.docs-table``
|
||||
language + ``.kb-folders-table``)."""
|
||||
Updated | Description — phase 106 (task 08, D8), visually-hidden
|
||||
caption, the ``.docs-table`` language + ``.kb-folders-table``).
|
||||
The file table's head is the 6-column contract (Source | Path |
|
||||
Title | Chunks | Created | Indexed — phase 106 (task 08, D8))."""
|
||||
view = _rag_view(_text(SHELL_HTML))
|
||||
for fragment in (
|
||||
'<nav id="kb-crumb" class="kb-crumb" aria-label="Catalog location" hidden></nav>',
|
||||
@@ -209,6 +216,7 @@ def test_rag_view_ships_the_tree_skeleton_in_order() -> None:
|
||||
for column in (
|
||||
"<th scope=\"col\">Folder</th>",
|
||||
"<th scope=\"col\">Documents</th>",
|
||||
"<th scope=\"col\">Updated</th>", # phase 106 (task 08, D8)
|
||||
"<th scope=\"col\">Description</th>",
|
||||
):
|
||||
assert column in head.group(1), f"#folders-table head must carry {column!r}"
|
||||
@@ -221,12 +229,13 @@ def test_rag_view_ships_the_tree_skeleton_in_order() -> None:
|
||||
< view.find('id="folders-wrap"')
|
||||
< view.find('id="docs-table"')
|
||||
), "the skeleton must sit between the stat cards and the file table"
|
||||
# The file table is UNCHANGED (the 5-column contract, makeRow's home).
|
||||
# The file table's head (the 6-column contract — phase 106 (task
|
||||
# 08, D8) added Created BEFORE Indexed; makeRow's home).
|
||||
doc_head = re.search(
|
||||
r'<table class="docs-table" id="docs-table">.*?<thead>(.*?)</thead>', view, re.S
|
||||
)
|
||||
assert doc_head, "the file table must keep its static thead"
|
||||
for column in ("Source", "Path", "Title", "Chunks", "Indexed"):
|
||||
for column in ("Source", "Path", "Title", "Chunks", "Created", "Indexed"):
|
||||
assert f">{column}</th>" in doc_head.group(1), f"#docs-table head must keep {column!r}"
|
||||
|
||||
|
||||
@@ -287,7 +296,9 @@ def test_source_row_click_drills_into_the_source_root() -> None:
|
||||
The row carries the recursive count and the stored (source, "")
|
||||
description — textContent only."""
|
||||
js = _js()
|
||||
body = js[js.find("function makeSourceRow(") : js.find("function makeSourceRow(") + 1200]
|
||||
# Slice to the next function (the row builders grew with phase 106's
|
||||
# Updated cell — a fixed window would drift out of the function).
|
||||
body = js[js.find("function makeSourceRow(") : js.find("function makeFolderRow(")]
|
||||
assert 'link.className = "folder-link"' in body, "the source row uses the row drill link"
|
||||
assert "link.textContent = s.name" in body
|
||||
assert "goTo({ source: s.name, folder: \"\" })" in body, (
|
||||
@@ -309,7 +320,7 @@ def test_folder_row_click_drills_into_the_folder() -> None:
|
||||
`{ source, folder: f.path }` (the source-relative folder path)."""
|
||||
js = _js()
|
||||
start = js.find("function makeFolderRow(")
|
||||
body = js[start : start + 1400]
|
||||
body = js[start : js.find("function renderLevel(")]
|
||||
assert 'link.className = "folder-link"' in body
|
||||
assert "link.textContent = f.path.split(\"/\").pop()" in body, (
|
||||
"the label is the last segment (the breadcrumb language)"
|
||||
@@ -1370,7 +1381,9 @@ def test_styles_carry_the_one_line_clamp() -> None:
|
||||
"white-space: nowrap",
|
||||
):
|
||||
assert prop in text, f".kb-desc-text must carry {prop!r}"
|
||||
col_i = css.find(".kb-folders-table td:nth-child(3) {")
|
||||
# Phase 106 (task 08): the clamp follows the Description cell, which
|
||||
# moved to the 4th column (Updated took 3rd).
|
||||
col_i = css.find(".kb-folders-table td:nth-child(4) {")
|
||||
assert col_i != -1
|
||||
col = css[col_i : col_i + 400]
|
||||
col = col[: col.find("\n}")]
|
||||
|
||||
Reference in New Issue
Block a user