Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ only the panels would instead lose text outside them.

- Keep every valid, bounded locator region even when the collection does not
cover the full image.
- Before cropping or persistence, discard locator boxes that are non-finite,
zero-sized, negative, or extend outside the normalized image bounds. If no
bounded region remains, use the parent-sized fallback rather than treating
malformed provider output as buyer evidence.
- Describe each retained region independently and persist its coordinates and
status as before.
- For a partial collection, also describe the original parent image once so
Expand Down
40 changes: 40 additions & 0 deletions docs/product-technical-gap-baseline.md
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -412,3 +412,43 @@ the existing whole-image fallback.
- Integration status: PR #320 is not protected-main truth; exact stack heads,
formal review, terminal Checks, and authorized post-merge image evidence
remain required.
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Resolved

## Current exact-head audit: 2026-08-20 continuation

The protected GitHub state was re-read after the embedding and visual-region
checkpoints. These are gate observations, not merge claims. A blank review
decision means no independent approval was observed; `UNSTABLE` and `BLOCKED`
are not release evidence.

| PR | Base -> head | Exact head | Review/check state |
|---|---|---|---|
| #258 | `main` -> `feat/analysis-run-name-evidence-lineage` | `49804b0fef503be1697b8be61919b022b615ef2f` | `REVIEW_REQUIRED`, `BLOCKED`; no independent approval observed |
| #323 | `main` -> `fix/tepp-request-contract-validation` | `1a27efec6863cd3439a4c6023e1c625ce4d7abf2` | `REVIEW_REQUIRED`, `BLOCKED`; required Checks queued |
| #322 | `fix/stale-summary-buyer-continuity` -> `feat/orchestrator-owned-embedding-consumer` | `a6a1d8fe8b17ad095e507f5d16b93c984e6de5db` | `UNSTABLE`; Full test and frontend Checks queued |
| #320 | `codex/normalize-source-indent-semantics` -> `codex/preserve-partial-image-regions` | `41d164c570fe232cc1e38a766439e4093d80cb84` | `UNSTABLE`; stacked visual evidence change |
| #324 | `codex/preserve-partial-image-regions` -> `fix/validate-partial-image-regions` | `a4627d6e1d04b4782a696c74d67303e1143038e0` | `UNSTABLE`; Full test and frontend Checks queued |
| #789 | `main` -> contextual-orchestrator embedding capability branch | `3a80d91b8c879e57d30ab87af664546b8712fb15` | `REVIEW_REQUIRED`, `BLOCKED`; upstream Checks queued |

The current implementation checkpoints are local/branch evidence only:
LineageWeave embedding model discovery is recorded in ADR 0118, and visual
locator validation is stacked in #324. Exact-head OpenCode review requests were
issued for #258, #322, #323, #324, and upstream #789. No protected branch was
approved, force-pushed, or merged from this audit.

This update supersedes neither the historical PR table nor the closure
criteria above; it supplies the current gate snapshot needed before the next
review -> fix -> Checks -> merge decision.

## Locator-bound validation checkpoint: 2026-08-20

The partial-region path now rejects non-finite, zero-sized, negative, and
out-of-bounds locator boxes before crop or persistence. Valid panels remain
independently searchable; if every returned box is invalid, the existing
parent-image fallback preserves an honest image-level outcome.

- Decision record: ADR 0104
- Implementation: PR #324, stacked on PR #320
- Local evidence: normalization module branch coverage `100%`; focused image,
persistence-edge, and normalization tests `52 passed`.
- Integration status: PR #324 is not protected-main truth; its exact current
head, formal review, terminal Checks, and browser evidence remain required.
16 changes: 16 additions & 0 deletions lineageweave/post_content_normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from __future__ import annotations

import math
import re
from dataclasses import dataclass, field

Expand Down Expand Up @@ -130,6 +131,20 @@ def _merge_region_descriptions(descriptions: list[ImageDescription]) -> ImageDes
return ImageDescription(extracted_text=extracted_text, caption=captions, tags=tags)


def _is_bounded_region(region: ImageRegion) -> bool:
"""Accept only finite, positive regions wholly inside the image."""
values = (region.x, region.y, region.width, region.height)
return (
all(math.isfinite(value) for value in values)
and 0.0 <= region.x <= 1.0
and 0.0 <= region.y <= 1.0
and 0.0 < region.width <= 1.0
and 0.0 < region.height <= 1.0
and region.x + region.width <= 1.0
and region.y + region.height <= 1.0
)


def _describe_image_region(
region_index: int,
image_bytes: bytes,
Expand Down Expand Up @@ -165,6 +180,7 @@ def _describe_image_chunk(
regions = locator(chunk.image_data, chunk.label) if callable(locator) else ()
except Exception: # noqa: BLE001 - locator failure falls back to whole-image evidence.
regions = ()
regions = tuple(region for region in regions if _is_bounded_region(region))
partial_regions = bool(regions) and not regions_cover_image(regions)
if not regions:
# No usable locator output still needs one parent-image evidence unit.
Expand Down
119 changes: 118 additions & 1 deletion tests/test_post_content_normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
import base64
from threading import Lock

from lineageweave.image_content import ImageDescription, ImageRegion
from lineageweave.chunking import Chunk
from lineageweave.image_content import ImageDescription, ImageRegion, NullImageContentClient
from lineageweave.llm_context import current_llm_metadata, use_llm_metadata
from lineageweave.post_content_normalization import normalize_post_body

Expand Down Expand Up @@ -70,6 +71,28 @@ def locate_regions(self, image_bytes: bytes, mime_type: str) -> tuple[ImageRegio
return (ImageRegion(0.25, 0.25, 0.25, 0.25),)


class _MixedValidityRegionVisionClient(_PartialRegionVisionClient):
def locate_regions(self, image_bytes: bytes, mime_type: str) -> tuple[ImageRegion, ...]:
return (
ImageRegion(0.25, 0.25, 0.25, 0.25),
ImageRegion(-0.1, 0.0, 0.5, 0.5),
ImageRegion(0.0, 0.0, float("nan"), 0.5),
)


class _LocatorFailureVisionClient(_FakeVisionClient):
def locate_regions(self, image_bytes: bytes, mime_type: str) -> tuple[ImageRegion, ...]:
raise RuntimeError("synthetic locator outage")


class _PartialRegionFailureVisionClient(_FakeVisionClient):
def locate_regions(self, image_bytes: bytes, mime_type: str) -> tuple[ImageRegion, ...]:
return (ImageRegion(0.25, 0.25, 0.25, 0.25),)

def describe(self, image_bytes: bytes, mime_type: str) -> ImageDescription:
raise RuntimeError("synthetic region and parent outage")


def test_plain_text_passes_through_unchanged() -> None:
result = normalize_post_body("Just a plain business record, no markup here.")
assert result.text == "Just a plain business record, no markup here."
Expand Down Expand Up @@ -142,6 +165,85 @@ def test_image_regions_are_cropped_and_described_as_independent_evidence() -> No
assert "panel text" in result.text


def test_image_without_ocr_uses_caption_only_and_preserves_image_result() -> None:
b64 = base64.b64encode(_PNG_1X1).decode("ascii")
description = ImageDescription(extracted_text="", caption="a blank chart", tags=())

result = normalize_post_body(
f'<img src="data:image/png;base64,{b64}"/>',
vision_client=_FakeVisionClient(description),
)

assert result.text == "[image: a blank chart]"
assert result.image_results[0].status_code == "described"


def test_unavailable_vision_channel_keeps_an_explicit_image_outcome() -> None:
b64 = base64.b64encode(_PNG_1X1).decode("ascii")

result = normalize_post_body(
f'<img src="data:image/png;base64,{b64}"/>',
vision_client=NullImageContentClient(),
)

assert result.text == "[image: content unavailable]"
assert result.image_results[0].status_code == "unavailable"


def test_available_client_with_missing_image_bytes_keeps_unavailable_outcome() -> None:
from lineageweave.post_content_normalization import _describe_image_chunk

result, description, placeholder = _describe_image_chunk(
Chunk(text="", unit_type="image", index=0, label="image/png", image_data=None),
_FakeVisionClient(ImageDescription(extracted_text="", caption="unused", tags=())),
)

assert result.status_code == "unavailable"
assert description is None
assert placeholder == "[image: content unavailable]"


def test_locator_failure_falls_back_to_parent_image_evidence() -> None:
b64 = base64.b64encode(_PNG_1X1).decode("ascii")
description = ImageDescription(extracted_text="parent", caption="whole image", tags=())

result = normalize_post_body(
f'<img src="data:image/png;base64,{b64}"/>',
vision_client=_LocatorFailureVisionClient(description),
)

assert result.image_results[0].status_code == "described"
assert result.image_results[0].regions[0].region == ImageRegion(0.0, 0.0, 1.0, 1.0)


def test_partial_locator_with_no_successful_description_fails_closed() -> None:
b64 = base64.b64encode(_PNG_1X1).decode("ascii")

result = normalize_post_body(
f'<img src="data:image/png;base64,{b64}"/>',
vision_client=_PartialRegionFailureVisionClient(
ImageDescription(extracted_text="unused", caption="unused", tags=())
),
)

assert result.image_results[0].status_code == "failed"
assert result.text == "[image: content unavailable]"


def test_unknown_chunk_kinds_are_not_leaked_into_buyer_text(monkeypatch) -> None:
from lineageweave import post_content_normalization

monkeypatch.setattr(
post_content_normalization,
"chunk_by_dom",
lambda _body: [Chunk(text="hidden", unit_type="unknown", index=0)],
)

result = normalize_post_body("<div>ignored by the synthetic chunker</div>")

assert result.text == ""


def test_image_analysis_preserves_post_scoped_llm_metadata() -> None:
b64 = base64.b64encode(_PNG_1X1).decode("ascii")
html = (
Expand Down Expand Up @@ -192,6 +294,21 @@ def test_partial_region_parent_failure_keeps_successful_panel_evidence() -> None
assert result.image_results[0].description is not None


def test_partial_region_analysis_discards_unbounded_locator_regions() -> None:
b64 = base64.b64encode(_PNG_1X1).decode("ascii")
client = _MixedValidityRegionVisionClient(
ImageDescription(extracted_text="whole", caption="whole", tags=())
)

result = normalize_post_body(
f'<img src="data:image/png;base64,{b64}"/>',
vision_client=client,
)

assert len(result.image_results[0].regions) == 1
assert result.image_results[0].regions[0].region == ImageRegion(0.25, 0.25, 0.25, 0.25)


def test_comparison_operators_in_plain_text_are_not_treated_as_html() -> None:
body = "Need delivery if qty < 50 and price > 10."
result = normalize_post_body(body)
Expand Down
Loading