Skip to content

WS-ART-001-03B3B4: bounded image metadata extractors - #239

Merged
abiorh-claw merged 5 commits into
mainfrom
codex/ws-art-001-03b3b4-image-metadata
Aug 1, 2026
Merged

WS-ART-001-03B3B4: bounded image metadata extractors#239
abiorh-claw merged 5 commits into
mainfrom
codex/ws-art-001-03b3b4-image-metadata

Conversation

@Abiorh001

@Abiorh001 Abiorh001 commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

WS-ART-001-03B3B4 PR Trust Bundle

Chunk

WS-ART-001-03B3B4 — Image Metadata Extractors (L1).

Goal and human-approved intent

Install only the pre-approved Pillow artifact and add bounded PNG, JPEG, and
WebP structural metadata extraction after exact guide-source classification.
Original verified bytes remain authoritative. This hidden chunk does not add
OCR, raw pixels, AUTH activation, guide sufficiency, submission ZIP handling,
or a second parser/storage path.

What changed and why

  • Added an isolated image adapter that independently validates complete image
    structure before Pillow decoder entry and emits only canonical metadata.
  • Advanced supported images to guide-extraction-v6 through the existing
    extraction worker and immutable persistence/replay path.
  • Installed only the approved hash-bound CPython 3.11/3.12 manylinux x86_64
    Pillow wheels and made unsupported Python/platform combinations fail closed.
  • Added direct, isolated-worker, architecture, dependency, persistence/replay,
    semantic-lane, and documentation proof for all three formats.

Design chosen and alternatives rejected

The existing worker loads the approved Pillow plugins before descriptor-only
seccomp, then the image adapter re-parses PNG chunks/CRCs, JPEG SOF structure,
or WebP RIFF structure before Image.open. Pillow must agree on format,
dimensions, mode, and frame count. Rejected alternatives were request-path
parsing, trusting MIME/classifier facts, direct provider access, OCR, pixel
loading, metadata propagation, unapproved wheels, and generic download or AUTH
capabilities.

Scope control and product behavior

Only hidden guide-source extraction changes. Guide source items may be PNG,
JPEG, or WebP; contributor submissions remain one outer ZIP. Image output is
typed structural metadata and cannot satisfy required textual guide semantics.
No route, AUTH action, Celery continuation, agent invocation, submission,
review, contribution, payment, or reputation behavior changes.

Acceptance criteria proof

  • Compact sorted v6 JSON has the exact fixed keys and closed format/color
    enums; omission facts remain exactly non-truncated/non-omitted.
  • PNG validates signature, CRC, IHDR, tRNS, APNG sequences/count/bounds;
    JPEG validates SOF precision/components; WebP validates RIFF, VP8/VP8L/VP8X,
    alpha, animation headers, frame bounds, and counts before decoder entry.
  • Limits cover 16,384 dimensions, 40,000,000 pixels, and 1,000 frames,
    including exact one-over and smallest feasible production pixel cases.
  • EXIF, XMP, IPTC, ICC, comments, text chunks, thumbnails, raw pixels, parser
    diagnostics, and sentinels never reach canonical output or error protocol.
  • The dependency gate binds exact approved wheel URLs/hashes, requires matching
    runtime declarations, and rejects unsupported Python, OS, architecture, or
    libc facts.

Tests and checks run

  • Dependency gate, uv lock --check, Ruff, stale-contract scan, Markdown links,
    and git diff --check — pass.
  • Image/dependency focused suite — 107 passed; image branch coverage 90.76%.
  • Image/extraction/dependency suite with real isolated PNG/JPEG/WebP workers —
    203 passed; image branch coverage 90.76%.
  • Format/image/extraction/architecture/dependency integration suite — 247
    passed.
  • DB-backed persistence/replay and repository-wide coverage remain assigned to
    hosted Backend/Agent Gates; no local full-suite run was used.

Test delta and CI integrity

No test, assertion, lane, workflow, or coverage threshold was removed, skipped,
or weakened. All three formats have direct stable-code tests, real isolated
worker tests, and DB persistence/replay parametrization. The image module joins
the existing semantic lane. Hosted Artifact 90 percent and repository 78
percent coverage gates remain unchanged. The large lockfile deletion is
mechanical pruning of Python 3.13+ wheel records after narrowing the supported
backend range to the approved 3.11/3.12 native-wheel matrix.

Reviewer results

Plan, architecture, security, product/ops, QA, senior engineering, docs,
reuse/dedup, CI integrity, and test-delta reviews pass. Valid findings for PNG transparency,
APNG declaration validation, runtime/platform enforcement, missing runtime
dependency detection, pixel-boundary proof, cross-format isolated/persistence
proof, exact documentation, and lockfile scope were repaired or verified and
re-reviewed.

External review

CodeRabbit and hosted GitHub checks have not yet reviewed the branch. They
supplement but do not replace internal review, and valid findings must be
repaired before human merge approval.

Remaining risks and follow-up work

Classifier and child image limits are intentionally independently enforced, so
tests pin their agreement to prevent drift. ART-03B4 must consume v6 image JSON
as typed metadata rather than textual sufficiency input. AUTH activation and
legacy cutover remain later separate chunks.

Human review focus and merge ownership

Review pre-decoder hostile-container validation, metadata minimization, native
wheel/runtime enforcement, v6 replay identity, and the absence of OCR, raw
pixels, AUTH activation, or sufficiency invocation. A human owns merge
approval; the agent will not merge this PR.

Summary by CodeRabbit

  • New Features

    • Added structural metadata extraction for PNG, JPEG, and WebP images.
    • Added validation for image dimensions, pixels, frames, formats, and file integrity.
    • Added stable error reporting for malformed, unsupported, and oversized images.
    • Image metadata is excluded from textual content sufficiency checks.
  • Documentation

    • Documented supported image formats, metadata behavior, runtime requirements, and validation rules.
  • Tests

    • Added comprehensive coverage for image extraction, security limits, format validation, and runtime isolation.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 34 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e6b2c20-de4b-4a04-bf9b-44e0e28b392f

📥 Commits

Reviewing files that changed from the base of the PR and between 2cbb183 and 5f1bad2.

📒 Files selected for processing (5)
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B4-external-review-response.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B4-pr-trust-bundle.md
  • backend/app/modules/artifacts/guide_images.py
  • backend/tests/test_artifact_architecture.py
  • backend/tests/test_guide_images.py
📝 Walkthrough

Walkthrough

Adds isolated, bounded structural metadata extraction for PNG, JPEG, and WebP images. The change adds Pillow dependency and platform validation, canonical v6 metadata, worker integration, stable failures, and extensive format, resource, isolation, and architecture tests.

Changes

Image metadata extraction

Layer / File(s) Summary
Extraction contract and review scope
.agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/..., docs/spec_artifact_storage_service.md
Defines the v6 metadata schema, supported image formats, structural validation, limits, stable failures, omission rules, verification commands, and excluded capabilities.
Native dependency and platform gate
backend/pyproject.toml, backend/scripts/check_guide_extractor_dependencies.py, backend/tests/test_guide_extractor_dependencies.py, docs/operations_backend_testing.md
Pins Pillow wheels for Python 3.11 and 3.12. Runtime validation now requires Linux x86_64 or AMD64 with glibc. Dependency checks require matching runtime declarations.
Structural image parsing and canonical output
backend/app/modules/artifacts/guide_images.py, backend/tests/test_guide_images.py
Adds bounded PNG, JPEG, and WebP parsing, format-specific validation, decoder agreement checks, metadata minimization, resource limits, and stable extraction failures.
Worker integration and pipeline validation
backend/app/modules/artifacts/guide_extraction.py, backend/app/modules/artifacts/guide_extraction_worker.py, backend/tests/test_guide_extraction.py, backend/tests/test_guide_bindings.py, backend/tests/test_artifact_architecture.py, backend/scripts/run_test_lanes.py
Routes image inputs through the isolated worker, applies guide-extraction-v6, confines Pillow imports, and validates isolated extraction and binding behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GuideExtractionWorker
  participant GuideImages
  participant Pillow
  GuideExtractionWorker->>GuideImages: Submit image bytes and detected format
  GuideImages->>GuideImages: Validate structural headers and limits
  GuideImages->>Pillow: Decode within bounded pixel limits
  Pillow-->>GuideImages: Return decoded image facts
  GuideImages-->>GuideExtractionWorker: Return canonical metadata or stable failure
Loading

Possibly related PRs

Suggested reviewers: abiorh-claw

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: bounded image metadata extractors.
Description check ✅ Passed The description covers the goal, design, scope, evidence, acceptance criteria, tests, risks, review status, and merge ownership.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ws-art-001-03b3b4-image-metadata

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.

@Abiorh001

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
backend/tests/test_guide_images.py (1)

175-183: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use monkeypatch.setattr for the module constant.

The test mutates image_module.MAXIMUM_PIXELS and restores it in finally. The local name monkeypatch_limit holds a saved value, not a fixture, which is confusing. monkeypatch.setattr performs the same override and guarantees restoration through pytest teardown.

♻️ Proposed refactor
-def test_exact_limit_constants_and_boundary_transitions() -> None:
+def test_exact_limit_constants_and_boundary_transitions(
+    monkeypatch: pytest.MonkeyPatch,
+) -> None:
@@
-    monkeypatch_limit = image_module.MAXIMUM_PIXELS
-    try:
-        image_module.MAXIMUM_PIXELS = 5
-        image_module._enforce_limits(ImageStructuralFacts("png", 5, 1, 1, "rgb", 8, False))
-        with pytest.raises(ImageExtractionFailure) as one_over:
-            image_module._enforce_limits(ImageStructuralFacts("png", 6, 1, 1, "rgb", 8, False))
-        assert one_over.value.code == "image_pixel_limit"
-    finally:
-        image_module.MAXIMUM_PIXELS = monkeypatch_limit
+    monkeypatch.setattr(image_module, "MAXIMUM_PIXELS", 5)
+    image_module._enforce_limits(ImageStructuralFacts("png", 5, 1, 1, "rgb", 8, False))
+    with pytest.raises(ImageExtractionFailure) as one_over:
+        image_module._enforce_limits(ImageStructuralFacts("png", 6, 1, 1, "rgb", 8, False))
+    assert one_over.value.code == "image_pixel_limit"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_guide_images.py` around lines 175 - 183, Update the test
around _enforce_limits to use the pytest monkeypatch fixture’s setattr method
for temporarily overriding image_module.MAXIMUM_PIXELS. Remove the manual
monkeypatch_limit save and try/finally restoration, while preserving both the
boundary-success assertion and the image_pixel_limit failure assertion.
backend/tests/test_artifact_architecture.py (1)

641-673: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Split the Pillow confinement assertion into its own test.

The function asserts two independent invariants: guide_images importer confinement and PIL importer confinement. It also walks APP_ROOT.rglob("*.py") twice. The neighboring test_docx_adapter_is_confined_to_the_isolated_worker and test_xlsx_adapter_is_confined_to_the_isolated_worker each assert one invariant. A separate test keeps a failure report specific to the invariant that broke.

♻️ Proposed refactor
     assert adapter_importers == {"modules/artifacts/guide_extraction_worker.py"}
 
+
+def test_pillow_is_confined_to_the_worker_and_the_image_adapter() -> None:
     pillow_importers: set[str] = set()
     for path in APP_ROOT.rglob("*.py"):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_artifact_architecture.py` around lines 641 - 673, Split
test_image_adapter_is_confined_to_the_isolated_worker into separate tests: keep
the guide_images importer assertion in the existing test and move the PIL
importer scan/assertion into a new dedicated test. Preserve both expected
importer sets while ensuring each test reports only its respective confinement
failure.
backend/app/modules/artifacts/guide_images.py (1)

57-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Annotate _fail with NoReturn.

_fail always raises. The None return type hides that fact from type checkers. With NoReturn, static analysis can prove that parser is not None after line 316 and that width/height are bound in _webp.

♻️ Proposed refactor
+from typing import NoReturn
+
-def _fail(status: str, code: str) -> None:
+def _fail(status: str, code: str) -> NoReturn:
     raise ImageExtractionFailure(status, code)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/artifacts/guide_images.py` around lines 57 - 58, Update
the `_fail` helper’s return annotation from `None` to `NoReturn`, importing
`NoReturn` from the appropriate typing module if needed. Preserve its existing
behavior of always raising `ImageExtractionFailure` so static analysis can
recognize subsequent control flow as unreachable after `_fail`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
@.agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B4-pr-trust-bundle.md:
- Line 63: Update the suite description in the review document to hyphenate the
compound modifier, changing “Image/dependency focused suite” to
“Image/dependency-focused suite” while preserving the surrounding coverage
statement.

In `@backend/app/modules/artifacts/guide_images.py`:
- Around line 320-335: Update _expected_modes() so the grayscale_alpha PNG
color-model mapping accepts both the existing "LA" mode and Pillow’s "RGBA" mode
for 16-bit grayscale+alpha images, while leaving other expected-mode mappings
unchanged.

---

Nitpick comments:
In `@backend/app/modules/artifacts/guide_images.py`:
- Around line 57-58: Update the `_fail` helper’s return annotation from `None`
to `NoReturn`, importing `NoReturn` from the appropriate typing module if
needed. Preserve its existing behavior of always raising
`ImageExtractionFailure` so static analysis can recognize subsequent control
flow as unreachable after `_fail`.

In `@backend/tests/test_artifact_architecture.py`:
- Around line 641-673: Split
test_image_adapter_is_confined_to_the_isolated_worker into separate tests: keep
the guide_images importer assertion in the existing test and move the PIL
importer scan/assertion into a new dedicated test. Preserve both expected
importer sets while ensuring each test reports only its respective confinement
failure.

In `@backend/tests/test_guide_images.py`:
- Around line 175-183: Update the test around _enforce_limits to use the pytest
monkeypatch fixture’s setattr method for temporarily overriding
image_module.MAXIMUM_PIXELS. Remove the manual monkeypatch_limit save and
try/finally restoration, while preserving both the boundary-success assertion
and the image_pixel_limit failure assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f10b49d-09cc-4583-9a8e-310d7113335d

📥 Commits

Reviewing files that changed from the base of the PR and between 13a1dc8 and 2cbb183.

⛔ Files ignored due to path filters (1)
  • backend/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/STATUS.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/chunks/WS-ART-001-03B3B4-image-metadata-extractors.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B4-external-review-response.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B4-pr-trust-bundle.md
  • backend/app/modules/artifacts/guide_extraction.py
  • backend/app/modules/artifacts/guide_extraction_worker.py
  • backend/app/modules/artifacts/guide_images.py
  • backend/pyproject.toml
  • backend/scripts/check_guide_extractor_dependencies.py
  • backend/scripts/run_test_lanes.py
  • backend/tests/test_artifact_architecture.py
  • backend/tests/test_guide_bindings.py
  • backend/tests/test_guide_extraction.py
  • backend/tests/test_guide_extractor_dependencies.py
  • backend/tests/test_guide_images.py
  • docs/operations_backend_testing.md
  • docs/spec_artifact_storage_service.md

Comment thread backend/app/modules/artifacts/guide_images.py
@Abiorh001

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@abiorh-claw
abiorh-claw self-requested a review August 1, 2026 10:40
@abiorh-claw
abiorh-claw self-requested a review August 1, 2026 11:23
@abiorh-claw
abiorh-claw merged commit 06eba13 into main Aug 1, 2026
4 checks passed
@abiorh-claw
abiorh-claw deleted the codex/ws-art-001-03b3b4-image-metadata branch August 1, 2026 11:46
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.

2 participants