**Phase 166 — final verification pass: green.** All 3 task files already in `complete/`, so this was verification + defect/doc fixing.
- **Verified:** `.msg .bubble:empty { display: none; }` exists once in the Messages block with provenance; `frontend/` diff is styles.css only (**no app.js change**); `tests/unit/test_no_empty_answer_bubble.py` 26 pins pass; phase-158/161 anchor pins (thinking_timeline + tool_states + edit_message) **75 passed**.
- **Phase E2E in isolation:** `uv run pytest tests/e2e/test_no_empty_box.py --no-cov` → **5 passed**. Mutation check (rule removed) → 2 failures, so the suite genuinely pins the defect.
- **Regression set, isolated:** thinking_timeline 6 · turn_progress_loader 3 · chat_history 5 · share_chat 4 · save_share_ux 5 · failed_turn_retry 4 · chat_answer_clusters 4 · chat_error_honesty 4 → all pass.
- **Full gates:** `uv run pytest --cov=app --cov-report=term-missing` → **3880 passed, app/ 99%** (gate >90%); `uv run ruff check .` → clean; `uv run pyright` → **0 errors**.
- **Whole E2E tree swept file-by-file (150 files, own pytest process each).** 4 suites were broken by *earlier* phases; fixed and re-run green:
- `test_kb_tree`, `test_sync_summary_visibility`, `test_folder_summary_voice` — `td:nth-child(4) span` became a strict-mode violation when phase 156 wrapped the Edit label in `.cell-clip` → scoped to `span.kb-desc-text`.
- `test_search_tool_scope` — pinned the pre-`690fd98` per-run `<summary>`/`open` shape → re-pinned to the ONE `details.reasoning` container + `.tool-calls-summary`.
- `test_header_consistency` — `.doc-meta` pixel bound (`<34px`) was broken by phase 153's 44px touch-target floor at ≤640px → replaced with a shape-first single-line check that still fails a real wrap.
- **Completion criteria:** mid-turn box hidden ✅ · bubble appears at first delta, phase-130 rows below unchanged ✅ · restored/shared empty answer paints no box ✅ · no app.js change + anchors + full gates ✅ · commit/`complete/` move = harness's job (I ran no git index/history commands).
- **Docs:** README — added the phase-166 "no empty answer box mid-turn" note; fixed a **stale** Thinking lead ("collapsible Thinking blocks", pre-dated the 2026-10-06 one-disclosure refinement); QA section now states E2E isolation is mandatory (shared Postgres + fixed ports 8123/8901) with the per-file sweep loop. AGENTS.md — rule 5 UI checklist now names the phase-166 suppression rule.
- **Notable:** running all of `tests/e2e/` in one pytest session is not supported (fixture/port interleaving causes ~126 spurious failures) — documented in README. Restored the tracked `.agents/screenshots/doc_modal_scrollbar_1280.png` that `test_document_viewer.py` rewrites on every run.
- **Next pending phase:** `167_api_payload_diet`.
70 lines
4.2 KiB
Markdown
70 lines
4.2 KiB
Markdown
# AGENTS.md — Operating Rules for All Agents on This Repo
|
|
|
|
1. **Always read `.agents/PLAN.md` first.** It contains the architecture, the
|
|
LOCKED DECISIONS, the UI/UX standards, the data model, and the roadmap.
|
|
Do not design anything that contradicts it.
|
|
2. **Follow the phased execution protocol in `.agents/phases/`.** Work through
|
|
`.agents/phases/todo/` in numeric order. When a phase is complete, move its
|
|
directory to `.agents/phases/complete/`.
|
|
3. **Strictly adhere to the LOCKED DECISIONS** (PLAN §2). If you believe a
|
|
LOCKED decision is wrong, stop and flag it — do not silently deviate.
|
|
4. **"One Story, One Phase":** each user story in `.agents/user_stories/`
|
|
corresponds to a distinct execution phase, and **every** phase — story-driven
|
|
or owner-directed — includes its own dedicated Playwright E2E test suite
|
|
(one test file for the phase, run in isolation).
|
|
5. **"UI Structure Check":** before finalizing any UI component, verify that
|
|
it follows the layout principles in `.agents/PLAN.md` §7 (proper container
|
|
usage, the 72rem centered reading column — every page rides the 72rem
|
|
container at every viewport; phase 100 supersedes §7.1's 46rem chat
|
|
column, full-width tables on Sources — no skinny wasted-space lists;
|
|
the catalogue tables (RAG, Sources, History) are bounded scroll
|
|
panels — `max-height: min(70vh, 64rem)` — with a sticky header row;
|
|
a clipped action label shows an ellipsis hint (`.cell-clip`) with
|
|
the full text kept reachable via the control's aria-label
|
|
(phase 156); an in-flight turn never paints an empty answer
|
|
bubble — the box is created empty as the reasoning anchor and
|
|
`.msg .bubble:empty { display: none }` hides it until the first
|
|
answer token (phase 166); the document viewer's page strip is CLASS-scoped —
|
|
the primary class shows the strip in place of the text, the
|
|
additive class never hides the text: Text/Pages toggle group
|
|
(`aria-pressed`, Text default) with the strip behind it
|
|
(phase 163)) and
|
|
meets WCAG 2.1 AA basics (semantic
|
|
landmarks, labels, contrast ≥4.5:1, focus-visible, aria-live for the
|
|
stream).
|
|
6. **"No CDN Rule":** all CSS, JS, fonts, and images must be served statically
|
|
from within the FastAPI application. No `<script src="https://…">` or
|
|
`<link href="https://…">` tags in HTML templates unless bundled locally.
|
|
An integration test enforces this on the index page.
|
|
7. **"Debugpy Check":** any new entrypoint must keep the conditional import —
|
|
`debugpy` is imported **only** when `DEBUGPY=1` (see
|
|
`app/core/debugging.py`); default off, never imported otherwise.
|
|
8. **Git protocol:** Git is mandatory. One **atomic, professional commit per
|
|
completed phase** (Conventional Commits, e.g. `feat(rag): stream RAG
|
|
answers over SSE with source citations`). Always append `--no-gpg-sign`
|
|
(the repo also sets `commit.gpgsign=false`). `.agents/` is **tracked and
|
|
committed** with the phase — only runtime artifacts (`.agents/phase-sessions/`,
|
|
`.agents/pipeline.log`) are gitignored.
|
|
9. **Test gates are non-negotiable:** a phase is complete only when unit +
|
|
integration tests pass, `app/` coverage is **>90%**
|
|
(`uv run pytest --cov=app --cov-report=term-missing`), and the phase's
|
|
Playwright E2E file passes **in isolation**
|
|
(`uv run pytest tests/e2e/test_<story>.py -v --no-cov`).
|
|
10. **Amply log, visibly feed back:** server-side, log the required
|
|
per-turn line (PLAN §9); UI-side, honor the "never stale" feedback
|
|
contract (PLAN §7.4).
|
|
|
|
## Quick reference
|
|
```bash
|
|
podman compose up -d db # start Postgres 17 + pgvector
|
|
cp .env.example .env # once; then edit
|
|
uv run alembic upgrade head # apply migrations
|
|
uv run uvicorn app.main:app --reload # dev server (add DEBUGPY=1 to debug)
|
|
uv run pytest # unit + integration
|
|
uv run pytest --cov=app --cov-report=term-missing
|
|
uv run playwright install chromium # once
|
|
uv run pytest tests/e2e/test_smoke.py -v --no-cov
|
|
uv run ruff check . && uv run pyright # lint + types
|
|
uv run python -m scripts.eval_retrieval --from-file tests/fixtures/retrieval_battery.txt # retrieval regression battery (phases 119/162)
|
|
```
|