chore(agent): track .agent/ planning tree in git
Build and Push Containers / build-and-push-app (push) Successful in 12s
Build and Push Containers / build-and-push-db (push) Successful in 10s

Remove the blanket .agent/ gitignore so the phase roadmap, user
stories, reports, and PLAN.md are versioned with the code. Only
runtime artifacts (.agent/phase-sessions/, .agent/pipeline.log)
remain ignored. Update AGENTS.md git protocol rule to match.
This commit is contained in:
2026-09-01 10:18:22 -04:00
parent 5fa620fde5
commit 4971e2859d
818 changed files with 23964 additions and 4 deletions
@@ -0,0 +1,11 @@
**Phase 53 — final verification pass: all green. No code changes needed.**
- Verified all 6 tasks complete (`complete/53_stale_saved_chats/` full); implementation confirmed in `app/rag/sources_meta.py`, migration 0010, `app/api/sync.py`, `scripts/import_docs.py`, `app/api/chats.py`, `index.html` banner, `history.js` Stale cell.
- `uv run pytest --cov=app` → 1047 passed, exit 0; **TOTAL coverage 99% (>90%)**.
- `uv run pytest tests/e2e/test_stale_saved_chats.py --no-cov` → 3 passed in isolation (full invalidation loop, no-brain text-only banner, anonymous shared snapshot).
- Regression E2E in isolation, all green: `test_chat_history` 5, `test_share_chat` 4, `test_sync_button` 3, `test_retry_answer` 4, `test_chat_persistence` 4.
- `uv run ruff check . && uv run pyright` → clean (0 errors).
- Criteria: bump-once/unchanged/`--limit`/failed-never-bump ✅ (test_sync_api + test_import_docs_* pins); stamp-on-save + server-side `stale` + share/unshare immunity ✅ (test_chats_api); History Stale pill, `width:100%` table intact ✅; banner → Regenerate → re-save → fresh ✅; `/shared/<token>` has no staleness surface ✅.
- Commit: `32b7bfd` (exact spec message, no GPG sig, only phase-53 code commit). Added `9518d9d` recording the harness's task-06 move as a pure rename (house pattern from phase 52); working tree clean.
- Dev DB left at migration 0010 with truncated KB — the established post-E2E state (git_sources empty; app functional, E2E suites ran against it green).
- Phase dir move to `complete/` left to the harness. Next pending phase: `55_save_share_ux`.
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 61%]
........................................................................ [ 68%]
........................................................................ [ 75%]
........................................................................ [ 82%]
........................................................................ [ 89%]
........................................................................ [ 96%]
....................................... [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 89 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 167 0 100%
-----------------------------------------------
TOTAL 2217 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,17 @@
Task 01 complete. Report:
**Implemented**
- `app/models.py`: `SourcesMeta` single-row counter (id=1 PK default, `version` INT NOT NULL default 0, `updated_at` timestamptz with `onupdate`) + `SavedChat.sources_version` (INT NOT NULL default 0, pre-counter KB = 0 per docstring)
- `alembic/versions/0010_sources_version.py`: one migration — `sources_meta` table + seed row (1, 0) + `saved_chats.sources_version`; downgrade reverses (drop column, then table)
- `app/rag/sources_meta.py`: `current_sources_version` (PK read, 0 when absent, never raises) + `bump_sources_version` (upsert, `+=1`, flush only — caller commits)
- `tests/integration/test_migration_0010.py` (4 tests, house 0009 pattern) + `tests/unit/test_sources_meta.py` (6 tests, seeded-row reset fixture)
**Results**
- `uv run alembic upgrade head` → 0009→0010 clean on the at-0009 dev DB; seed row verified `(1, 0)`
- `uv run pytest tests/integration/test_migration_0010.py tests/unit/test_sources_meta.py -v` → 10 passed
- `uv run pytest` → 1029 passed (exit 0); `--cov=app` TOTAL 99% (>90%)
- `uv run ruff check . && uv run pyright` → All checks passed / 0 errors
**Decisions** — no deviations; `bump` also upserts a deleted seed row (defensive, tested); dev DB left at head with the row reset to seed state.
**Next pending task:** `.agent/phases/todo/53_stale_saved_chats/02_sync_version_bump.md`
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 62%]
........................................................................ [ 69%]
........................................................................ [ 76%]
........................................................................ [ 83%]
........................................................................ [ 90%]
........................................................................ [ 97%]
..................... [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 105 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 81 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 165 0 100%
-----------------------------------------------
TOTAL 2202 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,15 @@
**Task 02 complete — version bump on both KB-changing sync paths**
- `app/api/sync.py`: `_run_sync` bumps `sources_meta.version` exactly once (short-lived `SessionLocal`, commit) when `added + updated + pruned > 0`; `sources_version` always lands in the success `detail`; any pre-bump failure → `failed` state, never bumps
- `scripts/import_docs.py`: same gate in `_run`; `--limit` and unchanged re-runs never bump; summary print gains `sources_version=<n|skipped>`; bump commits in its own session, independent of the best-effort overview
- Tests: `test_sync_api.py` (changed→bump once + detail; unchanged & git-failure & model-down → no bump; counter pinned to 0 via autouse fixture); `test_import_docs_overview.py` (all 5 existing tests extended with the new print tail + version asserts; new prune-only-bump test pinning the broader gate); `test_import_docs_git.py` (bump stubbed per no-real-DB style, single-bump + token asserted)
Results:
- `uv run pytest` → **1030 passed** (unit + integration)
- `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99%** (sync.py 100%, sources_meta.py 100%)
- `uv run ruff check . && uv run pyright` → clean (fixed one import-sort)
- `uv run pytest tests/e2e/test_sync_button.py -v --no-cov` → **3 passed** in isolation; dev DB restored to seed state after
Decisions: sync `detail` carries `sources_version` even on unchanged runs (current generation — stable, never-stale shape); CLI prints literal `skipped` per task spec; no commit (phase commits at task 06).
Next pending task: `.agent/phases/todo/53_stale_saved_chats/03_chats_api_staleness.md`
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 62%]
........................................................................ [ 69%]
........................................................................ [ 76%]
........................................................................ [ 83%]
........................................................................ [ 90%]
........................................................................ [ 97%]
...................... [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 105 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 89 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 165 0 100%
-----------------------------------------------
TOTAL 2210 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,16 @@
Task 03 complete — all gates green.
**Implemented**
- `app/schemas.py`: required `stale: bool` on `SavedChatRow` + `SavedChatOut` (no default — the API must always compute it); `SharedChatOut` untouched (frozen public snapshot).
- `app/api/chats.py`: `create_chat` stamps `sources_version` on the PENDING row (rides the same INSERT, the `share_token` precedent); `update_chat` re-stamps to the current generation unconditionally (Re-Save = affirmation, the false-positive escape hatch); `list_chats`/`get_chat` read `current_sources_version(db)` ONCE per request and compute `stale = row.sources_version < current` in the now-pure `_to_row(row, current_version)` / `_to_out(row, current_version)`; share/unshare unchanged (raw SQL on `share_token` only).
- `tests/integration/test_chats_api.py`: 6 new tests (create stamping, pre-counter row stale on first bump, stale in list+detail after bump, Re-Save re-stamp clears stale, share/unshare version immunity, shared-snapshot has no stale surface) + autouse `seeded_sources_meta` fixture + raw-SQL stamp reader (bypasses the session identity map); `OUT_KEYS`/`ROW_KEYS` extended with `stale`.
**Results**
- `uv run pytest tests/integration/test_chats_api.py -v --no-cov` → 49 passed
- `uv run pytest --cov=app --cov-report=term-missing` → 1036 passed, TOTAL **99%** (>90%; `chats.py`/`schemas.py` 100%)
- `uv run ruff check .` → clean; `uv run pyright` → 0 errors
- Regression insurance: `uv run pytest tests/e2e/test_chat_history.py -v --no-cov` → 5 passed; `tests/e2e/test_share_chat.py` → 4 passed
**Decisions**: `stale` made a required field (no default) so a future route can't ship the shape without the flag. No commit — the atomic phase commit belongs to task 06 per AGENTS.md rule 8.
**Next pending task**: `.agent/phases/todo/53_stale_saved_chats/04_history_stale_badge.md`
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 62%]
........................................................................ [ 69%]
........................................................................ [ 76%]
........................................................................ [ 83%]
........................................................................ [ 90%]
........................................................................ [ 97%]
............................ [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 89 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 167 0 100%
-----------------------------------------------
TOTAL 2217 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,18 @@
All green. Task 04 complete.
**Implemented**
- `frontend/history.html`: `Stale` `<th>` added between Updated and Share (i.e. between Updated and Actions); empty-row `colspan` 5→6
- `frontend/assets/history.js`: `makeRow` renders the Stale cell from `row.stale` (server-computed) — rose `Stale` pill with the exact Regenerate hover copy, em-dash when fresh; `<td>` gets its own `aria-label` in **both** states (WCAG 2.1 AA); READ-ONLY badge, no per-row control
- `frontend/assets/styles.css`: `.stale-pill` in the rose/Stop-treatment tokens (`--err-bg/--err-ink/--err-line`, theme-token based, err-ink on err-bg ≈9.3:1, ≈9.9:1 on `--surface`) + `.history-stale-cell` (nowrap, ink-soft em-dash)
- `tests/unit/test_history_page.py`: new pins (JS stale branch — pill class/em-dash/aria-label/exact title/READ-ONLY; `Stale` `<th>` + column order + `colspan="6"`; `.stale-pill` rose-family CSS) and updated the two existing skeleton/row-order pins to the six-column shape
**Verification**
- `uv run pytest` → 1038 passed
- `uv run pytest --cov=app --col-report=term-missing` → TOTAL **99%** (>90%)
- `uv run ruff check . && uv run pyright` → clean (0 errors)
- Regression E2E (isolation): `test_chat_history.py` 5 passed, `test_share_chat.py` 4 passed
- Node ESM syntax check on `history.js` OK
**Decisions**: Stale column placed immediately after Updated (metadata grouping; Share/Actions stay contiguous at the right edge) — still "between Updated and Actions" per the task, phase-51 Share contract intact. No commit made — the phase's single commit belongs to task 06; tasks 01–04 changes ride together in the working tree.
**Next pending task**: `.agent/phases/todo/53_stale_saved_chats/05_stale_banner_and_regenerate.md`
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 62%]
........................................................................ [ 69%]
........................................................................ [ 76%]
........................................................................ [ 83%]
........................................................................ [ 90%]
........................................................................ [ 97%]
.............................. [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 89 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 167 0 100%
-----------------------------------------------
TOTAL 2217 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,13 @@
All verification is complete. Final report:
**Phase 53 Task 05 — Stale banner + Regenerate on the chat page: complete.**
- `frontend/index.html`: `#stale-banner` section directly after `#kb-banner` (`role="status"`, ships hidden) — exact text + `#stale-regenerate` "Regenerate" pill (Save/Share brand-pill family, phase-49 redo glyph).
- `frontend/assets/app.js`: `retryLastTurn` now returns the `runTurn` promise (Retry click ignores it — behavior-neutral); `?chat=<id>` boot load reveals the banner on `payload.stale === true`; no-brain-record guard removes the button (text-only); new `regenerateStaleChat` handler: `retryLastTurn(lastBrainWrap)` → await → error-banner check → linked `PUT /api/chats/<id>` (404 → unlink + recreate) → banner hidden + `#send-status` announce; banner also clears on New chat / successful re-Save.
- `frontend/assets/styles.css`: `.stale-banner` rides the `.kb-banner` family (distinct redo glyph), `.stale-regenerate` is the exact Save/Share pill (theme tokens, 5.2:1/9.5:1 AA); ≤640px the pill takes a full-width row; stacks below `#kb-banner`.
- `tests/unit/test_save_chat_ui.py`: 8 new pins — banner HTML/position, `payload.stale` reveal branch, no-brain guard, return-promise change, Regenerate→`retryLastTurn` wiring, linked PUT + 404 recreate, binding, never-stale clears, CSS family.
- Tests: `uv run pytest --cov=app` → **1047 passed**, coverage **99%** (>90% gate); `uv run ruff check . && uv run pyright` → clean; `node --check` OK.
- E2E (isolated): `test_retry_answer.py` 4/4, `test_chat_history.py` 5/5, `test_sync_button.py` 3/3, `test_chat_persistence`/`test_share_chat`/`test_stop_generation` all pass — no regressions (two `test_sync_button` failures only occur when suites run back-to-back in one process; green in isolation per protocol).
- Live sanity (temp Playwright run, since deleted): save → modify KB + bump → open `/?chat=` → banner → Regenerate streams the **fresh** answer (sentinel from new docs) in place → row re-stamped `stale: false` → banner clears; user-only row shows text-only banner; deleted-row recreate works.
- Deviations: none; added banner-clear on New chat / re-Save as never-stale hygiene (pinned in unit tests).
- Next pending task: `53_stale_saved_chats/06_e2e_stale_saved_chats.md` (story Playwright suite + regressions + phase commit).
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 61%]
........................................................................ [ 68%]
........................................................................ [ 75%]
........................................................................ [ 82%]
........................................................................ [ 89%]
........................................................................ [ 96%]
....................................... [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 89 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 167 0 100%
-----------------------------------------------
TOTAL 2217 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK
@@ -0,0 +1,18 @@
**Phase 53, Task 06 complete** — the invalidation-loop E2E story suite, all regressions, and the atomic commit.
**Implemented**
- `tests/e2e/test_stale_saved_chats.py` (3 tests, isolated Playwright suite):
- `test_full_invalidation_loop` — Save → `stale: false` (API + DB stamp) → fresh open shows no banner → `bump_sources_version` (test-only stand-in for a KB-changing sync, per the task ASSUMPTION) → History Stale pill + `stale: true` (list + detail) → open `/?chat=<id>` via the table link → `#stale-banner` + Regenerate → phase-49 redo-in-place (old wrap provably removed via `data-retry-marker`, no question duplication) → auto re-save → banner clears, `stale: false`, fresh last brain message, re-stamped DB row, History pill gone.
- `test_stale_chat_without_brain_answer_is_text_only` — user-only stale row: banner text only, Regenerate button removed, no JS errors.
- `test_anonymous_shared_snapshot_has_no_staleness_surface` — stale→Regenerate→fresh, History "Create link", fresh anonymous context: snapshot renders with zero phase-53 elements/strings; public `GET /api/shared/<token>` wire carries exactly `{title, messages}`.
**Results**
- `uv run pytest tests/e2e/test_stale_saved_chats.py -v --no-cov` → 3 passed (in isolation, DB up)
- Regressions in isolation: `test_chat_history` 5 passed, `test_share_chat` 4 passed, `test_sync_button` 3 passed, `test_retry_answer` 4 passed, `test_chat_persistence` 4 passed
- `uv run pytest --cov=app --cov-report=term-missing` → 1047 passed, TOTAL 99% (>90%)
- `uv run ruff check . && uv run pyright` → clean
- Commit `32b7bfd` `feat(chat): invalidate saved chats on sources sync — …` (26 files, `--no-gpg-sign`); working tree clean
**Notes:** One fix during dev — the anonymous "no staleness surface" text check originally matched my own distinctive question marker `(stale-share)` quoted by the deterministic mock; narrowed to the phase-53 UI strings + element selectors + wire-shape pin. Per harness protocol I left `todo/53_stale_saved_chats/{00_phase.md,06_…}` in place for the harness to move.
**Next pending task:** `54_asset_cache_bust_revalidation/01_page_paths_ignore_conditional_headers.md`
@@ -0,0 +1,67 @@
........................................................................ [ 6%]
........................................................................ [ 13%]
........................................................................ [ 20%]
........................................................................ [ 27%]
........................................................................ [ 34%]
........................................................................ [ 41%]
........................................................................ [ 48%]
........................................................................ [ 55%]
........................................................................ [ 61%]
........................................................................ [ 68%]
........................................................................ [ 75%]
........................................................................ [ 82%]
........................................................................ [ 89%]
........................................................................ [ 96%]
....................................... [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/auth.py 22 0 100%
app/api/chat.py 131 0 100%
app/api/chats.py 110 0 100%
app/api/config.py 7 0 100%
app/api/docs.py 23 0 100%
app/api/git_sources.py 143 0 100%
app/api/health.py 10 0 100%
app/api/steering.py 42 0 100%
app/api/suggestions.py 8 0 100%
app/api/sync.py 89 0 100%
app/config.py 79 0 100%
app/core/__init__.py 0 0 100%
app/core/auth.py 20 0 100%
app/core/caching.py 93 0 100%
app/core/debugging.py 29 2 93%
app/core/logging.py 13 0 100%
app/db.py 21 0 100%
app/main.py 50 0 100%
app/models.py 74 0 100%
app/rag/__init__.py 0 0 100%
app/rag/agent.py 78 0 100%
app/rag/archive_upload.py 128 0 100%
app/rag/chunker.py 206 4 98%
app/rag/git_sources.py 14 0 100%
app/rag/importer.py 173 3 98%
app/rag/llm.py 189 0 100%
app/rag/overview.py 71 0 100%
app/rag/prompts.py 65 0 100%
app/rag/retriever.py 94 3 97%
app/rag/sources_meta.py 16 0 100%
app/rag/suggestions.py 27 0 100%
app/rag/summarizer.py 24 0 100%
app/schemas.py 167 0 100%
-----------------------------------------------
TOTAL 2217 12 99%
coverage gate: app/ 99% (>90%) OK
All checks passed!
0 errors, 0 warnings, 0 informations
validation OK