phase: 125_image_anchor_context
Build and Push Containers / build-and-push-app (push) Successful in 2m8s
Build and Push Containers / build-and-push-db (push) Failing after 1m38s

All completion criteria verified. The repository is left functional with all changes in the working tree (no commits made, per the harness protocol).

## Final report — phase 125 `image_anchor_context` (verification pass)

All 6 tasks were already complete; this pass verified every criterion and ran the full gates:

- **Migration 0023** `documents.image_context` (TEXT nullable, reversible) — applied (`alembic current` = 0023 head); round-trip test (4 passed) exercises real upgrade → downgrade 0022 → upgrade.
- **Criterion 1** (referenced image enriched + context line in retrieval): integration `test_markdown_referenced_image_gets_context_and_enriched_chunks` + E2E `test_sync_enriches_the_image_doc_with_markdown_context`, `test_chat_answer_quotes_the_context_line` (wire prompt pinned: `<document>` block leads with the one-line `Referenced in …: "alt"` line) — verified present and passing.
- **Criterion 2** (standalone image byte-identical): E2E `test_standalone_*` (NULL `image_context`, block body exactly the bare description, no `Referenced in` anywhere in the prompt) + unit `test_describe_image_without_context_is_byte_identical` — passing.
- **Criterion 3** (markdown-first: record stored on markdown doc, image picks up context later): integration `test_markdown_indexed_before_image_stores_record_and_image_picks_it_up` + post-index enrichment pass test (markdown file gone from disk) — passing.
- **Gates:** `uv run pytest` → 2938 passed, exit 0 · `uv run pytest --cov=app --cov-report=term-missing` → exit 0, TOTAL **99%** (>90%) · `uv run ruff check .` → All checks passed · `uv run pyright` → 0 errors, 0 warnings.
- **Phase E2E in isolation:** `uv run pytest tests/e2e/test_image_anchor_context.py -v --no-cov` → 4 passed.
- **Mock-LLM change regression check:** neighboring image E2E suites green in isolation — `test_smoke` (3), `test_image_documents` (16), `test_chat_image_questions` (17), `test_answer_images` (17).
- No defects found; no code changes needed. No live-infrastructure changes (local dev DB only). No commit made (harness commits).
- Next pending phase: check `.agents/phases/todo/` after the harness moves this phase.
This commit is contained in:
2026-09-27 05:53:12 -04:00
parent 62e4f6b572
commit e0307fe3ff
60 changed files with 6583 additions and 82 deletions
+99
View File
@@ -2790,3 +2790,102 @@ def test_zero_read_text_only_turn_still_chips_nothing(
assert done["sources"] == [] # phase-119 read-docs-only rule intact
for ref in done["sources"] + done["related"]:
assert "image_url" not in ref
# ---------------------------------------------------------------------------
# Phase 125, task 05 — retrieval display: the suggested tier's ENRICHED
# image doc (non-NULL image_context, the task-03/04 block shape) leads
# its <document> block with the one-line context line (the referring
# markdown's identity + the reference's alt) before the description;
# the non-enriched image doc (NULL image_context) stays byte-identical
# to pre-phase (LOCKED A4).
# ---------------------------------------------------------------------------
def test_grounded_turn_suggested_enriched_image_doc_carries_context_line(
client, db, seeded_kb: FakeRagLLM
) -> None:
"""LOCKED A4 end-to-end: a grounded turn whose suggested tier
contains an enriched image doc (the task-03/04 ``Referenced in``
block stored on ``image_context``) → the system prompt's
``<document>`` block for that doc leads with the short context
line, a blank line, then the description — and the ``Context:``
paragraphs of the stored block never reach the prompt (the line is
the locator + purpose, not a duplicate of the paragraphs)."""
doc = _seed_image_doc_with_chunk(db)
doc.image_context = (
"Referenced in docs/homelab/kubernetes.md:\n"
'- Alt text: "Cluster layout"\n'
" Context: The diagram shows the three Talos nodes.\n"
"It is referenced again from the runbook."
)
db.commit()
scripted = FakeRagLLM() # zero-read grounded turn (the image seed block IS its content)
fastapi_app.dependency_overrides[chat_api.get_llm] = lambda: scripted
try:
_, _, frames = _stream_chat(client, QUESTION)
finally:
fastapi_app.dependency_overrides.clear()
assert frames[-1]["deflected"] is False
system = scripted.seen_messages[0][0]["content"]
# The doc is in the suggested tier (retrieval is unchanged by the
# phase — the line rides on a doc the retrieval already picked).
block_start = system.index(f'<document source="docs" path="{doc.path}"')
block = system[
block_start : system.index("</document>", block_start) + len("</document>")
]
line = 'Referenced in docs/homelab/kubernetes.md: "Cluster layout"'
# The exact block shape: identity attrs (phase 106 date), the line,
# a blank line, the description (the phase-122 content == summary
# == vision description invariant).
assert block == (
f'<document source="docs" path="pic.png" title="pic" '
f'date="{_FIXTURE_CREATED_AT:%Y-%m-%d}">\n'
f"{line}\n"
"\n"
f"{doc.summary}\n"
"</document>"
)
# The line is the FIRST thing in the block body (before the
# description), inside <documents>.
assert system.index("<documents>") < system.index(line)
assert system.index(line) < system.index(doc.summary or "")
# The Context: body stays out of the whole prompt.
assert "The diagram shows the three Talos nodes." not in system
assert "referenced again from the runbook" not in system
assert "Context:" not in system
def test_grounded_turn_suggested_plain_image_doc_block_is_byte_identical(
client, db, seeded_kb: FakeRagLLM
) -> None:
"""LOCKED A4 (the byte-identity criterion) end-to-end: the SAME
flow with ``image_context`` left NULL (the standalone / pre-phase
image doc — the phase's default) → the ``<document>`` block is
EXACTLY the pre-phase block (the summary alone, no context line,
no stray blank) and the marker string does not appear anywhere in
the system prompt."""
doc = _seed_image_doc_with_chunk(db)
assert doc.image_context is None # the seed leaves it NULL (standalone)
scripted = FakeRagLLM()
fastapi_app.dependency_overrides[chat_api.get_llm] = lambda: scripted
try:
_, _, frames = _stream_chat(client, QUESTION)
finally:
fastapi_app.dependency_overrides.clear()
assert frames[-1]["deflected"] is False
system = scripted.seen_messages[0][0]["content"]
block_start = system.index(f'<document source="docs" path="{doc.path}"')
block = system[
block_start : system.index("</document>", block_start) + len("</document>")
]
# The pre-phase block: identity attrs + the description, verbatim.
assert block == (
f'<document source="docs" path="pic.png" title="pic" '
f'date="{_FIXTURE_CREATED_AT:%Y-%m-%d}">\n'
f"{doc.summary}\n"
"</document>"
)
assert "Referenced in" not in system