Skip to content

feat(email): resolve local inline media evidence - #1351

Closed
seonghobae wants to merge 12 commits into
developfrom
feat/email-inline-media-resolution
Closed

feat(email): resolve local inline media evidence#1351
seonghobae wants to merge 12 commits into
developfrom
feat/email-inline-media-resolution

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Scope

Implement the bounded deterministic media-normalization slice from #1350 before any OCR/vision/LLM stage:

  • bind cid: references to image body parts inside the nearest multipart/related scope;
  • preserve exact HTML source spans and MIME part paths as provenance;
  • decode bounded base64 data: images locally;
  • record HTTP(S) image references under an explicit no-fetch policy;
  • content-address duplicate image payloads while preserving every occurrence;
  • bound aggregate HTML references, media occurrences, distinct artifacts, message bytes, HTML size, and image bytes independently;
  • fail closed for malformed/ambiguous Content-ID, unsupported image types, MIME/signature mismatches, malformed data images, and resource-limit violations.

TDD and implementation evidence

The branch began with a deliberately RED acceptance-test commit before the production resolver existed. Production code and later aggregate-bound hardening were implemented on the same branch with regression tests first.

A current-head review found a second-order safety defect in digest deduplication: when identical bytes appeared once under a valid media type and once under a mismatched declaration, _store_artifact() returned whichever artifact representation was encountered first. That could upgrade the mismatched MIME/CID occurrence to llm_safe, or downgrade a valid occurrence, solely because of traversal order.

  • RED commit 0636a572f17319794e5cf3c909711d35f336b01a adds both traversal orders for one PNG payload declared as image/png and image/jpeg.
  • Production commit a9258a4be9e09e9b4aa78ef57140996669905e73 separates occurrence-scoped validation from the canonical digest artifact and promotes a canonical artifact only when a genuinely safe occurrence exists.
  • Doctoring commit f49b6302a41d479a1d49a52f761e7988d8359838 records that content-addressing is not safety authority.

The resulting contract keeps one safe canonical PNG artifact while the mismatched MIME and CID occurrences remain unsafe_media, independent of traversal order.

Standards and safety boundary

Primary standards are RFC 2045/2046 MIME, RFC 2183 Content-Disposition, RFC 2387 multipart/related, RFC 2392 cid: URLs, and RFC 2397 data: URLs. The APA 7 trace and shipped-state boundary are recorded in docs/doctoring/email-inline-media-resolution.md.

This resolver never fetches remote image URLs. llm_safe means only bounded admitted media with a matching deterministic signature; downstream decoders/model adapters still own actual decode and model-specific validation. Semantic labels such as logos, signatures, screenshots, charts, scans, and tables remain out of this deterministic slice.

Current-base reconciliation

The predecessor exact head was reconstructed onto protected develop@bc98789521d21271e84789888413c182aa111b4d by a normal non-forced merge. The protected-base delta was disjoint from the four media-resolution paths, so current protected develop is preserved everywhere outside this bounded slice.

Exact candidate

  • Base: develop@bc98789521d21271e84789888413c182aa111b4d
  • Head: cdaf876f1e81d723efe2771fcf1f00a20fda6fd3
  • Changed files: 4
  • GitHub reports the PR non-draft and mergeable.
  • Current exact-head repository workflows are queued and therefore non-passing.
  • No formal current-head review or unresolved review thread is present at this refresh.

Merge boundary

Do not merge until the unchanged exact head satisfies every live required CI/security/coverage gate, all actionable current-head threads are resolved, a qualifying independent non-author current-head approval exists, and live protected-branch/ruleset policy accepts the merge without bypass. Queued, stale, predecessor-head, skipped-required, neutral, rate-limited, status-only, author-only, or model-only evidence is not success.

Refs #1350

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bfed9ac-23a8-4b60-8fc7-575901ad4061

📥 Commits

Reviewing files that changed from the base of the PR and between bc98789 and 51a899e.

📒 Files selected for processing (5)
  • backend/services/email_media_resolution.py
  • backend/tests/test_email_media_artifact_dimensions.py
  • backend/tests/test_email_media_resolution.py
  • backend/tests/test_email_media_resolution_fallbacks.py
  • docs/doctoring/email-inline-media-resolution.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

PR governance metadata gate is not ready for 51a899e637f0b106242e136bc5f6453c43bd732c:

  • Required check backend (Python 3.14) is FAILURE on the current head.
  • Required check strix is FAILURE on the current head.

@seonghobae
seonghobae marked this pull request as ready for review August 15, 2026 09:20

Copy link
Copy Markdown
Contributor Author

@opencode-agent review current exact head a3e4ecf07dbd3828a493fca3c0da995472235e4c. Review the complete four-file deterministic inline-media resolver and publish a formal GitHub review verdict anchored to this SHA. All repository CI, security, dependency, and container workflows are terminal-success; verify MIME/CID/data-URL bounds, provenance, duplicate handling, and the no-remote-fetch trust boundary.

@seonghobae
seonghobae marked this pull request as draft August 15, 2026 11:02
@seonghobae
seonghobae marked this pull request as ready for review August 15, 2026 11:02

Copy link
Copy Markdown
Contributor Author

Closing as technically superseded by #1376, with unique work preserved. Fresh exact-head comparison proves current #1351 head 51a899e637f0b106242e136bc5f6453c43bd732c is the merge base / direct ancestor of #1376 head 76bd1cd3e228977e6af75f2a9fe40c9d4853e05c; #1376 is exactly 2 commits ahead and 0 behind. Those descendant commits complete #1351's RED intrinsic-dimension contract with the GREEN bounded PNG/GIF width/height implementation and carry the full #1351 history. Keeping both open would duplicate the same implementation lane and split exact-head review evidence. #1376 is therefore the canonical descendant candidate; no code from #1351 is discarded.

@seonghobae seonghobae closed this Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant