From 4f20c256d7eed76adda4bc87e7d4e9f908468c30 Mon Sep 17 00:00:00 2001 From: ducoterra Date: Mon, 19 Oct 2026 06:13:32 -0400 Subject: [PATCH] phase: 191_source_name_labels_tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All gates re-verified against a stable tree. Report: **Verified (all 6 tasks in `complete/`; this was the final pass)** - `SourceLabel`+alembic `0030` (dev DB `alembic current` = `0030 (head)`, table present, 0 rows); admin-only `GET/PUT/DELETE /api/source-labels` (`require_admin` router-wide, `resolve_source_name`, partial-update caps/404s); Sources-page "Names, labels and tags" card (read-only derived-name ``, per-row `saveInFlight`, 404 note that survives the settle, chips reuse `.git-source-hidden-count`); `question_name_hits` D2 rule; ONE `all_labels` read per turn in `chat.py` feeding both the `source_name_hit` flag and the prompt surfaces; `source_name_hit_bonus=0.005` in `_selection_order`; ` name=`/` label=` in `build_high_prompt` + `build_overview_prompt(names=…)`. - **Completion criteria:** E2E `tests/e2e/test_source_name_labels.py` ✅ 7 passed (arms a–e: editor all kinds, control/named question, rename-never-breaks-identity, 404 note, reset) · full suite ✅ · coverage ✅ · README/AGENTS ✅ · phase dir in `complete/` ✅ · commit left to the harness. - **Gates:** `uv run pytest --cov=app --cov-report=term-missing` → **exit 0, TOTAL 7160 stmts / 16 missed = 99%** (>90%) · `uv run pytest tests/e2e/test_source_name_labels.py -v --no-cov` → **7 passed, exit 0** · regression E2E isolated, exit 0: `test_document_viewer`, `test_admin_auth`, `test_api_tokens`, `test_git_sources_admin`, `test_kb_tree`, `test_local_directory_sources` · `uv run ruff check .` → All checks passed · `uv run pyright` → 0 errors. - **Battery (task 04 criterion):** `uv run python -m scripts.eval_retrieval --from-file tests/fixtures/retrieval_battery.txt` at default vs `BOR_SOURCE_NAME_HIT_BONUS=0` → **`diff` empty (line-for-line identical)**, matching the recorded arms (dev KB is empty, so every question deflects; the observable boost is unit/E2E-pinned). - **Documentation:** README — fixed the `/git-sources.html` rows (nav label is **Sources**) and cross-linked the phase-191 card from that section; full audit otherwise clean: all 86 `BOR_*` settings documented with defaults matching `app/config.py`, 0 broken file/dir references and 0 broken anchors in README+AGENTS, AGENTS rule 17 re-checked line-by-line against the code. - **Notable / deviations:** (1) a **concurrent pipeline process** (`phased-execution/progress.mjs` for `191_…_00_phase`) was mutating this same working tree mid-pass — it rewrote `tests/e2e/test_source_name_labels.py` (11→7 tests), `frontend/assets/git-sources.js`, `tests/unit/test_source_labels_editor_ui.py` and `AGENTS.md` at 05:27; every gate above was (re-)run after those edits with the tree no source file newer than the green full run. (2) The task-06 report/phase text claims regression suites `test_chat_token_gate.py`, `test_git_sources_page.py`, `test_rag_browser.py` are green — **those files have never existed in git history** (those runs exit 4); I ran the real equivalents listed above instead (phase files are not mine to edit). (3) **No live changes**: the VM DB already has `source_labels` (0 rows) but the deployed app predates this uncommitted code, so deploying `/api/source-labels` to the live service is the owner's post-commit step, not part of this phase's criteria. - **Next pending phase:** none — `191_source_name_labels_tags` is the only entry in `.agents/phases/todo/`. --- .../191_source_name_labels_tags/00_phase.md | 0 .../01_source_labels_table.md | 0 .../02_source_labels_api.md | 0 .../03_source_labels_ui.md | 0 .../04_source_name_boost.md | 0 .../05_prompt_surfacing.md | 0 .../191_source_name_labels_tags/06_e2e.md | 0 ...1_source_name_labels_tags__00_phase.a1.err | 0 ...91_source_name_labels_tags__00_phase.a1.md | 10 + ...ce_name_labels_tags__00_phase.a1.md.status | 1 + ...rce_name_labels_tags__00_phase.a1.validate | 150 +++ ...labels_tags__01_source_labels_table.a1.err | 0 ..._labels_tags__01_source_labels_table.a1.md | 18 + ..._tags__01_source_labels_table.a1.md.status | 1 + ...s_tags__01_source_labels_table.a1.validate | 147 +++ ...e_labels_tags__02_source_labels_api.a1.err | 0 ...me_labels_tags__02_source_labels_api.a1.md | 19 + ...ls_tags__02_source_labels_api.a1.md.status | 1 + ...els_tags__02_source_labels_api.a1.validate | 149 +++ ...me_labels_tags__03_source_labels_ui.a1.err | 0 ...ame_labels_tags__03_source_labels_ui.a1.md | 15 + ...els_tags__03_source_labels_ui.a1.md.status | 1 + ...bels_tags__03_source_labels_ui.a1.validate | 149 +++ ...e_labels_tags__04_source_name_boost.a1.err | 0 ...me_labels_tags__04_source_name_boost.a1.md | 19 + ...ls_tags__04_source_name_boost.a1.md.status | 1 + ...els_tags__04_source_name_boost.a1.validate | 149 +++ ...bels_tags__04_source_name_boost.battery.md | 17 + ...me_labels_tags__05_prompt_surfacing.a1.err | 0 ...ame_labels_tags__05_prompt_surfacing.a1.md | 20 + ...els_tags__05_prompt_surfacing.a1.md.status | 1 + ...bels_tags__05_prompt_surfacing.a1.validate | 150 +++ ...191_source_name_labels_tags__06_e2e.a1.err | 0 .../191_source_name_labels_tags__06_e2e.a1.md | 17 + ...urce_name_labels_tags__06_e2e.a1.md.status | 1 + ...ource_name_labels_tags__06_e2e.a1.validate | 150 +++ .../screenshots/doc_modal_scrollbar_1280.png | Bin 43137 -> 43439 bytes .env.example | 1 + AGENTS.md | 93 ++ README.md | 87 +- alembic/versions/0030_source_labels.py | 85 ++ app/api/chat.py | 52 +- app/api/source_labels.py | 249 ++++ app/config.py | 28 + app/core/settings_catalog.py | 7 + app/main.py | 6 + app/models.py | 62 + app/rag/overview.py | 47 +- app/rag/prompts.py | 78 +- app/rag/retriever.py | 92 +- app/rag/source_labels.py | 254 ++++ app/schemas.py | 115 ++ frontend/assets/git-sources.js | 540 +++++++++ frontend/assets/styles.css | 263 +++- frontend/index.html | 118 ++ scripts/api_payload_audit.py | 3 + tests/e2e/test_source_name_labels.py | 1066 +++++++++++++++++ tests/integration/test_chunks_hnsw_index.py | 20 +- tests/integration/test_migration_0030.py | 311 +++++ tests/integration/test_source_labels_api.py | 753 ++++++++++++ tests/unit/test_chat_gate.py | 113 ++ tests/unit/test_config.py | 33 + tests/unit/test_git_source_branch_ui.py | 8 +- tests/unit/test_hidden_folders_toggle.py | 10 +- tests/unit/test_overview.py | 217 ++++ tests/unit/test_prompts.py | 209 ++++ tests/unit/test_retriever.py | 183 ++- tests/unit/test_settings_catalog.py | 23 + tests/unit/test_source_labels.py | 370 ++++++ tests/unit/test_source_labels_editor_ui.py | 746 ++++++++++++ 70 files changed, 7378 insertions(+), 50 deletions(-) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/00_phase.md (100%) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/01_source_labels_table.md (100%) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/02_source_labels_api.md (100%) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/03_source_labels_ui.md (100%) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/04_source_name_boost.md (100%) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/05_prompt_surfacing.md (100%) rename .agents/phases/{todo => complete}/191_source_name_labels_tags/06_e2e.md (100%) create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.validate create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.validate create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.validate create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.validate create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__04_source_name_boost.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__04_source_name_boost.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__04_source_name_boost.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__04_source_name_boost.a1.validate create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__04_source_name_boost.battery.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__05_prompt_surfacing.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__05_prompt_surfacing.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__05_prompt_surfacing.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__05_prompt_surfacing.a1.validate create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__06_e2e.a1.err create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__06_e2e.a1.md create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__06_e2e.a1.md.status create mode 100644 .agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__06_e2e.a1.validate create mode 100644 alembic/versions/0030_source_labels.py create mode 100644 app/api/source_labels.py create mode 100644 app/rag/source_labels.py create mode 100644 tests/e2e/test_source_name_labels.py create mode 100644 tests/integration/test_migration_0030.py create mode 100644 tests/integration/test_source_labels_api.py create mode 100644 tests/unit/test_source_labels.py create mode 100644 tests/unit/test_source_labels_editor_ui.py diff --git a/.agents/phases/todo/191_source_name_labels_tags/00_phase.md b/.agents/phases/complete/191_source_name_labels_tags/00_phase.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/00_phase.md rename to .agents/phases/complete/191_source_name_labels_tags/00_phase.md diff --git a/.agents/phases/todo/191_source_name_labels_tags/01_source_labels_table.md b/.agents/phases/complete/191_source_name_labels_tags/01_source_labels_table.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/01_source_labels_table.md rename to .agents/phases/complete/191_source_name_labels_tags/01_source_labels_table.md diff --git a/.agents/phases/todo/191_source_name_labels_tags/02_source_labels_api.md b/.agents/phases/complete/191_source_name_labels_tags/02_source_labels_api.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/02_source_labels_api.md rename to .agents/phases/complete/191_source_name_labels_tags/02_source_labels_api.md diff --git a/.agents/phases/todo/191_source_name_labels_tags/03_source_labels_ui.md b/.agents/phases/complete/191_source_name_labels_tags/03_source_labels_ui.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/03_source_labels_ui.md rename to .agents/phases/complete/191_source_name_labels_tags/03_source_labels_ui.md diff --git a/.agents/phases/todo/191_source_name_labels_tags/04_source_name_boost.md b/.agents/phases/complete/191_source_name_labels_tags/04_source_name_boost.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/04_source_name_boost.md rename to .agents/phases/complete/191_source_name_labels_tags/04_source_name_boost.md diff --git a/.agents/phases/todo/191_source_name_labels_tags/05_prompt_surfacing.md b/.agents/phases/complete/191_source_name_labels_tags/05_prompt_surfacing.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/05_prompt_surfacing.md rename to .agents/phases/complete/191_source_name_labels_tags/05_prompt_surfacing.md diff --git a/.agents/phases/todo/191_source_name_labels_tags/06_e2e.md b/.agents/phases/complete/191_source_name_labels_tags/06_e2e.md similarity index 100% rename from .agents/phases/todo/191_source_name_labels_tags/06_e2e.md rename to .agents/phases/complete/191_source_name_labels_tags/06_e2e.md diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.err b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md new file mode 100644 index 0000000..8d3c1fa --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md @@ -0,0 +1,10 @@ +All gates re-verified against a stable tree. Report: + +**Verified (all 6 tasks in `complete/`; this was the final pass)** +- `SourceLabel`+alembic `0030` (dev DB `alembic current` = `0030 (head)`, table present, 0 rows); admin-only `GET/PUT/DELETE /api/source-labels` (`require_admin` router-wide, `resolve_source_name`, partial-update caps/404s); Sources-page "Names, labels and tags" card (read-only derived-name ``, per-row `saveInFlight`, 404 note that survives the settle, chips reuse `.git-source-hidden-count`); `question_name_hits` D2 rule; ONE `all_labels` read per turn in `chat.py` feeding both the `source_name_hit` flag and the prompt surfaces; `source_name_hit_bonus=0.005` in `_selection_order`; ` name=`/` label=` in `build_high_prompt` + `build_overview_prompt(names=…)`. +- **Completion criteria:** E2E `tests/e2e/test_source_name_labels.py` ✅ 7 passed (arms a–e: editor all kinds, control/named question, rename-never-breaks-identity, 404 note, reset) · full suite ✅ · coverage ✅ · README/AGENTS ✅ · phase dir in `complete/` ✅ · commit left to the harness. +- **Gates:** `uv run pytest --cov=app --cov-report=term-missing` → **exit 0, TOTAL 7160 stmts / 16 missed = 99%** (>90%) · `uv run pytest tests/e2e/test_source_name_labels.py -v --no-cov` → **7 passed, exit 0** · regression E2E isolated, exit 0: `test_document_viewer`, `test_admin_auth`, `test_api_tokens`, `test_git_sources_admin`, `test_kb_tree`, `test_local_directory_sources` · `uv run ruff check .` → All checks passed · `uv run pyright` → 0 errors. +- **Battery (task 04 criterion):** `uv run python -m scripts.eval_retrieval --from-file tests/fixtures/retrieval_battery.txt` at default vs `BOR_SOURCE_NAME_HIT_BONUS=0` → **`diff` empty (line-for-line identical)**, matching the recorded arms (dev KB is empty, so every question deflects; the observable boost is unit/E2E-pinned). +- **Documentation:** README — fixed the `/git-sources.html` rows (nav label is **Sources**) and cross-linked the phase-191 card from that section; full audit otherwise clean: all 86 `BOR_*` settings documented with defaults matching `app/config.py`, 0 broken file/dir references and 0 broken anchors in README+AGENTS, AGENTS rule 17 re-checked line-by-line against the code. +- **Notable / deviations:** (1) a **concurrent pipeline process** (`phased-execution/progress.mjs` for `191_…_00_phase`) was mutating this same working tree mid-pass — it rewrote `tests/e2e/test_source_name_labels.py` (11→7 tests), `frontend/assets/git-sources.js`, `tests/unit/test_source_labels_editor_ui.py` and `AGENTS.md` at 05:27; every gate above was (re-)run after those edits with the tree no source file newer than the green full run. (2) The task-06 report/phase text claims regression suites `test_chat_token_gate.py`, `test_git_sources_page.py`, `test_rag_browser.py` are green — **those files have never existed in git history** (those runs exit 4); I ran the real equivalents listed above instead (phase files are not mine to edit). (3) **No live changes**: the VM DB already has `source_labels` (0 rows) but the deployed app predates this uncommitted code, so deploying `/api/source-labels` to the live service is the owner's post-commit step, not part of this phase's criteria. +- **Next pending phase:** none — `191_source_name_labels_tags` is the only entry in `.agents/phases/todo/`. diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md.status b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.validate b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.validate new file mode 100644 index 0000000..d224b5a --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__00_phase.a1.validate @@ -0,0 +1,150 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 22%] +........................................................................ [ 24%] +........................................................................ [ 25%] +........................................................................ [ 27%] +........................................................................ [ 28%] +........................................................................ [ 30%] +........................................................................ [ 31%] +........................................................................ [ 33%] +........................................................................ [ 34%] +........................................................................ [ 36%] +........................................................................ [ 37%] +........................................................................ [ 39%] +........................................................................ [ 40%] +........................................................................ [ 42%] +........................................................................ [ 43%] +........................................................................ [ 45%] +........................................................................ [ 46%] +........................................................................ [ 48%] +........................................................................ [ 49%] +........................................................................ [ 51%] +........................................................................ [ 52%] +........................................................................ [ 54%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 65%] +........................................................................ [ 66%] +........................................................................ [ 68%] +........................................................................ [ 69%] +........................................................................ [ 71%] +........................................................................ [ 72%] +........................................................................ [ 74%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 78%] +........................................................................ [ 80%] +........................................................................ [ 81%] +........................................................................ [ 83%] +........................................................................ [ 84%] +........................................................................ [ 86%] +........................................................................ [ 87%] +........................................................................ [ 89%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 93%] +........................................................................ [ 95%] +........................................................................ [ 96%] +........................................................................ [ 98%] +........................................................................ [ 99%] +........... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 298 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/source_labels.py 52 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 332 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/memory.py 32 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 107 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 82 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 178 0 100% +app/rag/retriever.py 270 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 576 0 100% +-------------------------------------------------- +TOTAL 7160 16 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.err b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md new file mode 100644 index 0000000..491bd85 --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md @@ -0,0 +1,18 @@ +Task 01 complete. Report: + +**Implemented** +- `app/models.py`: new `SourceLabel` model (D1 spec: `source` String(120) PK, `display_name`/`label` plain-Text nullable, `tags` JSONB NOT NULL default `'[]'`, `updated_at` now()/onupdate) + module docstring table entry; alias-only contract documented. +- `alembic/versions/0030_source_labels.py` (rev `0030` ← `0029`): additive CREATE TABLE, no backfill, `DROP TABLE` downgrade; verified up/down/up on the dev DB. +- `app/rag/source_labels.py`: `SourceLabelView`, `get_label`/`label_for`/`all_labels`, `set_label` (upsert, `_UNSET`-sentinel partial-update — omitted untouched, explicit `None` clears; flush-only), `delete_label`, `normalize_tags` (trim/drop-empties, ≤10 / ≤32 ValueErrors, first-case case-insensitive de-dupe), `question_name_hits` (D2: reused `name_hit_tokens` + `_normalize_name`, 4-char floor on both sides, no digit rule), `question_name_hit_sources` (one query). +- **Defect fix (pre-existing latent)**: `test_chunks_hnsw_index.py::test_invalid_index_is_dropped_and_rebuilt` stamped below head without dropping later migrations' tables — once 0030 landed, every following `upgrade(head)` died on `source_labels already exists` (221 cascade errors). Now genuinely `downgrade("0029")` before the stamp; consistent with AGENTS rule 16. + +**Gates** (all green) +- `uv run pytest --cov=app --cov-report=term-missing` → **4667 passed**, TOTAL **99%**, `app/rag/source_labels.py` **100%**; dev DB left at `0030 (head)`. +- `tests/unit/test_source_labels.py` 31 pins (D2 every branch, partial-update shape, tag guards) + `tests/integration/test_migration_0030.py` 6 pins (column contract, no-backfill, PK/NOT-NULL, A13 round-trip) pass. +- `uv run ruff check .` clean; `uv run pyright` clean; `tests/e2e/test_smoke.py` 3 passed; `alembic upgrade head`/`downgrade 0029`/re-upgrade clean. + +**Docs**: no doc impact (pure data layer — README/AGENTS updates are task 06's per the phase plan; AGENTS rule 16's schema-move convention remains accurate). + +**Decisions**: `normalize_tags` count-guard runs before the de-dupe (11 typed = rejected, documented); whitespace-tag strictness is left to the task-02 API boundary per the task text. + +**Next pending task**: `191_source_name_labels_tags/02_source_labels_api.md`. diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md.status b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.validate b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.validate new file mode 100644 index 0000000..98040ab --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__01_source_labels_table.a1.validate @@ -0,0 +1,147 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 20%] +........................................................................ [ 21%] +........................................................................ [ 23%] +........................................................................ [ 24%] +........................................................................ [ 26%] +........................................................................ [ 27%] +........................................................................ [ 29%] +........................................................................ [ 30%] +........................................................................ [ 32%] +........................................................................ [ 33%] +........................................................................ [ 35%] +........................................................................ [ 37%] +........................................................................ [ 38%] +........................................................................ [ 40%] +........................................................................ [ 41%] +........................................................................ [ 43%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 47%] +........................................................................ [ 49%] +........................................................................ [ 50%] +........................................................................ [ 52%] +........................................................................ [ 53%] +........................................................................ [ 55%] +........................................................................ [ 57%] +........................................................................ [ 58%] +........................................................................ [ 60%] +........................................................................ [ 61%] +........................................................................ [ 63%] +........................................................................ [ 64%] +........................................................................ [ 66%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 74%] +........................................................................ [ 75%] +........................................................................ [ 77%] +........................................................................ [ 78%] +........................................................................ [ 80%] +........................................................................ [ 81%] +........................................................................ [ 83%] +........................................................................ [ 84%] +........................................................................ [ 86%] +........................................................................ [ 87%] +........................................................................ [ 89%] +........................................................................ [ 91%] +........................................................................ [ 92%] +........................................................................ [ 94%] +........................................................................ [ 95%] +........................................................................ [ 97%] +........................................................................ [ 98%] +........................................................... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 292 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 325 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/memory.py 32 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 105 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 259 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 549 0 100% +-------------------------------------------------- +TOTAL 7035 16 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.err b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md new file mode 100644 index 0000000..da4f54e --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md @@ -0,0 +1,19 @@ +Everything is green. Final report: + +**Implemented (phase 191 task 02)** +- `app/schemas.py` — `SourceLabelOut` / `SourceLabelList` / `SourceLabelUpdate` (`extra="forbid"`, trim-*before*-cap validators, `_Tag` item cap = the house `_Chip` item-cap convention). +- `app/api/source_labels.py` (NEW) — admin-gated router: catalogue `GET` (`effective_sources` names via `resolve_source_name` — git + local + the env fallback — ∪ `SELECT DISTINCT documents.source`, de-duped, sorted, ONE `all_labels` read), `PUT` (404 arm first → `normalize_tags` `ValueError`→422 → `set_label` from `model_fields_set`: omitted keeps / `null` clears / value sets, router commits), `DELETE` (404 when no row; 200 body = the entry's cleared state). +- `app/main.py` — registered in the admin-router block; `scripts/api_payload_audit.py` — the new endpoint in the byte audit. +- `tests/integration/test_source_labels_api.py` (NEW, 26 tests): 403 gate for anonymous AND token users, the git+local+upload union (sorted, no dupes, env-only arm, exactly 3 SELECTs and no `documents.content` read), round trip, partial-update shape, every cap as the framework's 422 with the row byte-identical, both 404 arms, the `ValueError`→422 funnel, and the D1 "a rename writes nothing but the label row" arm. + +**Gates** — `uv run pytest` → **4693 passed**; `uv run pytest --cov=app --cov-report=term-missing` → TOTAL **99%**, `app/api/source_labels.py` **100%**, `app/schemas.py` **100%**; `uv run ruff check .` → clean; `uv run pyright` → **0 errors**; E2E sanity in isolation: `tests/e2e/test_smoke.py`, `tests/e2e/test_git_sources_admin.py` pass. + +**Docs** — README gains "Source names, labels and tags (phase 191)" (route table + the alias-only contract); AGENTS.md gains rule 17 (alias-never-identity, reuse `resolve_source_name`, 404/no-partial-write, the pin file). + +**Decisions / deviations** +- Router uses the house prefix split (`prefix="/source-labels"` + include `prefix="/api"`) — wire paths are exactly D5's. +- `DELETE` answers 200 with the cleared `SourceLabelOut` (the task's "200"; body mirrors phase-168 `DELETE /api/admin/settings/{key}` returning the reset item). +- A whitespace-only/empty tag is the framework's 422 (trim runs before `min_length`), as this task's pins require; `normalize_tags` keeps its drop-empties contract for helper callers, still owns the case-insensitive de-dupe, and its `ValueError`→422 belt is pinned by substituting a raising normalizer. +- The GET lists *sources* (registry ∪ indexed documents), not orphan label rows; `DELETE` never consults the registry, so an orphan row stays clearable (documented in the route docstring). + +**Next pending task:** `191_source_name_labels_tags/03_source_labels_ui.md`. diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md.status b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md.status new file mode 100644 index 0000000..9766475 --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.md.status @@ -0,0 +1 @@ +ok diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.validate b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.validate new file mode 100644 index 0000000..223afd8 --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__02_source_labels_api.a1.validate @@ -0,0 +1,149 @@ +........................................................................ [ 1%] +........................................................................ [ 3%] +........................................................................ [ 4%] +........................................................................ [ 6%] +........................................................................ [ 7%] +........................................................................ [ 9%] +........................................................................ [ 10%] +........................................................................ [ 12%] +........................................................................ [ 13%] +........................................................................ [ 15%] +........................................................................ [ 16%] +........................................................................ [ 18%] +........................................................................ [ 19%] +........................................................................ [ 21%] +........................................................................ [ 23%] +........................................................................ [ 24%] +........................................................................ [ 26%] +........................................................................ [ 27%] +........................................................................ [ 29%] +........................................................................ [ 30%] +........................................................................ [ 32%] +........................................................................ [ 33%] +........................................................................ [ 35%] +........................................................................ [ 36%] +........................................................................ [ 38%] +........................................................................ [ 39%] +........................................................................ [ 41%] +........................................................................ [ 42%] +........................................................................ [ 44%] +........................................................................ [ 46%] +........................................................................ [ 47%] +........................................................................ [ 49%] +........................................................................ [ 50%] +........................................................................ [ 52%] +........................................................................ [ 53%] +........................................................................ [ 55%] +........................................................................ [ 56%] +........................................................................ [ 58%] +........................................................................ [ 59%] +........................................................................ [ 61%] +........................................................................ [ 62%] +........................................................................ [ 64%] +........................................................................ [ 65%] +........................................................................ [ 67%] +........................................................................ [ 69%] +........................................................................ [ 70%] +........................................................................ [ 72%] +........................................................................ [ 73%] +........................................................................ [ 75%] +........................................................................ [ 76%] +........................................................................ [ 78%] +........................................................................ [ 79%] +........................................................................ [ 81%] +........................................................................ [ 82%] +........................................................................ [ 84%] +........................................................................ [ 85%] +........................................................................ [ 87%] +........................................................................ [ 88%] +........................................................................ [ 90%] +........................................................................ [ 92%] +........................................................................ [ 93%] +........................................................................ [ 95%] +........................................................................ [ 96%] +........................................................................ [ 98%] +........................................................................ [ 99%] +............. [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/admin_settings.py 114 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 292 1 99% +app/api/chat_images.py 52 0 100% +app/api/chats.py 111 0 100% +app/api/config.py 13 0 100% +app/api/doc_drafts.py 99 0 100% +app/api/docs.py 239 1 99% +app/api/git_sources.py 259 0 100% +app/api/health.py 10 0 100% +app/api/source_labels.py 52 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 33 0 100% +app/api/sync.py 231 0 100% +app/api/tokens.py 40 0 100% +app/api/ui_settings.py 39 0 100% +app/config.py 325 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 124 0 100% +app/core/compression.py 59 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 43 0 100% +app/core/errors.py 5 0 100% +app/core/http_cache.py 22 0 100% +app/core/logging.py 13 0 100% +app/core/memory.py 32 0 100% +app/core/rate_limit.py 44 0 100% +app/core/response_budget.py 63 0 100% +app/core/security_headers.py 20 0 100% +app/core/settings_catalog.py 18 0 100% +app/core/settings_migrate.py 32 0 100% +app/core/settings_overlay.py 117 0 100% +app/core/theming.py 45 0 100% +app/core/tokens.py 44 0 100% +app/db.py 22 0 100% +app/main.py 107 0 100% +app/models.py 148 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 494 1 99% +app/rag/archive_upload.py 134 0 100% +app/rag/chunker.py 220 4 98% +app/rag/doc_dates.py 18 0 100% +app/rag/folder_summaries.py 134 0 100% +app/rag/git_sources.py 77 0 100% +app/rag/importer.py 865 3 99% +app/rag/llm.py 253 1 99% +app/rag/md_images.py 63 0 100% +app/rag/overview.py 78 0 100% +app/rag/pdf.py 192 0 100% +app/rag/prompts.py 162 0 100% +app/rag/retriever.py 259 3 99% +app/rag/scaffolding.py 55 0 100% +app/rag/source_labels.py 87 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 58 0 100% +app/rag/svg_text.py 111 0 100% +app/rag/verbatim.py 160 0 100% +app/schemas.py 576 0 100% +-------------------------------------------------- +TOTAL 7116 16 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +WARNING: there is a new pyright version available (v1.1.411 -> v1.1.414). +Please install the new version or set PYRIGHT_PYTHON_FORCE_VERSION to `latest` + +validation OK diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.err b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.md b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.md new file mode 100644 index 0000000..e6cd9fc --- /dev/null +++ b/.agents/reports/191_source_name_labels_tags/191_source_name_labels_tags__03_source_labels_ui.a1.md @@ -0,0 +1,15 @@ +**Implemented (phase 191 task 03 — the per-source name/label/tags editor, D6)** +- `frontend/index.html`: new **Names, labels and tags** card inside the admin-gated `#git-sources-content` — bounded `.table-wrap` table (sticky header), `role="alert"` load-error line, empty state, and ONE shared `