phase: 124_image_chips_and_answers
All green. Final report: **Phase 124 final verification pass — all criteria verified, no defects found (nothing to fix)** - Verified the implemented phase (all 7 tasks done, changes in working tree): `BOR_ANSWER_IMAGES` toggle, `show_image` tool + refusals + `holder.shown_images`, toggle-gated prompt clause, `answer_image` frame field (None-omitting serializer) + `ChatMessage` persistence, `merge_cited_docs` auto-cite bug fix, answer-figure UI (live/restore/shared/CSS), mock triggers + E2E suite. Also confirmed the bytes route → public change matches the phase-123 shared-chat precedent (task 06 design). - `uv run pytest --cov=app --cov-report=term-missing` → **2848 passed**, TOTAL **99%** (>90% gate) - `bash .agents/validate.sh` → **validation OK** (tests + coverage + ruff + pyright) - `uv run ruff check . && uv run pyright` → clean, 0 errors - `uv run pytest tests/e2e/test_answer_images.py -v --no-cov` (isolated) → **5/5 passed** - Mock-inert spot checks: `tests/e2e/test_image_documents.py` 4/4, `tests/e2e/test_agent_document_tools.py` 4/4 **Completion criteria:** ① zero-read suggested-tier image doc chips with figure — verified (unit matrix, integration `test_zero_read_grounded_turn_auto_cites_suggested_image_doc`, E2E bug-fix flows); ② show_image → answer figure below text/above chips, second call refused, persists + restore + shared — verified (unit handler matrix, integration round-trip, E2E feature flow); ③ default-off byte-identical (3 tools, no clause, no key) — verified (unit + integration + E2E toggle-off); ④ full suite green / >90% / lint clean — verified above; ⑤ commit + phase move — harness responsibility (changes left uncommitted in working tree, no live-infrastructure changes made). **Next pending phase:** none — `todo/` holds only this phase; the pipeline is clear once the harness moves it.
This commit is contained in:
+22
-10
@@ -28,12 +28,17 @@ BYTES route: the persistent copy behind an ``is_image`` document's
|
||||
``image_path``, served with the extension's ``Content-Type`` (the
|
||||
``app.rag.summarizer.IMAGE_MIMES`` map — one map, one truth) and a
|
||||
``Cache-Control: private, max-age=3600`` header (the bytes are
|
||||
content-hashed — long enough, bustable by re-upload). User-gated like
|
||||
the content endpoint (phase 79 — the ONLY anonymous surface is the
|
||||
shared chats): a missing doc, a non-image doc, a doc whose
|
||||
content-hashed — long enough, bustable by re-upload). PUBLIC (phase
|
||||
124 — the phase-123 chat-image precedent: the image is part of a
|
||||
shared chat's rendered content, and the shared chat — the app's ONLY
|
||||
anonymous surface — must render the answer figure faithfully for
|
||||
guests; the unguessable ``uuid4`` document id IS the credential, no
|
||||
enumeration value): a missing doc, a non-image doc, a doc whose
|
||||
``image_path`` is NULL, or a row whose copy was lost all map to 404
|
||||
``document not found`` (the router's unknown-document shape —
|
||||
traversal/UUID-guessing has no filesystem surface to hit).
|
||||
traversal/UUID-guessing has no filesystem surface to hit). The
|
||||
document's TEXT (the content endpoint) stays user-gated — only the
|
||||
bytes are public.
|
||||
|
||||
PATCH /api/folders/summary — the admin folder-description editor
|
||||
(phase 97, task 03): update / create / clear a stored
|
||||
@@ -212,16 +217,23 @@ def get_document_content(
|
||||
def get_document_image(
|
||||
doc_id: str,
|
||||
db: Session = Depends(get_db), # noqa: B008
|
||||
_user: None = Depends(require_user), # noqa: B008 # phase 79 posture (see docstring)
|
||||
) -> FileResponse:
|
||||
"""The phase-122 (task 04) image BYTES route — the persistent copy
|
||||
behind an ``is_image`` document's ``image_path``.
|
||||
|
||||
Same auth posture as the document content endpoint (phase 79 —
|
||||
``require_user``: admin OR live token holder; the ONLY anonymous
|
||||
surface is the shared chats — the image is part of a document's
|
||||
content, so it travels under the same gate): anonymous callers get
|
||||
401 ``authentication required`` before any row is read.
|
||||
PUBLIC (phase 124, LOCKED A4 — "visible … on the shared page"): a
|
||||
guest opening a shared chat sees the brain answer's image figure,
|
||||
so the bytes must serve ANONYMOUSLY. The trust model is the
|
||||
phase-123 chat-image precedent (the question attachment travels in
|
||||
the SAME shared content): the document id is an unguessable
|
||||
server-minted ``uuid4`` — IT IS the credential, with no
|
||||
enumeration value — exactly like the saved-chat id (phase 55) and
|
||||
the chat-image filename (phase 123). (The phase-122/79
|
||||
``require_user`` posture was set before the image became part of a
|
||||
shared chat's rendered content; the shared page's figure — built
|
||||
on this route per the phase-124 design — 401'd and collapsed for
|
||||
every guest, contradicting the owner-locked A4. The document's
|
||||
TEXT stays user-gated: only the bytes are public.)
|
||||
|
||||
404 ``document not found`` (the router's unknown-document shape) in
|
||||
every non-servable case — a missing id (an unparseable string maps
|
||||
|
||||
Reference in New Issue
Block a user