Files
brain-of-reese/alembic/versions/0017_folder_summaries.py
T
ducoterra d4943b4822
Build and Push Containers / build-and-push-app (push) Successful in 1m45s
Build and Push Containers / build-and-push-db (push) Successful in 25s
phase: 94_ls_tree_drilldown
All green. Verification complete.

**Phase 94 — `ls` drill-down tree: final verification pass (all 5 tasks were already complete; verified, nothing to fix)**

- Verified `ls` 3-level tree (`app/rag/agent.py`): `ls()` sources + summaries, `ls(source)`/`ls(source/folder)` drill-down, 50-line file cap + grep-pointer note, NOT-A-FOLDER teaching refusal
- Verified `folder_summaries` (migration 0017, model, `app/rag/folder_summaries.py` generator: `FOLDER_SUMMARY_MODE` marker, fail-soft per folder, ≥2-doc scope + prune) wired change-gated in both sync paths
- Verified 10-turn fixture battery verdict recorded in `TOOL_CALLING_TESTING.md` §9 (2026-09-11): turbo PASS 19/19 contract, 98.7 s (−12.5…−13.2 % vs baseline); lite PASS 18/18, 43.6 s (+7.7 %) — accuracy at/above baseline, gate met
- `uv run pytest --cov=app --cov-report=term-missing` → 1939 passed, 0 failed; TOTAL coverage **99 %** (folder_summaries.py 100 %)
- `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings
- E2E in isolation: `test_ls_tree_drilldown.py` 3 passed; `test_agent_document_tools` 4, `test_agent_unlimited_tools` 4, `test_harness_aligned_tools` 3, `test_search_tool` 3, `test_grep_regex_teaching` 2, `test_response_to_docs` 4 — all passed (read/grep contracts untouched)
- Dedicated folder-summary tests (fail-soft, prune, both sync paths, migration): 46 passed
- Completion criteria: all 6 met; working tree holds only phase-94 changes (commit left to harness per protocol)

**Next pending phase:** `95_read_truncation_cap`
2026-09-11 00:59:35 -04:00

64 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""folder_summaries: sync-time lite folder summaries (phase 94, task 01)
Revision ID: 0017
Revises: 0016
Create Date: 2026-09-10
Phase 94 (``ls`` becomes a filesystem-style drill-down tree — TODO.md
L4): the LLM lists the synced projects, then drills into folders; each
level's listing shows the folder's **subtree summary** — a 1–3 sentence
plain-text description of what the folder's documents cover, generated
at sync time by the aipi ``lite`` model (the ``KB_OVERVIEW_MODE``
contract, ``app.rag.overview``: change-gated by the caller, fail-soft,
``FOLDER_SUMMARY_MODE`` marker for the E2E mock). This migration adds
the storage — ONE additive, fully reversible table (A13), no other
schema change:
* ``folder_summaries`` — one row per folder with ≥ 2 documents
(recursive count — the same set the ``ls`` count rule counts,
``00_phase.md``; the ≥ 2 rule and the prune rule are generator
policy, ``app.rag.folder_summaries``, not schema constraints):
* PK ``(source, folder_path)`` — ``source`` is VARCHAR(120) NOT NULL
(mirrors ``documents.source``); ``folder_path`` is VARCHAR(1000)
NOT NULL (mirrors ``documents.path`` — the source-relative folder
prefix). ``folder_path = ""`` is the SOURCE ROOT: the top-level
source summary (the whole source's recursive subtree).
* ``summary`` — TEXT NOT NULL: the ``lite``-written description
(never empty — the generator validates before storing).
* ``updated_at`` — TIMESTAMPTZ NOT NULL, server default now() (house
style — the ``kb_overview.updated_at`` precedent); the generator
always stamps it explicitly on upsert.
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
revision = "0017"
down_revision = "0016"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
"folder_summaries",
sa.Column("source", sa.String(length=120), primary_key=True),
sa.Column("folder_path", sa.String(length=1000), primary_key=True),
sa.Column("summary", sa.Text(), nullable=False),
sa.Column(
"updated_at",
sa.DateTime(timezone=True),
server_default=sa.func.now(),
nullable=False,
),
)
def downgrade() -> None:
# The table is the only 0017 artefact — dropping it leaves the 0016
# schema byte-identical (A13, fully reversible).
op.drop_table("folder_summaries")