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.
4.7 KiB
Phase 57 — Edit + Re-embed Document Summaries
Source: TODO.md L4 — "Be able to edit the summaries for documents in the RAG. Click an edit button in summary box and change the summary that the AI created. re-embed that document after changing the summary."
Story: n/a (TODO-derived — owner roadmap confirmation 2026-08-31)
Context: The summary box is the .doc-summary section rendered by the shared core in frontend/assets/document.js (page + modal surfaces) — it renders only when doc.summary is non-empty, as a labeled h2 + text-node <p> (XSS contract: textContent only). Phase 30 stores a non-markdown document's lite digest on documents.summary and indexes it as one extra embedded chunk (is_summary=True, position −1 — app/rag/importer.py:313–336). The document viewer is deliberately PUBLIC (phase 16 owner decision — only the catalog is admin-gated), so the new edit affordance and endpoint must be admin-gated (require_admin, app/core/auth.py); GET /api/whoami (app/api/auth.py:56) already drives admin reveals on static pages. Async endpoints exist in app/api/ (app/api/chat.py:223, app/api/git_sources.py:231), so the re-embed (await llm.embed([...])) fits a standard async def handler.
Objective
An admin can edit (or clear) the AI-generated summary directly in the summary box; on save the stored summary and its is_summary chunk are updated and the chunk is re-embedded — anonymous visitors see the unchanged public viewer with no edit affordance.
Dependencies
56_import_extensions_env(todo, preceding)
Tasks
01_update_summary_api.md—PATCH /api/documents/summary(admin): update/cleardocuments.summary, replace theis_summarychunk, re-embed it (oneembedcall, DB untouched if the LLM fails).02_summary_edit_ui.md— Edit button in the.doc-summarypanel (admin-only) → inline textarea + Save/Cancel → live-region status on both viewer surfaces.03_e2e_edit_summaries.md— story Playwright suite + regressions + the atomic commit.
Testing & Quality
- Integration: the existing document-content API tests (phase 10) gain the PATCH cases — update + re-embed (chunk content + non-NULL vector + unchanged chunk count), clear (summary NULL + chunk deleted), markdown doc with no prior
is_summarychunk (one created), 404 unknown pair, 403 anonymous, LLM-failure error mapping (502/503, DB unchanged). - Frontend source pins (house style,
tests/unit/test_save_chat_ui.pypattern):document.js(whoami gate, editor wiring, PATCH path,textContentrender contract),styles.css(new.doc-summary-*classes). - E2E (mandatory, A16):
tests/e2e/test_edit_summaries.py, run in isolation (mockSUMMARY_MODEfixture KB). - Coverage: >90% on
app/(validate.sh gate).
Completion Criteria
- Admin:
PATCH /api/documents/summarywith new text updatesdocuments.summary, replaces theis_summarychunk's content, and stores a fresh embedding (content chunks untouched — count unchanged). - Admin: PATCH with an empty/whitespace summary clears
documents.summary(NULL) and deletes theis_summarychunk. - Anonymous: 403 on PATCH; no Edit button in the viewer; the viewer otherwise renders byte-for-byte as today.
- The Edit button appears in the summary box (document page and modal), opens a textarea prefilled with the current summary, and Save reflects the change in the panel with a live-region confirmation; Cancel restores.
uv run pytestgreen; coverage TOTAL >90%.uv run pytest tests/e2e/test_edit_summaries.py -v --no-covgreen in isolation (DB up).- Regression E2E suites green in isolation:
test_document_summaries.py,test_document_viewer.py,test_cache_busting.py. uv run ruff check . && uv run pyrightclean.- One
--no-gpg-signcommit; phase dir moved to.agent/phases/complete/(.agent/stays untracked — owner instruction, commit281f355).
Locked decisions
- Owner-locked (2026-08-31, roadmap confirmation, D4):
- Summary editing is admin-only (endpoint + UI affordance). The document viewer stays public.
- "Re-embed that document" = replace the
is_summarychunk with a fresh embedding (oneembedcall). The document's content chunks are not re-embedded — the summary is the only text that changed. - Clearing the summary (empty save) sets
documents.summary = NULLand deletes theis_summarychunk.
- Fail-before-write: the embedding happens before any DB mutation; an LLM failure returns an error (502/503,
app/api/git_sources.pyModelUnavailableError-style mapping) and leaves the row and chunk untouched.
Commit
git add app/ frontend/ tests/ && git commit --no-gpg-sign -m "feat(kb): edit + re-embed document summaries from the viewer (admin)"