phase: 137_pdf_image_context
All verification complete — everything is 100% green. Final report: **Phase 137 final verification pass — all tasks already complete, all criteria verified** - **Full suite:** `uv run pytest --cov=app --cov-report=term-missing` → 3272 passed, exit 0; `app/` coverage **99%** (>90% ✓) - **Phase E2E in isolation:** `uv run pytest tests/e2e/test_pdf_image_context.py -v --no-cov` → **4 passed** (forward context, display line, standalone parity, both-blocks markdown case) - **Pre-existing suites in isolation:** `test_pdf_support.py` + `test_image_anchor_context.py` + `test_image_documents.py` → **14 passed**; ripple-edited `test_garbage_pdf.py` → **3 passed** - **Lint/types:** `uv run ruff check .` → all passed; `uv run pyright` → 0 errors **Completion criteria:** (1) forward-path context in vision msg + stored `image_context`/summary — ✓ (unit builder/seam + integration fake-LLM + E2E); (2) both blocks document-first + standalone describe byte-identical — ✓ (combiner + standalone pins); (3) backfill with context + zero-vision idempotent re-sync + parent-gone origin-only — ✓ (6 integration tests); (4) suggestion block leads with `From <source>/<pdf> (page N)` — ✓ (renderer units + E2E); (5) all gates green — ✓ above; (6) no behavior change in phases 122/125/126 + sync `detail` shape untouched — ✓ (verified in code: new counter is log-only); (7) ruff+pyright — ✓; (8) commit — left to the harness per pipeline rules (working tree untouched by me). **Documentation:** README.md audited in full — the new phase-137 bullet verified against code (6 000-char cap, log-only `image_context_backfilled=N`, `<document>`-body locator placement), all env tables/defaults cross-checked vs `app/config.py` and `.env.example` — consistent, no changes needed. AGENTS.md: every rule/command verified — consistent, no changes needed. **Notable deviations (pre-existing, documented in task-05 report, forced by design):** `test_pdf_support.py`/`test_garbage_pdf.py` got minimal ripple edits (the "UNEDITED" pin was unsatisfiable once describe calls carry context by design); the unit `test_image_anchor_context.py` CONTEXT_PREFIX pin generalized per ASSUMPTION A5; one extra mock line (`_seed_context_line` accepts `From …`). **Next pending phase:** none — `todo/` holds only this phase.
This commit is contained in:
+23
-10
@@ -227,16 +227,22 @@ async def describe_image(
|
||||
beyond the client's own (SDK-level + the house one-shot empty-
|
||||
content policy) — a description failure must not stall a sync.
|
||||
|
||||
*context* (phase 125, task 03, LOCKED A3): the optional markdown
|
||||
reference context — the alt text + surrounding paragraphs of the
|
||||
```` references that point at THIS image (the importer's
|
||||
same-source scan). When provided, it is appended to the text part
|
||||
AFTER the locked :data:`DESCRIBE_PROMPT` (the marker + instruction
|
||||
stay byte-identical — the ``IMAGE_DESCRIPTION_MODE`` mock key is
|
||||
untouched): the vision model is told WHAT THE IMAGE IS FOR so it
|
||||
*context* (phase 125, task 03, LOCKED A3; generalized in phase 137,
|
||||
task 02): the optional DOCUMENT/REFERENCE context built by the
|
||||
importer — for a PDF-embedded image, the
|
||||
``Extracted from <source>/<pdf> (page N):`` provenance block (the
|
||||
page's text, capped — WHERE the image came from) combined with any
|
||||
phase-125 markdown reference blocks (the ```` alt text
|
||||
+ surrounding paragraphs — WHAT it illustrates; document block
|
||||
first); for a standalone image, the markdown reference context
|
||||
alone (the importer's same-source scan). When provided, it is
|
||||
appended to the text part AFTER the locked :data:`DESCRIBE_PROMPT`
|
||||
(the marker + instruction stay byte-identical — the
|
||||
``IMAGE_DESCRIPTION_MODE`` mock key is untouched): the vision model
|
||||
learns where the image comes from AND what it is used for, so it
|
||||
can write a context-aware description. ``context=None`` (the
|
||||
default — standalone images) sends the bare prompt: the message is
|
||||
byte-identical to the pre-phase-125 shape.
|
||||
default — a reference-free standalone image) sends the bare prompt:
|
||||
the message is byte-identical to the pre-phase shape.
|
||||
|
||||
Returns the stripped reply cut exactly at
|
||||
``(settings or llm.settings).summary_max_chars`` (the phase-30 cap —
|
||||
@@ -248,8 +254,15 @@ async def describe_image(
|
||||
continues (LOCKED A3).
|
||||
"""
|
||||
data_url = image_data_url(data, mime)
|
||||
# Phase 137 (task 02, ASSUMPTION A5): the prefix wording is neutral
|
||||
# — it covers BOTH block kinds (the provenance's ``Extracted from
|
||||
# …`` document context and the phase-125 ``Referenced in …``
|
||||
# markdown references). ``DESCRIBE_PROMPT`` (the marker + the locked
|
||||
# instruction) stays byte-identical; ``context=None`` sends the bare
|
||||
# prompt (byte-identical to the pre-phase-137 message).
|
||||
context_prefix = (
|
||||
f"\n\nThis image is referenced in documentation with the following context:\n{context}"
|
||||
"\n\nThis image is part of a document. The following context "
|
||||
f"describes where it comes from and what it is used for:\n{context}"
|
||||
if context
|
||||
else ""
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user