change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes #14

Merged
ai-reviewer merged 2 commits from change/6-implement-4-filter-candidates-by-real-format-and-minimum-size- into task/1-task 2026-11-03 02:21:27 +00:00
Member

Added tools/images.py with stdlib-only detection of the real image format and pixel dimensions from downloaded bytes (PNG signature + IHDR chunk, ICO ICONDIR/ICONDIRENTRY directory including the 0-means-256 encoding) plus stdlib-only builders (png_bytes, ico_bytes) so tests/sources can produce genuine payloads. Wired it into the CLI search path in tools/example.py: a bounded candidate window derived from --count (candidate_cap = count * 4, capped at 50) is fetched from the selected source, each payload is parsed, and only items whose actual format equals the requested png/ico and whose actual width and height are both at least the requested minimum are kept. Kept items report source, url, format and the actual width/height (plus size_bytes and metadata as extras); verified bytes are reused for --download instead of being fetched twice. Statuses stay distinct: ok (0), no_format (3) when hits were only other formats, no_size (4) when format-matching items were all too small, access_error (5) when bytes could not be fetched or are not readable images, partial_download (6) when some candidates could not be read. All metadata-based filtering (FORMAT_MATCHERS, _matches_format, _matches_size) was removed so only parsed bytes decide. Added tests/test_images.py with detector/builder unit tests and CLI tests using an injected fake byte-fetch callable (no network), and updated tests/test_cli.py fixtures to real image bytes where the previous metadata-only assumption no longer holds.

Tests:
Facade commands run with .venv/bin on PATH after prepare_environment(component=tools, mode=restore): python -m compileall tools tests (tools.validate) succeeded; pytest (tools.test) => 114 passed, including the new tests/test_images.py (31 tests); python -m tools.example examples/input.json (tools.smoke) exited 0 with a single dry_run JSON document; acceptance commands python -m tools.example --help exited 0 and import tools resolved. Target branch task/1-task is at the same commit as this work branch (git rev-list count 0 ahead / 0 behind), so it is already integrated; facade/protected paths untouched.

Progress:
Implemented byte-based format and minimum-size filtering for the image search path. New tools/images.py: detect_format (png/ico plus jpeg/gif/bmp/webp so "other format" is distinguishable from "unreadable"), read_png_dimensions (IHDR), read_ico_dimensions (ICONDIR entries, 0 => 256, largest entry), inspect_image/ImageInfo, ImageFormatError (code image_unreadable), and png_bytes/ico_bytes builders. tools/example.py: candidate_cap(count) bounded window (count*4, max 50) requested from the source, _select() fetches and parses every candidate, KeptImage.to_item() reports source/url/format/actual width+height/size_bytes, _download() writes the already verified bytes, and _execute() distinguishes ok/no_format/no_size/access_error/partial_download with the existing exit codes; metadata-based filtering removed. tests/test_images.py added (31 tests) and tests/test_cli.py fixtures aligned to real image bytes. All facade commands pass: compileall, pytest (114 passed), smoke, help, package import.

Published by developer-agent through Tool Backend.

Closes #6

Added tools/images.py with stdlib-only detection of the real image format and pixel dimensions from downloaded bytes (PNG signature + IHDR chunk, ICO ICONDIR/ICONDIRENTRY directory including the 0-means-256 encoding) plus stdlib-only builders (png_bytes, ico_bytes) so tests/sources can produce genuine payloads. Wired it into the CLI search path in tools/example.py: a bounded candidate window derived from --count (candidate_cap = count * 4, capped at 50) is fetched from the selected source, each payload is parsed, and only items whose actual format equals the requested png/ico and whose actual width and height are both at least the requested minimum are kept. Kept items report source, url, format and the actual width/height (plus size_bytes and metadata as extras); verified bytes are reused for --download instead of being fetched twice. Statuses stay distinct: ok (0), no_format (3) when hits were only other formats, no_size (4) when format-matching items were all too small, access_error (5) when bytes could not be fetched or are not readable images, partial_download (6) when some candidates could not be read. All metadata-based filtering (FORMAT_MATCHERS, _matches_format, _matches_size) was removed so only parsed bytes decide. Added tests/test_images.py with detector/builder unit tests and CLI tests using an injected fake byte-fetch callable (no network), and updated tests/test_cli.py fixtures to real image bytes where the previous metadata-only assumption no longer holds. Tests: Facade commands run with .venv/bin on PATH after prepare_environment(component=tools, mode=restore): `python -m compileall tools tests` (tools.validate) succeeded; `pytest` (tools.test) => 114 passed, including the new tests/test_images.py (31 tests); `python -m tools.example examples/input.json` (tools.smoke) exited 0 with a single dry_run JSON document; acceptance commands `python -m tools.example --help` exited 0 and `import tools` resolved. Target branch task/1-task is at the same commit as this work branch (git rev-list count 0 ahead / 0 behind), so it is already integrated; facade/protected paths untouched. Progress: Implemented byte-based format and minimum-size filtering for the image search path. New tools/images.py: detect_format (png/ico plus jpeg/gif/bmp/webp so "other format" is distinguishable from "unreadable"), read_png_dimensions (IHDR), read_ico_dimensions (ICONDIR entries, 0 => 256, largest entry), inspect_image/ImageInfo, ImageFormatError (code image_unreadable), and png_bytes/ico_bytes builders. tools/example.py: candidate_cap(count) bounded window (count*4, max 50) requested from the source, _select() fetches and parses every candidate, KeptImage.to_item() reports source/url/format/actual width+height/size_bytes, _download() writes the already verified bytes, and _execute() distinguishes ok/no_format/no_size/access_error/partial_download with the existing exit codes; metadata-based filtering removed. tests/test_images.py added (31 tests) and tests/test_cli.py fixtures aligned to real image bytes. All facade commands pass: compileall, pytest (114 passed), smoke, help, package import. Published by developer-agent through Tool Backend. Closes #6
ai-dev added 1 commit 2026-11-03 02:11:37 +00:00
change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes
Repository Validate / repository-checks (pull_request) Successful in 3s
b544968cb8
Added tools/images.py with stdlib-only detection of the real image format and pixel dimensions from downloaded bytes (PNG signature + IHDR chunk, ICO ICONDIR/ICONDIRENTRY directory including the 0-means-256 encoding) plus stdlib-only builders (png_bytes, ico_bytes) so tests/sources can produce genuine payloads. Wired it into the CLI search path in tools/example.py: a bounded candidate window derived from --count (candidate_cap = count * 4, capped at 50) is fetched from the selected source, each payload is parsed, and only items whose actual format equals the requested png/ico and whose actual width and height are both at least the requested minimum are kept. Kept items report source, url, format and the actual width/height (plus size_bytes and metadata as extras); verified bytes are reused for --download instead of being fetched twice. Statuses stay distinct: ok (0), no_format (3) when hits were only other formats, no_size (4) when format-matching items were all too small, access_error (5) when bytes could not be fetched or are not readable images, partial_download (6) when some candidates could not be read. All metadata-based filtering (FORMAT_MATCHERS, _matches_format, _matches_size) was removed so only parsed bytes decide. Added tests/test_images.py with detector/builder unit tests and CLI tests using an injected fake byte-fetch callable (no network), and updated tests/test_cli.py fixtures to real image bytes where the previous metadata-only assumption no longer holds.

Tests:
Facade commands run with .venv/bin on PATH after prepare_environment(component=tools, mode=restore): `python -m compileall tools tests` (tools.validate) succeeded; `pytest` (tools.test) => 114 passed, including the new tests/test_images.py (31 tests); `python -m tools.example examples/input.json` (tools.smoke) exited 0 with a single dry_run JSON document; acceptance commands `python -m tools.example --help` exited 0 and `import tools` resolved. Target branch task/1-task is at the same commit as this work branch (git rev-list count 0 ahead / 0 behind), so it is already integrated; facade/protected paths untouched.

Progress:
Implemented byte-based format and minimum-size filtering for the image search path. New tools/images.py: detect_format (png/ico plus jpeg/gif/bmp/webp so "other format" is distinguishable from "unreadable"), read_png_dimensions (IHDR), read_ico_dimensions (ICONDIR entries, 0 => 256, largest entry), inspect_image/ImageInfo, ImageFormatError (code image_unreadable), and png_bytes/ico_bytes builders. tools/example.py: candidate_cap(count) bounded window (count*4, max 50) requested from the source, _select() fetches and parses every candidate, KeptImage.to_item() reports source/url/format/actual width+height/size_bytes, _download() writes the already verified bytes, and _execute() distinguishes ok/no_format/no_size/access_error/partial_download with the existing exit codes; metadata-based filtering removed. tests/test_images.py added (31 tests) and tests/test_cli.py fixtures aligned to real image bytes. All facade commands pass: compileall, pytest (114 passed), smoke, help, package import.

Published by developer-agent through Tool Backend.

Closes #6
Author
Member

Developer-agent completed implementation and CI passed, but updating the PR title/body failed.

Intended title: change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes
Commit: b544968cb8
CI: CI passed.

Intended body:
Added tools/images.py with stdlib-only detection of the real image format and pixel dimensions from downloaded bytes (PNG signature + IHDR chunk, ICO ICONDIR/ICONDIRENTRY directory including the 0-means-256 encoding) plus stdlib-only builders (png_bytes, ico_bytes) so tests/sources can produce genuine payloads. Wired it into the CLI search path in tools/example.py: a bounded candidate window derived from --count (candidate_cap = count * 4, capped at 50) is fetched from the selected source, each payload is parsed, and only items whose actual format equals the requested png/ico and whose actual width and height are both at least the requested minimum are kept. Kept items report source, url, format and the actual width/height (plus size_bytes and metadata as extras); verified bytes are reused for --download instead of being fetched twice. Statuses stay distinct: ok (0), no_format (3) when hits were only other formats, no_size (4) when format-matching items were all too small, access_error (5) when bytes could not be fetched or are not readable images, partial_download (6) when some candidates could not be read. All metadata-based filtering (FORMAT_MATCHERS, _matches_format, _matches_size) was removed so only parsed bytes decide. Added tests/test_images.py with detector/builder unit tests and CLI tests using an injected fake byte-fetch callable (no network), and updated tests/test_cli.py fixtures to real image bytes where the previous metadata-only assumption no longer holds.

Tests:
Facade commands run with .venv/bin on PATH after prepare_environment(component=tools, mode=restore): python -m compileall tools tests (tools.validate) succeeded; pytest (tools.test) => 114 passed, including the new tests/test_images.py (31 tests); python -m tools.example examples/input.json (tools.smoke) exited 0 with a single dry_run JSON document; acceptance commands python -m tools.example --help exited 0 and import tools resolved. Target branch task/1-task is at the same commit as this work branch (git rev-list count 0 ahead / 0 behind), so it is already integrated; facade/protected paths untouched.

Published by developer-agent through Tool Backend.

Developer-agent completed implementation and CI passed, but updating the PR title/body failed. Intended title: change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes Commit: b544968cb8188439c85055ac750101f7ab5109e1 CI: CI passed. Intended body: Added tools/images.py with stdlib-only detection of the real image format and pixel dimensions from downloaded bytes (PNG signature + IHDR chunk, ICO ICONDIR/ICONDIRENTRY directory including the 0-means-256 encoding) plus stdlib-only builders (png_bytes, ico_bytes) so tests/sources can produce genuine payloads. Wired it into the CLI search path in tools/example.py: a bounded candidate window derived from --count (candidate_cap = count * 4, capped at 50) is fetched from the selected source, each payload is parsed, and only items whose actual format equals the requested png/ico and whose actual width and height are both at least the requested minimum are kept. Kept items report source, url, format and the actual width/height (plus size_bytes and metadata as extras); verified bytes are reused for --download instead of being fetched twice. Statuses stay distinct: ok (0), no_format (3) when hits were only other formats, no_size (4) when format-matching items were all too small, access_error (5) when bytes could not be fetched or are not readable images, partial_download (6) when some candidates could not be read. All metadata-based filtering (FORMAT_MATCHERS, _matches_format, _matches_size) was removed so only parsed bytes decide. Added tests/test_images.py with detector/builder unit tests and CLI tests using an injected fake byte-fetch callable (no network), and updated tests/test_cli.py fixtures to real image bytes where the previous metadata-only assumption no longer holds. Tests: Facade commands run with .venv/bin on PATH after prepare_environment(component=tools, mode=restore): `python -m compileall tools tests` (tools.validate) succeeded; `pytest` (tools.test) => 114 passed, including the new tests/test_images.py (31 tests); `python -m tools.example examples/input.json` (tools.smoke) exited 0 with a single dry_run JSON document; acceptance commands `python -m tools.example --help` exited 0 and `import tools` resolved. Target branch task/1-task is at the same commit as this work branch (git rev-list count 0 ahead / 0 behind), so it is already integrated; facade/protected paths untouched. Published by developer-agent through Tool Backend.
ai-dev added the auto:allowedrole:reviewerstatus:in-review labels 2026-11-03 02:11:59 +00:00
ai-dev added the claim:active label 2026-11-03 02:12:01 +00:00
ai-reviewer requested changes 2026-11-03 02:14:40 +00:00
Dismissed
ai-reviewer left a comment
Member

The declared acceptance checks do pass (tools.validate/test/smoke and tests/test_images.py green on b544968), and the byte-based PNG/ICO detection and minimum-size filtering are implemented well. However the classification of non-PNG/ICO hits is too narrow for the approved live source, and it turns common, fully working searches into partial_download (exit 6) and no_format/no_size outcomes into access_error (exit 5). That regresses REQ-007/REQ-008/AC-004/AC-006 behavior rather than just adding the requested feature.

Findings:

  • Blocking: tools/images.detect_format only recognises png/ico/jpeg/gif/bmp/webp (evidence-3), so any other real image served by the approved source is treated as unreadable in _select and appended to failures (evidence-6). Wikimedia Commons search is not format-filtered (gsrsearch over namespace 6, tools/sources.py:370-423, evidence-15) and the repository's own Commons fixture already contains an image/svg+xml hit (tests/test_sources.py:117-130, evidence-25); TIFF/SVG/PDF bodies are therefore routine. Consequence 1: a normal png search that keeps real pngs and also hits one SVG returns partial_download/exit 6 instead of ok/exit 0 (tools/example.py:936-951, evidence-9), so the success path regresses on the live source. Consequence 2: an ico request whose hits are svg+png returns access_error/candidate_unreadable (tools/example.py:899-917, evidence-8) instead of the explicit no-format message required by REQ-007/AC-004, and a topic with only too-small pngs plus one SVG returns access_error instead of no_size (REQ-008/AC-006). test_ico_request_with_only_png_payloads_yields_no_format and test_no_format_and_no_size_and_access_error_stay_distinct (evidence-11, evidence-23) only use recognised other formats, so this path is untested. Fix by recognising the other container families the approved hosts serve (svg/tiff/pdf/...) or by classifying any parseable image body that is not the requested format as a format rejection, and add tests for (a) png hit + svg hit => ok, (b) ico request with an svg hit => no_format, (c) genuinely non-image/HTML body => access_error.
  • Non-download searches can now return STATUS_PARTIAL_DOWNLOAD (exit 6) when candidates merely failed to parse (tools/example.py:936-951, evidence-9), while the accepted status vocabulary documents that status as 'Some downloads succeeded and some failed' (tools/envelope.py:55-63, evidence-7). No test covers this branch. Either keep ok plus a warnings/notes field for non-fatal unreadable candidates, or revise the documented vocabulary through the proper change path instead of redefining it inside a feature PR.
  • Minor: in the no-match envelope, details["format_matches"] is filled with selection.size_rejects (tools/example.py:899-909, evidence-6/evidence-9) and the new tests assert that value (evidence-11:328, evidence-23), so the field name misreports what it counts; consider renaming to size_rejected / reporting the real format-match count.
The declared acceptance checks do pass (tools.validate/test/smoke and tests/test_images.py green on b544968), and the byte-based PNG/ICO detection and minimum-size filtering are implemented well. However the classification of non-PNG/ICO hits is too narrow for the approved live source, and it turns common, fully working searches into `partial_download` (exit 6) and `no_format`/`no_size` outcomes into `access_error` (exit 5). That regresses REQ-007/REQ-008/AC-004/AC-006 behavior rather than just adding the requested feature. Findings: - Blocking: `tools/images.detect_format` only recognises png/ico/jpeg/gif/bmp/webp (evidence-3), so any other real image served by the approved source is treated as unreadable in `_select` and appended to `failures` (evidence-6). Wikimedia Commons search is not format-filtered (`gsrsearch` over namespace 6, tools/sources.py:370-423, evidence-15) and the repository's own Commons fixture already contains an `image/svg+xml` hit (tests/test_sources.py:117-130, evidence-25); TIFF/SVG/PDF bodies are therefore routine. Consequence 1: a normal png search that keeps real pngs and also hits one SVG returns `partial_download`/exit 6 instead of `ok`/exit 0 (tools/example.py:936-951, evidence-9), so the success path regresses on the live source. Consequence 2: an ico request whose hits are svg+png returns `access_error`/`candidate_unreadable` (tools/example.py:899-917, evidence-8) instead of the explicit no-format message required by REQ-007/AC-004, and a topic with only too-small pngs plus one SVG returns access_error instead of `no_size` (REQ-008/AC-006). `test_ico_request_with_only_png_payloads_yields_no_format` and `test_no_format_and_no_size_and_access_error_stay_distinct` (evidence-11, evidence-23) only use recognised other formats, so this path is untested. Fix by recognising the other container families the approved hosts serve (svg/tiff/pdf/...) or by classifying any parseable image body that is not the requested format as a format rejection, and add tests for (a) png hit + svg hit => ok, (b) ico request with an svg hit => no_format, (c) genuinely non-image/HTML body => access_error. - Non-download searches can now return `STATUS_PARTIAL_DOWNLOAD` (exit 6) when candidates merely failed to parse (tools/example.py:936-951, evidence-9), while the accepted status vocabulary documents that status as 'Some downloads succeeded and some failed' (tools/envelope.py:55-63, evidence-7). No test covers this branch. Either keep `ok` plus a warnings/notes field for non-fatal unreadable candidates, or revise the documented vocabulary through the proper change path instead of redefining it inside a feature PR. - Minor: in the no-match envelope, `details["format_matches"]` is filled with `selection.size_rejects` (tools/example.py:899-909, evidence-6/evidence-9) and the new tests assert that value (evidence-11:328, evidence-23), so the field name misreports what it counts; consider renaming to `size_rejected` / reporting the real format-match count.
ai-dev added role:developerstatus:in-development and removed claim:activerole:reviewerstatus:in-review labels 2026-11-03 02:14:48 +00:00
ai-dev added 1 commit 2026-11-03 02:19:12 +00:00
change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes
Repository Validate / repository-checks (pull_request) Successful in 3s
d5bb24fc01
Fix for review-fix on issue #6: non-PNG/ICO hits in the bounded candidate window are now classified as format mismatches instead of access problems, so working searches no longer degrade to `partial_download` (exit 6) or `access_error` (exit 5).

Changes:
- `tools/images.py`: `detect_format` now also names the formats a live image source commonly serves instead (svg, tiff, pdf) alongside png/ico/jpeg/gif/bmp/webp, so "the topic has images, but not in the requested format" is describable; `ImageFormatError` is documented as reserved for genuinely unusable bytes (unknown container, or a png/ico header that is truncated/corrupt).
- `tools/example.py`: `_select()` counts any payload whose detected format differs from the request (including payloads that are not a recognised image at all, e.g. an HTML error page) as a format rejection and records `observed_formats`; only an unfetchable candidate is a failure. `Selection` gained `other_formats`. `_execute()` now returns `no_size` when format-matching items were all too small, `no_format` when the topic only offered other formats (or no hits at all), and `access_error` only when not a single candidate could be fetched; a stray unfetchable candidate no longer demotes a successful search to `partial_download`. Status/exit-code vocabulary (`ok`/`no_format` 3/`no_size` 4/`access_error` 5/`partial_download` 6) is unchanged.
- `tests/test_images.py`: added svg/tiff/pdf fixtures and detection cases, plus regression tests for the reviewed behaviour — mixed-format window still `ok` (exit 0), ico request with only foreign formats yields `no_format` (exit 3) with `observed_formats`, too-small format matches still yield `no_size` (exit 4), non-image body yields `no_format` not `access_error`, unfetchable candidate does not demote a usable search, corrupt png does not hide a valid match, empty window is `no_format`, fetch failure still `access_error`.
- `tests/test_cli.py`: the former "unreadable payload is an access error" test now asserts `no_format` for a non-image body, matching the classification.

Filtering still uses only the parsed downloaded bytes (PNG IHDR / ICO directory) and never source-reported metadata, and the candidate cap derived from `--count` is unchanged.

Tests:
Ran the facade commands from /workspace with the prepared virtualenv on PATH: `python -m compileall tools tests` (validate, ok), `python -m pytest` (test, 129 passed), `python -m tools.example examples/input.json` (smoke, exit 0, dry_run envelope) and `python -m tools.example --help` (acceptance, exit 0). Dependencies restored via prepare_environment (component tools, mode restore). Target branch origin/task/1-task is already an ancestor of the work branch HEAD (verified with git merge-base), so no extra integration commit was needed; the checks ran on the integrated revision.

Progress:
Addressed changes-requested review on PR #14: the CLI no longer turns common live-source results into partial_download/access_error. Any payload whose real format is not the requested png/ico (jpeg, gif, bmp, webp, svg, tiff, pdf, or an unrecognised body such as an HTML page) is now a format mismatch feeding no_format, with observed_formats/other_format_candidates detail; only unfetchable candidates are failures, and access_error is emitted only when nothing at all could be fetched. images.detect_format gained svg/tiff/pdf recognition and ImageFormatError is scoped to genuinely unusable png/ico payloads. Statuses/exits unchanged (no_format 3, no_size 4, access_error 5). Tests extended in tests/test_images.py (svg/tiff/pdf detection, mixed-format window stays ok, ico-only-foreign yields no_format, no_size preserved alongside other formats, non-image body is no_format, unfetchable candidate does not demote a search, corrupt png does not hide a match, empty window) and tests/test_cli.py aligned. Facade validate/test/smoke/help all green (129 passed) on the integrated branch; no protected facade paths touched.

Published by developer-agent through Tool Backend.

Closes #6
Author
Member

Developer-agent completed implementation and CI passed, but updating the PR title/body failed.

Intended title: change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes
Commit: d5bb24fc01
CI: CI passed.

Intended body:
Fix for review-fix on issue #6: non-PNG/ICO hits in the bounded candidate window are now classified as format mismatches instead of access problems, so working searches no longer degrade to partial_download (exit 6) or access_error (exit 5).

Changes:

  • tools/images.py: detect_format now also names the formats a live image source commonly serves instead (svg, tiff, pdf) alongside png/ico/jpeg/gif/bmp/webp, so "the topic has images, but not in the requested format" is describable; ImageFormatError is documented as reserved for genuinely unusable bytes (unknown container, or a png/ico header that is truncated/corrupt).
  • tools/example.py: _select() counts any payload whose detected format differs from the request (including payloads that are not a recognised image at all, e.g. an HTML error page) as a format rejection and records observed_formats; only an unfetchable candidate is a failure. Selection gained other_formats. _execute() now returns no_size when format-matching items were all too small, no_format when the topic only offered other formats (or no hits at all), and access_error only when not a single candidate could be fetched; a stray unfetchable candidate no longer demotes a successful search to partial_download. Status/exit-code vocabulary (ok/no_format 3/no_size 4/access_error 5/partial_download 6) is unchanged.
  • tests/test_images.py: added svg/tiff/pdf fixtures and detection cases, plus regression tests for the reviewed behaviour — mixed-format window still ok (exit 0), ico request with only foreign formats yields no_format (exit 3) with observed_formats, too-small format matches still yield no_size (exit 4), non-image body yields no_format not access_error, unfetchable candidate does not demote a usable search, corrupt png does not hide a valid match, empty window is no_format, fetch failure still access_error.
  • tests/test_cli.py: the former "unreadable payload is an access error" test now asserts no_format for a non-image body, matching the classification.

Filtering still uses only the parsed downloaded bytes (PNG IHDR / ICO directory) and never source-reported metadata, and the candidate cap derived from --count is unchanged.

Tests:
Ran the facade commands from /workspace with the prepared virtualenv on PATH: python -m compileall tools tests (validate, ok), python -m pytest (test, 129 passed), python -m tools.example examples/input.json (smoke, exit 0, dry_run envelope) and python -m tools.example --help (acceptance, exit 0). Dependencies restored via prepare_environment (component tools, mode restore). Target branch origin/task/1-task is already an ancestor of the work branch HEAD (verified with git merge-base), so no extra integration commit was needed; the checks ran on the integrated revision.

Published by developer-agent through Tool Backend.

Developer-agent completed implementation and CI passed, but updating the PR title/body failed. Intended title: change: Implement 4: Filter candidates by real format and minimum size from downloaded bytes Commit: d5bb24fc01c12b9a79ff7db3681db32f5f7da9f9 CI: CI passed. Intended body: Fix for review-fix on issue #6: non-PNG/ICO hits in the bounded candidate window are now classified as format mismatches instead of access problems, so working searches no longer degrade to `partial_download` (exit 6) or `access_error` (exit 5). Changes: - `tools/images.py`: `detect_format` now also names the formats a live image source commonly serves instead (svg, tiff, pdf) alongside png/ico/jpeg/gif/bmp/webp, so "the topic has images, but not in the requested format" is describable; `ImageFormatError` is documented as reserved for genuinely unusable bytes (unknown container, or a png/ico header that is truncated/corrupt). - `tools/example.py`: `_select()` counts any payload whose detected format differs from the request (including payloads that are not a recognised image at all, e.g. an HTML error page) as a format rejection and records `observed_formats`; only an unfetchable candidate is a failure. `Selection` gained `other_formats`. `_execute()` now returns `no_size` when format-matching items were all too small, `no_format` when the topic only offered other formats (or no hits at all), and `access_error` only when not a single candidate could be fetched; a stray unfetchable candidate no longer demotes a successful search to `partial_download`. Status/exit-code vocabulary (`ok`/`no_format` 3/`no_size` 4/`access_error` 5/`partial_download` 6) is unchanged. - `tests/test_images.py`: added svg/tiff/pdf fixtures and detection cases, plus regression tests for the reviewed behaviour — mixed-format window still `ok` (exit 0), ico request with only foreign formats yields `no_format` (exit 3) with `observed_formats`, too-small format matches still yield `no_size` (exit 4), non-image body yields `no_format` not `access_error`, unfetchable candidate does not demote a usable search, corrupt png does not hide a valid match, empty window is `no_format`, fetch failure still `access_error`. - `tests/test_cli.py`: the former "unreadable payload is an access error" test now asserts `no_format` for a non-image body, matching the classification. Filtering still uses only the parsed downloaded bytes (PNG IHDR / ICO directory) and never source-reported metadata, and the candidate cap derived from `--count` is unchanged. Tests: Ran the facade commands from /workspace with the prepared virtualenv on PATH: `python -m compileall tools tests` (validate, ok), `python -m pytest` (test, 129 passed), `python -m tools.example examples/input.json` (smoke, exit 0, dry_run envelope) and `python -m tools.example --help` (acceptance, exit 0). Dependencies restored via prepare_environment (component tools, mode restore). Target branch origin/task/1-task is already an ancestor of the work branch HEAD (verified with git merge-base), so no extra integration commit was needed; the checks ran on the integrated revision. Published by developer-agent through Tool Backend.
ai-dev added role:reviewerstatus:in-review and removed role:developerstatus:in-development labels 2026-11-03 02:19:34 +00:00
ai-dev added the claim:active label 2026-11-03 02:19:36 +00:00
ai-reviewer left a comment
Member

Approved. Byte-based format and minimum-size filtering is implemented as specified and the earlier changes-requested findings are fixed. On exact head d5bb24fc01 the facade commands ran in CI: tools.validate compiled tools/images.py, tools.test passed with 129 tests including tests/test_images.py, tools.smoke emitted the dry-run envelope and acceptance.help-command exited 0 (AGENT_CI_RESULT records tools.validate/tools.test/tools.smoke all status=passed). Filtering uses only parsed bytes (PNG IHDR / ICO ICONDIR with 0=>256), different-format and unrecognised payloads are format rejections rather than access errors, no_size/no_format/access_error stay distinct, and verified bytes are reused for --download. Protected facade paths and dependency manifests are untouched.

Findings:

  • Non-blocking: the --count help text still says "how many candidates to request, 1-50" (tools/example.py:149-155) while the CLI now requests candidate_cap(count) = count*4 (max 50) candidates and returns at most count items; consider clarifying the help/docs so --count is described as the result limit.
  • Non-blocking: read_ico_dimensions reports only the single largest-area ICONDIRENTRY (tools/images.py:267-276). For a multi-entry ICO with non-square entries, another entry could satisfy both requested minimums while the reported pair fails; consider checking whether any entry meets both minimum dimensions.
  • Non-blocking: KeptImage.to_item() copies the source-reported mime_type verbatim next to the byte-verified format/width/height (tools/example.py:365-384); the tests deliberately use misleading metadata, so a consumer reading mime_type can see a value contradicting format. Consider dropping it or renaming it to source_mime_type.
  • Non-blocking: on a search without --download, candidates whose bytes could not be fetched are silently dropped from an otherwise ok answer with no warnings/notes field, so the caller cannot see that part of the candidate window was unreadable.

Acceptance evidence for d5bb24fc01c12b9a79ff7db3681db32f5f7da9f9:

  • issue-6-ac-1: tools/images.py exists at the reviewed revision and implements stdlib-only detect_format (png/ico + jpeg/gif/bmp/webp/svg/tiff/pdf), read_png_dimensions (IHDR), ico_entries/read_ico_dimensions (0=>256, bounds-checked), inspect_image/ImageInfo and png_bytes/ico_bytes builders; CI tools.validate compiled it successfully. (.:1-11; tools/images.py:1-160; tools/images.py:160-319; CI job 7:315-430)
  • issue-6-ac-2: tests/test_images.py is present (listed in the tests directory, 24 KB) with detector/builder unit tests and offline CLI tests using a fake byte-fetch callable (png kept with actual dims, ico request with only foreign formats => no_format, all-too-small => no_size, dimension reporting, fetch failure => access_error, mixed-format window stays ok, empty window, bounded candidate window), and the standard entrypoint (pytest via tools.test, configured by pyproject testpaths=tests) executed tests/test_images.py in CI with 129 tests passing. (tests:1-4; pyproject.toml:1-23; tests/test_images.py:560-654; CI job 7:315-430)
  • issue-6-ac-3: The repository's pytest entrypoint is declared in pyproject.toml (testpaths=tests, pytest>=8.0 dev dependency) and the tests directory holds the suite; CI at the exact head SHA emitted AGENT_CI_RESULT command_id=tools.test exit_code=0 expected_exit_code=0 status=passed after the dependency restore step, with 129 passed. (pyproject.toml:1-23; tests:1-4; CI job 7:315-430)
  • issue-6-ac-4: The capability is provided by the three supporting checks: _select fetches candidate bytes for a bounded window (candidate_cap = count*4, max 50) and keeps only payloads whose detected format equals the requested png/ico and whose parsed width/height meet both minimums, reporting source/url/format/actual dimensions; statuses and exit codes stay distinct (no_format 3, no_size 4, access_error 5) and verified bytes are reused for --download. (tools/example.py:320-479; tools/example.py:880-1018; tools/example.py:760-919; CI job 7:315-430)
Approved. Byte-based format and minimum-size filtering is implemented as specified and the earlier changes-requested findings are fixed. On exact head d5bb24fc01c12b9a79ff7db3681db32f5f7da9f9 the facade commands ran in CI: tools.validate compiled tools/images.py, tools.test passed with 129 tests including tests/test_images.py, tools.smoke emitted the dry-run envelope and acceptance.help-command exited 0 (AGENT_CI_RESULT records tools.validate/tools.test/tools.smoke all status=passed). Filtering uses only parsed bytes (PNG IHDR / ICO ICONDIR with 0=>256), different-format and unrecognised payloads are format rejections rather than access errors, no_size/no_format/access_error stay distinct, and verified bytes are reused for --download. Protected facade paths and dependency manifests are untouched. Findings: - Non-blocking: the --count help text still says "how many candidates to request, 1-50" (tools/example.py:149-155) while the CLI now requests candidate_cap(count) = count*4 (max 50) candidates and returns at most count items; consider clarifying the help/docs so --count is described as the result limit. - Non-blocking: read_ico_dimensions reports only the single largest-area ICONDIRENTRY (tools/images.py:267-276). For a multi-entry ICO with non-square entries, another entry could satisfy both requested minimums while the reported pair fails; consider checking whether any entry meets both minimum dimensions. - Non-blocking: KeptImage.to_item() copies the source-reported mime_type verbatim next to the byte-verified format/width/height (tools/example.py:365-384); the tests deliberately use misleading metadata, so a consumer reading mime_type can see a value contradicting format. Consider dropping it or renaming it to source_mime_type. - Non-blocking: on a search without --download, candidates whose bytes could not be fetched are silently dropped from an otherwise ok answer with no warnings/notes field, so the caller cannot see that part of the candidate window was unreadable. Acceptance evidence for `d5bb24fc01c12b9a79ff7db3681db32f5f7da9f9`: - issue-6-ac-1: tools/images.py exists at the reviewed revision and implements stdlib-only detect_format (png/ico + jpeg/gif/bmp/webp/svg/tiff/pdf), read_png_dimensions (IHDR), ico_entries/read_ico_dimensions (0=>256, bounds-checked), inspect_image/ImageInfo and png_bytes/ico_bytes builders; CI tools.validate compiled it successfully. (.:1-11; tools/images.py:1-160; tools/images.py:160-319; CI job 7:315-430) - issue-6-ac-2: tests/test_images.py is present (listed in the tests directory, 24 KB) with detector/builder unit tests and offline CLI tests using a fake byte-fetch callable (png kept with actual dims, ico request with only foreign formats => no_format, all-too-small => no_size, dimension reporting, fetch failure => access_error, mixed-format window stays ok, empty window, bounded candidate window), and the standard entrypoint (pytest via tools.test, configured by pyproject testpaths=tests) executed tests/test_images.py in CI with 129 tests passing. (tests:1-4; pyproject.toml:1-23; tests/test_images.py:560-654; CI job 7:315-430) - issue-6-ac-3: The repository's pytest entrypoint is declared in pyproject.toml (testpaths=tests, pytest>=8.0 dev dependency) and the tests directory holds the suite; CI at the exact head SHA emitted AGENT_CI_RESULT command_id=tools.test exit_code=0 expected_exit_code=0 status=passed after the dependency restore step, with 129 passed. (pyproject.toml:1-23; tests:1-4; CI job 7:315-430) - issue-6-ac-4: The capability is provided by the three supporting checks: _select fetches candidate bytes for a bounded window (candidate_cap = count*4, max 50) and keeps only payloads whose detected format equals the requested png/ico and whose parsed width/height meet both minimums, reporting source/url/format/actual dimensions; statuses and exit codes stay distinct (no_format 3, no_size 4, access_error 5) and verified bytes are reused for --download. (tools/example.py:320-479; tools/example.py:880-1018; tools/example.py:760-919; CI job 7:315-430)
ai-reviewer merged commit d5bb24fc01 into task/1-task 2026-11-03 02:21:27 +00:00
ai-reviewer deleted branch change/6-implement-4-filter-candidates-by-real-format-and-minimum-size- 2026-11-03 02:21:27 +00:00
ai-dev added status:accepted and removed claim:activerole:reviewerstatus:in-review labels 2026-11-03 02:21:28 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: projects/product-54354138-1#14